/** * The response idle state will initialize response processing, as well as * finalize each transactions after we are done with it. * * @param[in] connp * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed. */ htp_status_t htp_connp_RES_IDLE(htp_connp_t *connp) { // 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 = htp_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; int rc = htp_tx_state_response_start(connp->out_tx); if (rc != HTP_OK) return rc; 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; }