Example #1
0
void bstr_builder_clear(bstr_builder_t *bb) {    
    // Do nothing if the list is empty
    if (htp_list_size(bb->pieces) == 0) return;

    for (size_t i = 0, n = htp_list_size(bb->pieces); i < n; i++) {
        bstr *b = htp_list_get(bb->pieces, i);
        bstr_free(b);
    }

    htp_list_clear(bb->pieces);
}
Example #2
0
/**
 * Free stream data.
 *
 * @param[in] sd
 */
void free_stream_data(stream_data *sd) {
    if (sd == NULL) return;
    
    // Free stream chunks, if any
    if (sd->chunks != NULL) {
        for (int i = 0, n = htp_list_size(sd->chunks); i < n; i++) {
            chunk_t *chunk = htp_list_get(sd->chunks, i);
            free(chunk->data);
            free(chunk);
        }
        
        htp_list_destroy(sd->chunks);
        sd->chunked = NULL;
    }
    
    // Free inbound chunks, if any
    if (sd->inbound_chunks != NULL) {
        for (int i = 0, n = htp_list_size(sd->inbound_chunks); i < n; i++) {
            chunk_t *chunk = htp_list_get(sd->inbound_chunkds, i);
            free(chunk->data);
            free(chunk);
        }
        
        htp_list_destroy(sd->inbound_chunks);
        sd->inbound_chunks = NULL;
    }
    
    // Free outbound chunks, if any
    if (sd->outbound_chunks != NULL) {
        for (int i = 0, n = htp_list_size(sd->outbound_chunks); i < n; i++) {
            chunk_t *chunk = htp_list_get(sd->outbound_chunkds, i);
            free(chunk->data);
            free(chunk);
        }
        
        htp_list_destroy(sd->outbound_chunks);
        sd->outbound_chunks = NULL;
    }

    // Close the stream file, if we have it open    
    if (sd->fd != -1) {
        close(sd->fd);
    }
    
    free(sd);
}
Example #3
0
/**
 * Process as much buffered inbound and outbound data as possible
 * (in that order)
 *
 * @param[in] sd
 */
