示例#1
0
/**
 * 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;
}
示例#2
0
/**
 * 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;
}