Exemple #1
0
/**
 * Processes a chunk of data.
 *
 * @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_BODY_CHUNKED_DATA(htp_connp_t *connp) {
    size_t bytes_to_consume;

    // Determine how many bytes we can consume.
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_chunked_length) {
        bytes_to_consume = connp->out_chunked_length;
    } else {
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
    }

    if (bytes_to_consume == 0) return HTP_DATA;

    // Consume the data.
    int rc = htp_tx_res_process_body_data(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
    if (rc != HTP_OK) return rc;

    // Adjust the counters.
    connp->out_current_read_offset += bytes_to_consume;
    connp->out_current_consume_offset += bytes_to_consume;
    connp->out_stream_offset += bytes_to_consume;
    connp->out_chunked_length -= bytes_to_consume;

    // Have we seen the entire chunk?
    if (connp->out_chunked_length == 0) {
        connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END;
        return HTP_OK;
    }

    return HTP_DATA;
}
Exemple #2
0
/**
 * Processes an identity response body of known length.
 *
 * @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_BODY_IDENTITY_CL_KNOWN(htp_connp_t *connp) {
    size_t bytes_to_consume;   
        
    // Determine how many bytes we can consume.
    if (connp->out_current_len - connp->out_current_read_offset >= connp->out_body_data_left) {
        bytes_to_consume = connp->out_body_data_left;
    } else {
        bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;
    }       
    
    if (bytes_to_consume == 0) return HTP_DATA;    

    // Consume the data.
    int rc = htp_tx_res_process_body_data(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
    if (rc != HTP_OK) return rc;

    // Adjust the counters.
    connp->out_current_read_offset += bytes_to_consume;
    connp->out_current_consume_offset += bytes_to_consume;
    connp->out_stream_offset += bytes_to_consume;
    connp->out_body_data_left -= bytes_to_consume;

    // Have we seen the entire response body?    
    if (connp->out_body_data_left == 0) {
        connp->out_state = htp_connp_RES_FINALIZE;
        return HTP_OK;
    }

    return HTP_DATA;
}
htp_status_t htp_tx_state_response_complete(htp_tx_t *tx) {
    if (tx->connp->out_tx->progress != HTP_RESPONSE_COMPLETE) {
        tx->progress = HTP_RESPONSE_COMPLETE;

        // Run the last RESPONSE_BODY_DATA HOOK, but only if there was a response body present.
        if (tx->response_transfer_coding != HTP_CODING_NO_BODY) {
            htp_tx_res_process_body_data(tx, NULL, 0);
        }

        // Run hook RESPONSE_COMPLETE.
        return htp_hook_run_all(tx->connp->cfg->hook_response_complete, tx->connp);
    }

    return HTP_OK;
}
Exemple #4
0
/**
 * Processes identity response body of unknown length. In this case, we assume the
 * response body consumes all data until the end of the stream.
 *
 * @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_BODY_IDENTITY_STREAM_CLOSE(htp_connp_t *connp) {        
    // Consume all data from the input buffer.
    size_t bytes_to_consume = connp->out_current_len - connp->out_current_read_offset;

    if (bytes_to_consume != 0) {
        int rc = htp_tx_res_process_body_data(connp->out_tx, connp->out_current_data + connp->out_current_read_offset, bytes_to_consume);
        if (rc != HTP_OK) return rc;

        // Adjust the counters.
        connp->out_current_read_offset += bytes_to_consume;
        connp->out_current_consume_offset += bytes_to_consume;
        connp->out_stream_offset += bytes_to_consume;        
    }

    // Have we seen the entire response body?
    if (connp->out_status == HTP_STREAM_CLOSED) {
        connp->out_state = htp_connp_RES_FINALIZE;
        return HTP_OK;
    }
   
    return HTP_DATA;
}
Exemple #5
0
/**
 * Parses response line.
 *
 * @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_LINE(htp_connp_t *connp) {
    for (;;) {
        // Get one byte
        OUT_COPY_BYTE_OR_RETURN(connp);

        // Have we reached the end of the line?
        if (connp->out_next_byte == LF) {
            unsigned char *data;
            size_t len;

            htp_connp_res_consolidate_data(connp, &data, &len);

            #ifdef HTP_DEBUG
            fprint_raw_data(stderr, __FUNCTION__, data, len);
            #endif

            // Is this a line that should be ignored?
            if (htp_connp_is_line_ignorable(connp, data, len)) {
                // We have an empty/whitespace line, which we'll note, ignore and move on
                connp->out_tx->response_ignored_lines++;

                // TODO How many lines are we willing to accept?

                // Start again
                htp_connp_res_clear_buffer(connp);

                return HTP_OK;
            }
           
            // Deallocate previous response line allocations, which we would have on a 100 response.

            if (connp->out_tx->response_line != NULL) {
                bstr_free(connp->out_tx->response_line);
                connp->out_tx->response_line = NULL;
            }           

            if (connp->out_tx->response_protocol != NULL) {
                bstr_free(connp->out_tx->response_protocol);
                connp->out_tx->response_protocol = NULL;
            }

            if (connp->out_tx->response_status != NULL) {
                bstr_free(connp->out_tx->response_status);
                connp->out_tx->response_status = NULL;
            }

            if (connp->out_tx->response_message != NULL) {
                bstr_free(connp->out_tx->response_message);
                connp->out_tx->response_message = NULL;
            }

            // Process response line.           

            int chomp_result = htp_chomp(data, &len);

            connp->out_tx->response_line = bstr_dup_mem(data, len);
            if (connp->out_tx->response_line == NULL) return HTP_ERROR;            

            if (connp->cfg->parse_response_line(connp) != HTP_OK) return HTP_ERROR;

            // If the response line is invalid, determine if it _looks_ like
            // a response line. If it does not look like a line, process the
            // data as a response body because that is what browsers do.

            if (htp_treat_response_line_as_body(connp->out_tx)) {
                connp->out_tx->response_content_encoding_processing = HTP_COMPRESSION_NONE;
                
                int rc = htp_tx_res_process_body_data(connp->out_tx, data, len + chomp_result);
                if (rc != HTP_OK) return rc;
               
                // Continue to process response body. Because we don't have
                // any headers to parse, we assume the body continues until
                // the end of the stream.
                connp->out_tx->response_transfer_coding = HTP_CODING_IDENTITY;
                connp->out_tx->progress = HTP_RESPONSE_BODY;
                connp->out_state = htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE;
                connp->out_body_data_left = -1;
                
                return HTP_OK;
            }
           
            int rc = htp_tx_state_response_line(connp->out_tx);
            if (rc != HTP_OK) return rc;
            
            htp_connp_res_clear_buffer(connp);

            // Move on to the next phase.
            connp->out_state = htp_connp_RES_HEADERS;
            connp->out_tx->progress = HTP_RESPONSE_HEADERS;

            return HTP_OK;
        }
    }

    return HTP_ERROR;
}