void process_stored_stream_data(stream_data *sd) {
    int loop = 0;

    do {
        // Reset loop
        loop = 0;
        
        // Send as much inbound data as possible    
        while((sd->connp->in_status == HTP_STREAM_DATA)&&(htp_list_size(sd->inbound_chunks) > 0)) {
            chunk_t *chunk = (chunk_t *)htp_list_get(sd->inbound_chunks, 0);
                
            int rc = htp_connp_req_data(sd->connp, 0, chunk->data + chunk->consumed, chunk->len - chunk->consumed);
            if (rc == HTP_STREAM_DATA) {
                // The entire chunk was consumed
                htp_list_shift(sd->inbound_chunks);
                free(chunk->data);
                free(chunk);
            } else {
                // Partial consumption
                chunk->consumed = htp_connp_req_data_consumed(sd->connp);
            }
        }
   
        // Send as much outbound data as possible          
        while((sd->connp->out_status == HTP_STREAM_DATA)&&(htp_list_size(sd->outbound_chunks) > 0)) {
            chunk_t *chunk = (chunk_t *)htp_list_get(sd->outbound_chunks, 0);
                
            int rc = htp_connp_res_data(sd->connp, 0, chunk->data + chunk->consumed, chunk->len - chunk->consumed);
            if (rc == HTP_STREAM_DATA) {
                // The entire chunk was consumed
                htp_list_shift(sd->outbound_chunks);
                free(chunk->data);
                free(chunk);
            } else {
                // Partial consumption
                chunk->consumed = htp_connp_res_data_consumed(sd->connp);
            }
            
            // Whenever we send some outbound data to the parser,
            // we need to go back and try to send inbound data
            // if we have it.
            loop = 1;
        }
    } while(loop);
}
Example #4
0
void htp_hook_destroy(htp_hook_t *hook) {
    if (hook == NULL) return;

    for (size_t i = 0, n = htp_list_size(hook->callbacks); i < n; i++) {
        free((htp_callback_t *) htp_list_get(hook->callbacks, i));
    }

    htp_list_array_destroy(hook->callbacks);

    free(hook);
}
Example #5
0
void *htp_table_get_index(const htp_table_t *table, size_t idx, bstr **key) {
    if (table == NULL) return NULL;
    
    if (idx >= htp_list_size(table->list)) return NULL;

    if (key != NULL) {
        *key = htp_list_get(table->list, idx * 2);
    }

    return htp_list_get(table->list, (idx * 2) + 1);
}
Example #6
0
void htp_conn_destroy(htp_conn_t *conn) {
    if (conn == NULL) return;

    if (conn->transactions != NULL) {
        // 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).        
        for (size_t i = 0, n = htp_list_size(conn->transactions); i < n; i++) {
            htp_tx_t *tx = htp_list_get(conn->transactions, i);
            if (tx != NULL) {
                htp_tx_destroy_incomplete(tx);
            }
        }

        htp_list_destroy(conn->transactions);
        conn->transactions = NULL;
    }

    if (conn->messages != NULL) {
        // Destroy individual messages.
        for (size_t i = 0, n = htp_list_size(conn->messages); i < n; i++) {
            htp_log_t *l = htp_list_get(conn->messages, i);
            free((void *) l->msg);
            free(l);
        }

        htp_list_destroy(conn->messages);
        conn->messages = NULL;
    }

    if (conn->server_addr != NULL) {
        free(conn->server_addr);
    }

    if (conn->client_addr != NULL) {
        free(conn->client_addr);
    }
    
    free(conn);
}
Example #7
0
bstr *bstr_builder_to_str(const bstr_builder_t *bb) {
    size_t len = 0;

    // Determine the size of the string
    for (size_t i = 0, n = htp_list_size(bb->pieces); i < n; i++) {
        bstr *b = htp_list_get(bb->pieces, i);
        len += bstr_len(b);
    }

    // Allocate string
    bstr *bnew = bstr_alloc(len);
    if (bnew == NULL) return NULL;

    // Determine the size of the string
    for (size_t i = 0, n = htp_list_size(bb->pieces); i < n; i++) {
        bstr *b = htp_list_get(bb->pieces, i);
        bstr_add_noex(bnew, b);
    }

    return bnew;
}
Example #8
0
void bstr_builder_destroy(bstr_builder_t *bb) {
    if (bb == NULL) return;

    // Destroy any pieces we might have
    for (size_t i = 0, n = htp_list_size(bb->pieces); i < n; i++) {
        bstr *b = htp_list_get(bb->pieces, i);
        bstr_free(b);
    }

    htp_list_destroy(bb->pieces);

    free(bb);
}
Example #9
0
htp_status_t htp_conn_remove_tx(htp_conn_t *conn, const htp_tx_t *tx) {
    if ((tx == NULL) || (conn == NULL)) return HTP_ERROR;
    if (conn->transactions == NULL) return HTP_ERROR;

    for (size_t i = 0, n = htp_list_size(conn->transactions); i < n; i++) {
        htp_tx_t *candidate_tx = htp_list_get(conn->transactions, i);
        if (tx == candidate_tx) {
            htp_list_replace(conn->transactions, i, NULL);
            return HTP_OK;
        }
    }

    return HTP_DECLINED;
}
Example #10
0
File: htpy.c Project: 0rbytal/htpy
/*
 * XXX: Not sure I like mucking around in the transaction to get the method,
 * but I'm not sure of a better way.
 */
static PyObject *htpy_connp_get_method(PyObject *self, PyObject *args) {
	PyObject *ret;
	htp_tx_t *tx = NULL;

	tx = htp_list_get(((htpy_connp *) self)->connp->conn->transactions, htp_list_size(((htpy_connp *) self)->connp->conn->transactions) - 1);
	if (!tx || !tx->request_method) {
		PyErr_SetString(htpy_error, "Missing transaction or request method.");
		return NULL;
	}

	ret = Py_BuildValue("s#", bstr_ptr(tx->request_method), bstr_len(tx->request_method));

	return ret;
}
Example #11
0
File: htpy.c Project: 0rbytal/htpy
static PyObject *htpy_connp_get_response_status(PyObject *self, PyObject *args) {
	PyObject *ret;
	htp_tx_t *tx = NULL;

	tx = htp_list_get(((htpy_connp *) self)->connp->conn->transactions, htp_list_size(((htpy_connp *) self)->connp->conn->transactions) - 1);
	if (!tx) {
		PyErr_SetString(htpy_error, "Missing transaction.");
		return NULL;
	}

	ret = Py_BuildValue("i", tx->response_status_number);

	return ret;
}
Example #12
0
void htp_table_clear(htp_table_t *table) {
    if (table == NULL) return;

    // Free the table keys, but only if we're managing them.
    if ((table->alloc_type == HTP_TABLE_KEYS_COPIED)||(table->alloc_type == HTP_TABLE_KEYS_ADOPTED)) {
        bstr *key = NULL;
        for (size_t i = 0, n = htp_list_size(table->list); i < n; i += 2) {
            key = htp_list_get(table->list, i);
            bstr_free(key);
        }
    }

    htp_list_clear(table->list);
}
Example #13
0
/**
 * Invoked every time LibHTP wants to log. 
 *
 * @param[in] log
 */
