TEST(BstrTest, Alloc) { bstr *p1; p1 = bstr_alloc(10); EXPECT_EQ(10, bstr_size(p1)); EXPECT_EQ(0, bstr_len(p1)); bstr_free(p1); }
TEST(BstrTest, ExpandSmaller) { bstr *p1; bstr *p2; p1 = bstr_alloc(100); p2 = bstr_expand(p1, 10); ASSERT_TRUE(p2 == NULL); bstr_free(p1); }
TEST(BstrTest, ExpandLocal) { bstr *p1; bstr *p2; p1 = bstr_alloc(10); p2 = bstr_expand(p1, 100); ASSERT_NE(reinterpret_cast<bstr*>(NULL), p2); EXPECT_EQ(100, bstr_size(p2)); EXPECT_EQ(0, bstr_len(p2)); bstr_free(p2); }
TEST(BstrTest, Chop) { bstr *p1 = bstr_dup_c("abcdef"); bstr *p2 = bstr_alloc(10); bstr_chop(p1); EXPECT_EQ(0, bstr_cmp_c(p1,"abcde")); bstr_chop(p2); EXPECT_EQ(0, bstr_len(p2)); bstr_free(p1); bstr_free(p2); }
TEST(BstrTest, AddMemNoex) { bstr *p1; bstr *p2; p1 = bstr_alloc(10); p1 = bstr_add_c(p1, "12345"); p2 = bstr_add_mem_noex(p1,"abcdefghijklmnop",6); EXPECT_EQ(p1,p2); EXPECT_EQ(0,bstr_cmp_c(p2,"12345abcde")); bstr_free(p1); }
TEST(BstrTest, AddNoex) { bstr *p1; bstr *p2; bstr *p3; p1 = bstr_alloc(10); p1 = bstr_add_c(p1, "12345"); p2 = bstr_dup_c("abcdef"); p3 = bstr_add_noex(p1,p2); EXPECT_EQ(p1,p3); EXPECT_EQ(0,bstr_cmp_c(p3,"12345abcde")); bstr_free(p1); bstr_free(p2); }
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; }
/** * \brief Generates the normalized uri. * * Libhtp doesn't recreate the whole normalized uri and save it. * That duty has now been passed to us. A lot of this code has been * copied from libhtp. * * Keep an eye out on the tx->parsed_uri struct and how the parameters * in it are generated, just in case some modifications are made to * them in the future. * * \param uri_include_all boolean to indicate if scheme, username/password, hostname and port should be part of the buffer */ bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, int uri_include_all) { if (uri == NULL) return NULL; // On the first pass determine the length of the final string size_t len = 0; if (uri_include_all) { if (uri->scheme != NULL) { len += bstr_len(uri->scheme); len += 3; // "://" } if ((uri->username != NULL) || (uri->password != NULL)) { if (uri->username != NULL) { len += bstr_len(uri->username); } len += 1; // ":" if (uri->password != NULL) { len += bstr_len(uri->password); } len += 1; // "@" } if (uri->hostname != NULL) { len += bstr_len(uri->hostname); } if (uri->port != NULL) { len += 1; // ":" len += bstr_len(uri->port); } } if (uri->path != NULL) { len += bstr_len(uri->path); } if (uri->query != NULL) { len += 1; // "?" len += bstr_len(uri->query); } if (uri->fragment != NULL) { len += 1; // "#" len += bstr_len(uri->fragment); } // On the second pass construct the string /* FIXME in memcap */ bstr *r = bstr_alloc(len); if (r == NULL) { return NULL; } if (uri_include_all) { if (uri->scheme != NULL) { bstr_add_noex(r, uri->scheme); bstr_add_c_noex(r, "://"); } if ((uri->username != NULL) || (uri->password != NULL)) { if (uri->username != NULL) { bstr_add_noex(r, uri->username); } bstr_add_c_noex(r, ":"); if (uri->password != NULL) { bstr_add_noex(r, uri->password); } bstr_add_c_noex(r, "@"); } if (uri->hostname != NULL) { bstr_add_noex(r, uri->hostname); } if (uri->port != NULL) { bstr_add_c_noex(r, ":"); bstr_add_noex(r, uri->port); } } if (uri->path != NULL) { bstr_add_noex(r, uri->path); } if (uri->query != NULL) { bstr *query = bstr_dup(uri->query); if (query) { uint64_t flags = 0; htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); bstr_add_c_noex(r, "?"); bstr_add_noex(r, query); bstr_free(query); } } if (uri->fragment != NULL) { bstr_add_c_noex(r, "#"); bstr_add_noex(r, uri->fragment); } return r; }
/** * Extract one request header. A header can span multiple lines, in * which case they will be folded into one before parsing is attempted. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_process_request_header_apache_2_2(htp_connp_t *connp) { bstr *tempstr = NULL; unsigned char *data = NULL; size_t len = 0; // Create new header structure htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) return HTP_ERROR; // Ensure we have the necessary header data in a single buffer if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { // Single line htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, connp->in_header_line_index); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); free(h); return HTP_ERROR; } data = (unsigned char *) bstr_ptr(hl->line); len = bstr_len(hl->line); hl->header = h; } else { // Multiple lines (folded) int i = 0; for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); free(h); return HTP_ERROR; } len += bstr_len(hl->line); } tempstr = bstr_alloc(len); if (tempstr == NULL) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Failed to allocate bstring of %d bytes", len); free(h); return HTP_ERROR; } for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); bstr_free(tempstr); free(h); return HTP_ERROR; } char *data = bstr_ptr(hl->line); size_t len = bstr_len(hl->line); htp_chomp((unsigned char *)data, &len); bstr_add_mem_noex(tempstr, data, len); hl->header = h; } data = (unsigned char *) bstr_ptr(tempstr); } // Now try to parse the header if (htp_parse_request_header_apache_2_2(connp, h, data, len) != HTP_OK) { // Note: downstream responsible for error logging if (tempstr != NULL) { free(tempstr); } free(h); return HTP_ERROR; } // Do we already have a header with the same name? htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name); if (h_existing != NULL) { // TODO Do we want to keep a list of the headers that are // allowed to be combined in this way? // Add to existing header h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value)); bstr_add_mem_noex(h_existing->value, ", ", 2); bstr_add_str_noex(h_existing->value, h->value); // The header is no longer needed if (h->name != NULL) free(h->name); if (h->value != NULL) free(h->value); free(h); // Keep track of same-name headers h_existing->flags |= HTP_FIELD_REPEATED; } else { // Add as a new header table_add(connp->in_tx->request_headers, h->name, h); } if (tempstr != NULL) { free(tempstr); } return HTP_OK; }
/** * Extract one request header. A header can span multiple lines, in * which case they will be folded into one before parsing is attempted. * * @param[in] connp * @return HTP_OK or HTP_ERROR */ int htp_process_request_header_generic(htp_connp_t *connp) { bstr *tempstr = NULL; unsigned char *data = NULL; size_t len = 0; // Create new header structure htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) { return HTP_ERROR; } // Ensure we have the necessary header data in a single buffer if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { // Single line htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, connp->in_header_line_index); if (hl == NULL) { // Internal error free(h); return HTP_ERROR; } data = (unsigned char *)bstr_ptr(hl->line); len = bstr_len(hl->line); hl->header = h; } else { // Multiple lines (folded) int i = 0; for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i); len += bstr_len(hl->line); } tempstr = bstr_alloc(len); if (tempstr == NULL) { free(h); return HTP_ERROR; } for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i); unsigned char *line = bstr_ptr(hl->line); size_t llen = bstr_len(hl->line); htp_chomp((unsigned char *)line, &llen); bstr_add_mem_noex(tempstr, line, llen); hl->header = h; if (i != connp->in_header_line_index) { hl->flags |= HTP_FIELD_FOLDED; } } h->flags |= HTP_FIELD_FOLDED; data = (unsigned char *)bstr_ptr(tempstr); len = bstr_len(tempstr); } // Now try to parse the header if (htp_parse_request_header_generic(connp, h, data, len) != HTP_OK) { bstr_free(tempstr); free(h); return HTP_ERROR; } // Do we already have a header with the same name? htp_header_t *h_existing = htp_table_get(connp->in_tx->request_headers, h->name); if (h_existing != NULL) { // repeated header int i = 0; // TODO Do we want to keep a list of the headers that are // allowed to be combined in this way? // Add to existing header bstr *new_value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value)); if (new_value == NULL) { bstr_free(h->name); bstr_free(h->value); free(h); bstr_free(tempstr); return HTP_ERROR; } h_existing->value = new_value; bstr_add_mem_noex(h_existing->value, (unsigned char *)", ", 2); bstr_add_noex(h_existing->value, h->value); // replace the header references in all lines for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i); hl->header = h_existing; } // The header fields are no longer needed bstr_free(h->name); bstr_free(h->value); free(h); // Keep track of same-name headers h_existing->flags |= HTP_FIELD_REPEATED; } else { // Add as a new header htp_table_add(connp->in_tx->request_headers, h->name, h); } bstr_free(tempstr); return HTP_OK; }