htp_status_t htp_tx_finalize(htp_tx_t *tx) { if (tx == NULL) return HTP_ERROR; if (!htp_tx_is_complete(tx)) return HTP_OK; // Run hook TRANSACTION_COMPLETE. htp_status_t rc = htp_hook_run_all(tx->connp->cfg->hook_transaction_complete, tx); if (rc != HTP_OK) return rc; // In streaming processing, we destroy the transaction because it will not be needed any more. if (tx->connp->cfg->tx_auto_destroy) { htp_tx_destroy(tx); } return HTP_OK; }
/** * Destroys a connection, as well as all the transactions it contains. It is * not possible to destroy a connection structure yet leave any of its * transactions intact. This is because transactions need its connection and * connection structures hold little data anyway. The opposite is true, though * it is possible to delete a transaction but leave its connection alive. * * @param conn */ void htp_conn_destroy(htp_conn_t *conn) { if (conn == NULL) return; // Destroy individual transactions. Do note that iterating // using the iterator does not work here because some of the // list element may be NULL (and with the iterator it is impossible // to distinguish a NULL element from the end of the list). if (conn->transactions != NULL) { size_t i; for (i = 0; i < list_size(conn->transactions); i++) { htp_tx_t *tx = (htp_tx_t *)list_get(conn->transactions, i); if (tx != NULL) { htp_tx_destroy(tx); } } list_destroy(conn->transactions); } // Destroy individual messages if (conn->messages != NULL) { htp_log_t *l = NULL; list_iterator_reset(conn->messages); while ((l = list_iterator_next(conn->messages)) != NULL) { free((void *)l->msg); free(l); } list_destroy(conn->messages); } if (conn->local_addr != NULL) { free(conn->local_addr); } if (conn->remote_addr != NULL) { free(conn->remote_addr); } // Finally, destroy the connection // structure itself. free(conn); }
htp_status_t htp_connp_RES_FINALIZE(htp_connp_t *connp) { int rc = htp_tx_state_response_complete(connp->out_tx); if (rc != HTP_OK) return rc; // Check if the inbound parser is waiting on us. If it is, that means that // there might be request data that the inbound parser hasn't consumed yet. // If we don't stop parsing we might encounter a response without a request, // which is why we want to return straight away before processing any data. // // This situation will occur any time the parser needs to see the server // respond to a particular situation before it can decide how to proceed. For // example, when a CONNECT is sent, different paths are used when it is accepted // and when it is not accepted. if ((connp->in_status == HTP_STREAM_DATA_OTHER) && (connp->in_tx == connp->out_tx)) { return HTP_DATA_OTHER; } // Do we have a signal to yield to inbound processing at // the end of the next transaction? if (connp->out_data_other_at_tx_end) { // We do. Let's yield then. connp->out_data_other_at_tx_end = 0; return HTP_DATA_OTHER; } // In streaming processing, we destroy the transaction // because it will not be needed any more. if (connp->cfg->tx_auto_destroy) { htp_tx_destroy(connp->out_tx); } // Disconnect from the transaction connp->out_tx = NULL; connp->out_state = htp_connp_RES_IDLE; return HTP_OK; }
/** * The response idle state will initialize response processing, as well as * finalize each transactions after we are done with it. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_IDLE(htp_connp_t * connp) { // If we're here and an outgoing transaction object exists that // means we've just completed parsing a response. We need // to run the final hook in a transaction and start over. if (connp->out_tx != NULL) { // Shut down the decompressor, if we've used one if (connp->out_decompressor != NULL) { connp->out_decompressor->destroy(connp->out_decompressor); connp->out_decompressor = NULL; } connp->out_tx->progress = TX_PROGRESS_DONE; // Run the last RESPONSE_BODY_DATA HOOK, but // only if there was a response body if (connp->out_tx->response_transfer_coding != -1) { htp_tx_data_t d; d.data = NULL; d.tx = connp->out_tx; htp_res_run_hook_body_data(connp, &d); } // Run hook RESPONSE int rc = hook_run_all(connp->cfg->hook_response, connp); if (rc != HTP_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response callback returned error (%d)", rc); return HTP_ERROR; } if (connp->cfg->tx_auto_destroy) { htp_tx_destroy(connp->out_tx); } // Check if the inbound parser is waiting on us. If it is that means that // there might be request data that the inbound parser hasn't consumed yet. // If we don't stop parsing we might encounter a response without a request. if ((connp->in_status == STREAM_STATE_DATA_OTHER) && (connp->in_tx == connp->out_tx)) { connp->out_tx = NULL; return HTP_DATA_OTHER; } // Start afresh connp->out_tx = NULL; // Do we have a signal to yield to inbound processing at // the end of the next transaction? if (connp->out_data_other_at_tx_end) { // We do. Let's yield then. connp->out_data_other_at_tx_end = 0; return HTP_DATA_OTHER; } } // We want to start parsing the next response (and change // the state from IDLE) only if there's at least one // byte of data available. Otherwise we could be creating // new structures even if there's no more data on the // connection. OUT_TEST_NEXT_BYTE_OR_RETURN(connp); // Parsing a new response // Find the next outgoing transaction connp->out_tx = list_get(connp->conn->transactions, connp->out_next_tx_index); if (connp->out_tx == NULL) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Unable to match response to request"); return HTP_ERROR; } // We've used one transaction connp->out_next_tx_index++; // TODO Detect state mismatch connp->out_content_length = -1; connp->out_body_data_left = -1; connp->out_header_line_index = -1; connp->out_header_line_counter = 0; // Change state into response line parsing, except if we're following // a short HTTP/0.9 request, because such requests to not have a // response line and headers. if (connp->out_tx->protocol_is_simple) { connp->out_tx->response_transfer_coding = IDENTITY; connp->out_state = htp_connp_RES_BODY_IDENTITY; connp->out_tx->progress = TX_PROGRESS_RES_BODY; } else { connp->out_state = htp_connp_RES_LINE; connp->out_tx->progress = TX_PROGRESS_RES_LINE; } return HTP_OK; }