int callback_log(htp_log_t *log) {
    stream_data *sd = (stream_data *)htp_connp_get_user_data(log->connp);
    
    if ((sd->log_level == -1)||(sd->log_level > log->level)) {
        sd->log_level = log->level;
    }

    if (log->code != 0) {
        fprintf(stderr, "[#%d/%d][%d][code %d][file %s][line %d] %s\n", sd->id, sd->req_count,
            log->level, log->code, log->file, log->line, log->msg);
    } else {
        fprintf(stderr, "[#%d/%d][%d][file %s][line %d] %s\n", sd->id, sd->req_count,
            log->level, log->file, log->line, log->msg);
    }
    
    // If this is the first time a log message was generated for this connection,
    // start writing the entire thing to a file on disk.
    if (sd->fd == -1) {
        char filename[256];        
        
        // TODO Use IP addresses and ports in filename
        snprintf(filename, 255, "conn-%d.t", sd->id);
        
        sd->fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
        if (sd->fd == -1) {
            fprintf(stderr, "Failed to create file %s: %s\n", filename, strerror(errno));
            exit(1);
        }

        // Write to disk the data we have in memory                
        for (int i = 0, n = htp_list_size(sd->chunks); i < n; i++) {
            chunk_t *chunk = htp_list_get(sd->chunks, i);

            if (sd->chunk_counter != 0) {
                write(sd->fd, "\r\n", 2);
            }
            
            if (sd->direction == chunk->direction) {
                write(sd->fd, ">>>\r\n", 5);
            } else {
                write(sd->fd, "<<<\r\n", 5);
            }
            
            write(sd->fd, chunk->data, chunk->len);
            
            sd->chunk_counter++;
        }
    }
}
Example #14
0
void *htp_table_get_mem(const htp_table_t *table, const void *key, size_t key_len) {
    if ((table == NULL)||(key == NULL)) return NULL;

    // Iterate through the list, comparing
    // keys with the parameter, return data if found.
    for (size_t i = 0, n = htp_list_size(table->list); i < n; i += 2) {
        bstr *key_candidate = htp_list_get(table->list, i);
        void *element = htp_list_get(table->list, i + 1);
        if (bstr_cmp_mem_nocase(key_candidate, key, key_len) == 0) {
            return element;
        }
    }

    return NULL;
}
Example #15
0
htp_hook_t *htp_hook_copy(const htp_hook_t *hook) {
    if (hook == NULL) return NULL;

    htp_hook_t *copy = htp_hook_create();
    if (copy == NULL) return NULL;

    for (size_t i = 0, n = htp_list_size(hook->callbacks); i < n; i++) {
        htp_callback_t *callback = htp_list_get(hook->callbacks, i);
        if (htp_hook_register(&copy, callback->fn) != HTP_OK) {
            htp_hook_destroy(copy);
            return NULL;
        }
    }

    return copy;
}
htp_tx_t *htp_connp_tx_create(htp_connp_t *connp) {    
    // Detect pipelining
    if (htp_list_size(connp->conn->transactions) > connp->out_next_tx_index) {
        connp->conn->flags |= HTP_CONN_PIPELINED;
    }

    htp_tx_t *tx = htp_tx_create(connp);
    if (tx == NULL) return NULL;

    connp->in_tx = tx;

    htp_list_add(connp->conn->transactions, tx);

    htp_connp_in_reset(connp);

    return tx;
}
Example #17
0
htp_status_t htp_hook_run_all(htp_hook_t *hook, void *user_data) {
    if (hook == NULL) return HTP_OK;

    // Loop through the registered callbacks, giving each a chance to run.
    for (size_t i = 0, n = htp_list_size(hook->callbacks); i < n; i++) {
        htp_callback_t *callback = htp_list_get(hook->callbacks, i);

        htp_status_t rc = callback->fn(user_data);

        // A hook can return HTP_OK to say that it did some work,
        // or HTP_DECLINED to say that it did no work. Anything else
        // is treated as an error.
        if ((rc != HTP_OK) && (rc != HTP_DECLINED)) {
            return rc;
        }
    }

    return HTP_OK;
}
Example #18
0
/**
 * Finalize Multipart processing.
 * 
 * @param[in] d
 * @return HTP_OK on success, HTP_ERROR on failure.
 */
htp_status_t htp_ch_multipart_callback_request_body_data(htp_tx_data_t *d) {
    htp_tx_t *tx = d->tx;

    // Check that we were not invoked again after the finalization.
    if (tx->request_mpartp->gave_up_data == 1) return HTP_ERROR;

    if (d->data != NULL) {
        // Process one chunk of data.
        htp_mpartp_parse(tx->request_mpartp, d->data, d->len);
    } else {
        // Finalize parsing.
        htp_mpartp_finalize(tx->request_mpartp);

        htp_multipart_t *body = htp_mpartp_get_multipart(tx->request_mpartp);

        for (size_t i = 0, n = htp_list_size(body->parts); i < n; i++) {
            htp_multipart_part_t *part = htp_list_get(body->parts, i);

            // Use text parameters.
            if (part->type == MULTIPART_PART_TEXT) {
                htp_param_t *param = calloc(1, sizeof (htp_param_t));
                if (param == NULL) return HTP_ERROR;
                param->name = part->name;
                param->value = part->value;
                param->source = HTP_SOURCE_BODY;
                param->parser_id = HTP_PARSER_MULTIPART;
                param->parser_data = part;

                if (htp_tx_req_add_param(tx, param) != HTP_OK) {
                    free(param);
                    return HTP_ERROR;
                }
            }
        }

        // Tell the parser that it no longer owns names
        // and values of MULTIPART_PART_TEXT parts.
        tx->request_mpartp->gave_up_data = 1;
    }

    return HTP_OK;
}
Example #19
0
htp_status_t htp_hook_run_one(htp_hook_t *hook, void *user_data) {
    if (hook == NULL) return HTP_DECLINED;

    for (size_t i = 0, n = htp_list_size(hook->callbacks); i < n; i++) {
        htp_callback_t *callback = htp_list_get(hook->callbacks, i);

        htp_status_t rc = callback->fn(user_data);

        // A hook can return HTP_DECLINED to say that it did no work,
        // and we'll ignore that. If we see HTP_OK or anything else,
        // we stop processing (because it was either a successful
        // handling or an error).
        if (rc != HTP_DECLINED) {
            // Return HTP_OK or an error.
            return rc;
        }
    }

    // No hook wanted to process the callback.
    return HTP_DECLINED;
}
Example #20
0
size_t bstr_builder_size(const bstr_builder_t *bb) {
    return htp_list_size(bb->pieces);
}
Example #21
0
static htp_status_t htp_tx_process_request_headers(htp_tx_t *tx) {
    // Remember how many header lines there were before trailers.
    tx->request_header_lines_no_trailers = htp_list_size(tx->request_header_lines);

    // Determine if we have a request body, and how it is packaged.
    htp_header_t *cl = htp_table_get_c(tx->request_headers, "content-length");
    htp_header_t *te = htp_table_get_c(tx->request_headers, "transfer-encoding");

    // Check for the Transfer-Encoding header, which would indicate a chunked request body.
    if (te != NULL) {
        // Make sure it contains "chunked" only.
        if (bstr_cmp_c(te->value, "chunked") != 0) {
            // Invalid T-E header value.
            tx->flags |= HTP_INVALID_CHUNKING;

            htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                    "Invalid T-E value in request");
        }

        // Chunked encoding is a HTTP/1.1 feature. Check that some other protocol is not
        // used. The flag will also be set if the protocol could not be parsed.
        //
        // TODO IIS 7.0, for example, would ignore the T-E header when it
        //      it is used with a protocol below HTTP 1.1.
        if (tx->request_protocol_number < HTP_PROTOCOL_1_1) {
            tx->flags |= HTP_INVALID_CHUNKING;
        }

        // If the T-E header is present we are going to use it.
        tx->request_transfer_coding = HTP_CODING_CHUNKED;

        // We are still going to check for the presence of C-L.
        if (cl != NULL) {
            // This is a violation of the RFC.
            tx->flags |= HTP_REQUEST_SMUGGLING;
        }
    } else if (cl != NULL) {
        // We have a request body of known length.
        tx->request_transfer_coding = HTP_CODING_IDENTITY;

        // Check for a folded C-L header.
        if (cl->flags & HTP_FIELD_FOLDED) {
            tx->flags |= HTP_REQUEST_SMUGGLING;
        }

        // Check for multiple C-L headers.
        if (cl->flags & HTP_FIELD_REPEATED) {
            tx->flags |= HTP_REQUEST_SMUGGLING;
        }

        // Get body length.
        tx->request_content_length = htp_parse_content_length(cl->value);
        if (tx->request_content_length < 0) {
            htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in request");
            return HTP_ERROR;
        }
    } else {
        // No body.
        tx->request_transfer_coding = HTP_CODING_NO_BODY;
    }

    // Check for PUT requests, which we need to treat as file uploads.
    if (tx->request_method_number == HTP_M_PUT) {
        if (htp_tx_req_has_body(tx)) {
            // Prepare to treat PUT request body as a file.
            tx->connp->put_file = calloc(1, sizeof (htp_file_t));
            if (tx->connp->put_file == NULL) return HTP_ERROR;
            tx->connp->put_file->source = HTP_FILE_PUT;
        } else {
            // TODO Warn about PUT request without a body.
        }

        return HTP_OK;
    }

    // Host resolution
    htp_header_t *h = htp_table_get_c(tx->request_headers, "host");
    if (h == NULL) {
        // No host information in the headers.

        // HTTP/1.1 requires host information in the headers.
        if (tx->request_protocol_number >= HTP_PROTOCOL_1_1) {
            tx->flags |= HTP_HOST_MISSING;
            htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0,
                    "Host information in request headers required by HTTP/1.1");
        }
    } else {
        // Host information available in the headers.

        bstr *hostname;
        int port;

        if (htp_parse_hostport(h->value, &hostname, &port, &(tx->flags)) != HTP_OK) return HTP_ERROR;

        // Is there host information in the URI?
        if (tx->parsed_uri->hostname == NULL) {
            // There is no host information in the URI. Place the
            // hostname from the headers into the parsed_uri structure.
            tx->parsed_uri->hostname = hostname;
            tx->parsed_uri->port_number = port;
        } else {
            if ((bstr_cmp_nocase(hostname, tx->parsed_uri->hostname) != 0) || (port != tx->parsed_uri->port_number)) {
                // The host information is different in the
                // headers and the URI. The HTTP RFC states that
                // we should ignore the header copy.
                tx->flags |= HTP_HOST_AMBIGUOUS;
                htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Host information ambiguous");
            }

            bstr_free(hostname);
        }
    }

    // Parse the Content-Type header.
    htp_header_t *ct = htp_table_get_c(tx->request_headers, "content-type");
    if (ct != NULL) {
        if (htp_parse_ct_header(ct->value, &tx->request_content_type) != HTP_OK) return HTP_ERROR;
    }

    // Parse cookies.
    if (tx->connp->cfg->parse_request_cookies) {
        htp_parse_cookies_v0(tx->connp);
    }

    // Parse authentication information.
    if (tx->connp->cfg->parse_request_http_authentication) {
        htp_parse_authorization(tx->connp);
    }

    // Run hook REQUEST_HEADERS.
    int rc = htp_hook_run_all(tx->connp->cfg->hook_request_headers, tx->connp);
    if (rc != HTP_OK) return rc;

    return HTP_OK;
}
Example #22
0
void htp_tx_destroy(htp_tx_t *tx) {
    bstr_free(tx->request_line);
    bstr_free(tx->request_line_raw);
    bstr_free(tx->request_method);
    bstr_free(tx->request_uri);
    bstr_free(tx->request_uri_normalized);
    bstr_free(tx->request_protocol);
    bstr_free(tx->request_headers_sep);

    if (tx->parsed_uri != NULL) {
        bstr_free(tx->parsed_uri->scheme);
        bstr_free(tx->parsed_uri->username);
        bstr_free(tx->parsed_uri->password);
        bstr_free(tx->parsed_uri->hostname);
        bstr_free(tx->parsed_uri->port);
        bstr_free(tx->parsed_uri->path);
        bstr_free(tx->parsed_uri->query);
        bstr_free(tx->parsed_uri->fragment);

        free(tx->parsed_uri);
    }

    if (tx->parsed_uri_incomplete != NULL) {
        bstr_free(tx->parsed_uri_incomplete->scheme);
        bstr_free(tx->parsed_uri_incomplete->username);
        bstr_free(tx->parsed_uri_incomplete->password);
        bstr_free(tx->parsed_uri_incomplete->hostname);
        bstr_free(tx->parsed_uri_incomplete->port);
        bstr_free(tx->parsed_uri_incomplete->path);
        bstr_free(tx->parsed_uri_incomplete->query);
        bstr_free(tx->parsed_uri_incomplete->fragment);
        free(tx->parsed_uri_incomplete);
    }

    // Destroy request_header_lines.
    if (tx->request_header_lines != NULL) {
        for (int i = 0, n = htp_list_size(tx->request_header_lines); i < n; i++) {
            htp_header_line_t *hl = htp_list_get(tx->request_header_lines, i);
            bstr_free(hl->line);
            // No need to destroy hl->header because
            // htp_header_line_t does not own it.
            free(hl);
        }

        htp_list_destroy(tx->request_header_lines);
        tx->request_header_lines = NULL;
    }

    // Destroy request_headers.
    if (tx->request_headers != NULL) {
        htp_header_t *h = NULL;
        for (int i = 0, n = htp_table_size(tx->request_headers); i < n; i++) {
            h = htp_table_get_index(tx->request_headers, i, NULL);
            bstr_free(h->name);
            bstr_free(h->value);
            free(h);
        }

        htp_table_destroy(tx->request_headers);
    }

    if (tx->request_headers_raw != NULL) {
        bstr_free(tx->request_headers_raw);
    }
    if (tx->response_headers_raw != NULL) {
        bstr_free(tx->response_headers_raw);
    }

    bstr_free(tx->response_line);
    bstr_free(tx->response_line_raw);
    bstr_free(tx->response_protocol);
    bstr_free(tx->response_status);
    bstr_free(tx->response_message);
    bstr_free(tx->response_headers_sep);

    // Destroy response_header_lines.
    if (tx->response_header_lines != NULL) {
        for (int i = 0, n = htp_list_size(tx->response_header_lines); i < n; i++) {
            htp_header_line_t *hl = htp_list_get(tx->response_header_lines, i);
            bstr_free(hl->line);
            // No need to destroy hl->header because
            // htp_header_line_t does not own it.
            free(hl);
        }

        htp_list_destroy(tx->response_header_lines);
        tx->response_header_lines = NULL;
    }

    // Destroy response headers.
    if (tx->response_headers != NULL) {
        htp_header_t *h = NULL;
        for (int i = 0, n = htp_table_size(tx->response_headers); i < n; i++) {
            h = htp_table_get_index(tx->response_headers, i, NULL);
            bstr_free(h->name);
            bstr_free(h->value);
            free(h);
        }

        htp_table_destroy(tx->response_headers);
    }

    // Tell the connection to remove this transaction from the list.
    htp_conn_remove_tx(tx->conn, tx);

    // Invalidate the pointer to this transactions held
    // by the connection parser. This is to allow a transaction
    // to be destroyed from within the final response callback.
    if (tx->connp != NULL) {
        if (tx->connp->out_tx == tx) {
            tx->connp->out_tx = NULL;
        }
    }

    bstr_free(tx->request_content_type);
    bstr_free(tx->response_content_type);

    // Parsers

    htp_urlenp_destroy(tx->request_urlenp_query);
    htp_urlenp_destroy(tx->request_urlenp_body);
    htp_mpartp_destroy(tx->request_mpartp);

    // Request parameters

    htp_param_t *param = NULL;
    for (int i = 0, n = htp_table_size(tx->request_params); i < n; i++) {
        param = htp_table_get_index(tx->request_params, i, NULL);
        free(param->name);
        free(param->value);
        free(param);
    }

    htp_table_destroy(tx->request_params);

    // Request cookies

    if (tx->request_cookies != NULL) {
        bstr *b = NULL;
        for (int i = 0, n = htp_table_size(tx->request_cookies); i < n; i++) {
            b = htp_table_get_index(tx->request_cookies, i, NULL);
            bstr_free(b);
        }

        htp_table_destroy(tx->request_cookies);
    }

    htp_hook_destroy(tx->hook_request_body_data);

    // If we're using a private configuration, destroy it.
    if (tx->is_config_shared == HTP_CONFIG_PRIVATE) {
        htp_config_destroy(tx->cfg);
    }

    free(tx);
}
Example #23
0
size_t htp_table_size(const htp_table_t *table) {
    if (table == NULL) return 0;
    return htp_list_size(table->list) / 2;
}