diff options
Diffstat (limited to 'test/test_main.cpp')
-rw-r--r-- | test/test_main.cpp | 2148 |
1 files changed, 2148 insertions, 0 deletions
diff --git a/test/test_main.cpp b/test/test_main.cpp new file mode 100644 index 0000000..73b8686 --- /dev/null +++ b/test/test_main.cpp @@ -0,0 +1,2148 @@ +/*************************************************************************** + * Copyright (c) 2009-2010 Open Information Security Foundation + * Copyright (c) 2010-2013 Qualys, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + + * - Neither the name of the Qualys, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************/ + +/** + * @file + * + * @author Ivan Ristic <ivanr@webkreator.com> + */ + +#include <iostream> +#include <gtest/gtest.h> +#include <htp/htp_private.h> +#include "test.h" + +class ConnectionParsing : public testing::Test { +protected: + + virtual void SetUp() { + home = getenv("srcdir"); + if (home == NULL) { + fprintf(stderr, "This program needs environment variable 'srcdir' set."); + exit(EXIT_FAILURE); + } + + cfg = htp_config_create(); + htp_config_set_server_personality(cfg, HTP_SERVER_APACHE_2); + htp_config_register_urlencoded_parser(cfg); + htp_config_register_multipart_parser(cfg); + } + + virtual void TearDown() { + htp_connp_destroy_all(connp); + htp_config_destroy(cfg); + } + + htp_connp_t *connp; + + htp_cfg_t *cfg; + + char *home; +}; + +TEST_F(ConnectionParsing, AdHoc) { + int rc = test_run(home, "00-adhoc.t", cfg, &connp); + ASSERT_GE(rc, 0); +} + +TEST_F(ConnectionParsing, Get) { + int rc = test_run(home, "01-get.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/?p=%20")); + + ASSERT_TRUE(tx->parsed_uri != NULL); + + ASSERT_TRUE(tx->parsed_uri->query != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->query, "p=%20")); + + htp_param_t *p = htp_tx_req_get_param(tx, "p", 1); + ASSERT_TRUE(p != NULL); + + ASSERT_EQ(0, bstr_cmp_c(p->value, " ")); +} + +TEST_F(ConnectionParsing, ApacheHeaderParsing) { + int rc = test_run(home, "02-header-test-apache2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(9, htp_table_size(tx->request_headers)); + + // Check every header + int count = 0; + bstr *key = NULL; + htp_header_t *h = NULL; + + for (int i = 0, n = htp_table_size(tx->request_headers); i < n; i++) { + h = (htp_header_t *) htp_table_get_index(tx->request_headers, i, &key); + + switch (count) { + case 0: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Invalid-Folding")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "1")); + break; + case 1: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Valid-Folding")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "2 2")); + break; + case 2: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Normal-Header")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "3")); + break; + case 3: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Invalid Header Name")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "4")); + break; + case 4: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Same-Name-Headers")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "5, 6")); + break; + case 5: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Empty-Value-Header")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "")); + break; + case 6: + ASSERT_EQ(0, bstr_cmp_c(h->name, "")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "8, ")); + break; + case 7: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Header-With-LWS-After")); + ASSERT_EQ(0, bstr_cmp_c(h->value, "9")); + break; + case 8: + ASSERT_EQ(0, bstr_cmp_c(h->name, "Header-With-NUL")); + ASSERT_EQ(0, bstr_cmp_c_nocasenorzero(h->value, "BEFOREAFTER")); + break; + } + + count++; + } +} + +TEST_F(ConnectionParsing, PostUrlencoded) { + int rc = test_run(home, "03-post-urlencoded.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + htp_param_t *p = htp_tx_req_get_param(tx1, "p", 1); + ASSERT_TRUE(p != NULL); + + ASSERT_EQ(0, bstr_cmp_c(p->value, "0123456789")); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx1->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx1->response_progress); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx1->response_headers, "Server"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + ASSERT_EQ(0, bstr_cmp_c(h->value, "Apache")); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx2->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx2->response_progress); + + h = (htp_header_t *)htp_table_get_c(tx2->response_headers, "Server"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + ASSERT_EQ(0, bstr_cmp_c(h->value, "Apache")); +} + +TEST_F(ConnectionParsing, PostUrlencodedChunked) { + int rc = test_run(home, "04-post-urlencoded-chunked.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + htp_param_t *p = htp_tx_req_get_param(tx, "p", 1); + ASSERT_TRUE(p != NULL); + + ASSERT_EQ(0, bstr_cmp_c(p->value, "0123456789")); + + ASSERT_EQ(25, tx->request_message_len); + + ASSERT_EQ(12, tx->request_entity_len); +} + +TEST_F(ConnectionParsing, Expect) { + int rc = test_run(home, "05-expect.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + // The interim header from the 100 response should not be among the final headers. + htp_header_t *h = (htp_header_t *) htp_table_get_c(tx->request_headers, "Header1"); + ASSERT_TRUE(h == NULL); +} + +TEST_F(ConnectionParsing, UriNormal) { + int rc = test_run(home, "06-uri-normal.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); +} + +TEST_F(ConnectionParsing, PipelinedConn) { + int rc = test_run(home, "07-pipelined-connection.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + ASSERT_TRUE(connp->conn->flags & HTP_CONN_PIPELINED); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); +} + +TEST_F(ConnectionParsing, NotPipelinedConn) { + int rc = test_run(home, "08-not-pipelined-connection.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + ASSERT_FALSE(connp->conn->flags & HTP_CONN_PIPELINED); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_FALSE(tx->flags & HTP_MULTI_PACKET_HEAD); +} + +TEST_F(ConnectionParsing, MultiPacketRequest) { + int rc = test_run(home, "09-multi-packet-request-head.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_MULTI_PACKET_HEAD); +} + +TEST_F(ConnectionParsing, HeaderHostParsing) { + int rc = test_run(home, "10-host-in-headers.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(4, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + ASSERT_TRUE(tx1->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx1->request_hostname, "www.example.com")); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + ASSERT_TRUE(tx2->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx2->request_hostname, "www.example.com.")); + + htp_tx_t *tx3 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 2); + ASSERT_TRUE(tx3 != NULL); + ASSERT_TRUE(tx3->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx3->request_hostname, "www.example.com")); + + htp_tx_t *tx4 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 3); + ASSERT_TRUE(tx4 != NULL); + ASSERT_TRUE(tx4->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx4->request_hostname, "www.example.com")); +} + +TEST_F(ConnectionParsing, ResponseWithoutContentLength) { + int rc = test_run(home, "11-response-stream-closure.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); +} + +TEST_F(ConnectionParsing, FailedConnectRequest) { + int rc = test_run(home, "12-connect-request.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "CONNECT")); + + ASSERT_EQ(405, tx->response_status_number); +} + +TEST_F(ConnectionParsing, CompressedResponseContentType) { + int rc = test_run(home, "13-compressed-response-gzip-ct.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(187, tx->response_message_len); + + ASSERT_EQ(225, tx->response_entity_len); +} + +TEST_F(ConnectionParsing, CompressedResponseChunked) { + int rc = test_run(home, "14-compressed-response-gzip-chunked.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(28261, tx->response_message_len); + + ASSERT_EQ(159590, tx->response_entity_len); +} + +TEST_F(ConnectionParsing, SuccessfulConnectRequest) { + int rc = test_run(home, "15-connect-complete.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + // TODO: Update the test_run() function to provide better + // simulation of real traffic. At the moment, it does not + // invoke inbound parsing after outbound parsing returns + // HTP_DATA_OTHER, which is why the check below fails. + //ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "CONNECT")); + + ASSERT_EQ(200, tx->response_status_number); +} + +TEST_F(ConnectionParsing, ConnectRequestWithExtraData) { + int rc = test_run(home, "16-connect-extra.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx1)); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx2)); +} + +TEST_F(ConnectionParsing, Multipart) { + int rc = test_run(home, "17-multipart-1.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + htp_param_t *field1 = htp_tx_req_get_param(tx, "field1", 6); + ASSERT_TRUE(field1 != NULL); + ASSERT_EQ(0, bstr_cmp_c(field1->value, "0123456789")); + + htp_param_t *field2 = htp_tx_req_get_param(tx, "field2", 6); + ASSERT_TRUE(field2 != NULL); + ASSERT_EQ(0, bstr_cmp_c(field2->value, "9876543210")); +} + +TEST_F(ConnectionParsing, CompressedResponseDeflate) { + int rc = test_run(home, "18-compressed-response-deflate.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(755, tx->response_message_len); + + ASSERT_EQ(1433, tx->response_entity_len); +} + +TEST_F(ConnectionParsing, UrlEncoded) { + int rc = test_run(home, "19-urlencoded-test.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "POST")); + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/?p=1&q=2")); + + htp_param_t *body_p = htp_tx_req_get_param_ex(tx, HTP_SOURCE_BODY, "p", 1); + ASSERT_TRUE(body_p != NULL); + ASSERT_EQ(0, bstr_cmp_c(body_p->value, "3")); + + htp_param_t *body_q = htp_tx_req_get_param_ex(tx, HTP_SOURCE_BODY, "q", 1); + ASSERT_TRUE(body_q != NULL); + ASSERT_EQ(0, bstr_cmp_c(body_q->value, "4")); + + htp_param_t *body_z = htp_tx_req_get_param_ex(tx, HTP_SOURCE_BODY, "z", 1); + ASSERT_TRUE(body_z != NULL); + ASSERT_EQ(0, bstr_cmp_c(body_z->value, "5")); +} + +TEST_F(ConnectionParsing, AmbiguousHost) { + int rc = test_run(home, "20-ambiguous-host.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(5, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + ASSERT_TRUE(htp_tx_is_complete(tx1)); + ASSERT_FALSE(tx1->flags & HTP_HOST_AMBIGUOUS); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + ASSERT_TRUE(htp_tx_is_complete(tx2)); + ASSERT_TRUE(tx2->flags & HTP_HOST_AMBIGUOUS); + ASSERT_TRUE(tx2->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx2->request_hostname, "example.com")); + + htp_tx_t *tx3 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 2); + ASSERT_TRUE(tx3 != NULL); + ASSERT_TRUE(htp_tx_is_complete(tx3)); + ASSERT_FALSE(tx3->flags & HTP_HOST_AMBIGUOUS); + ASSERT_TRUE(tx3->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx3->request_hostname, "www.example.com")); + ASSERT_EQ(8001, tx3->request_port_number); + + htp_tx_t *tx4 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 3); + ASSERT_TRUE(tx4 != NULL); + ASSERT_TRUE(htp_tx_is_complete(tx4)); + ASSERT_TRUE(tx4->flags & HTP_HOST_AMBIGUOUS); + ASSERT_TRUE(tx4->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx4->request_hostname, "www.example.com")); + ASSERT_EQ(8002, tx4->request_port_number); + + htp_tx_t *tx5 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 4); + ASSERT_TRUE(tx5 != NULL); + ASSERT_TRUE(htp_tx_is_complete(tx5)); + ASSERT_FALSE(tx5->flags & HTP_HOST_AMBIGUOUS); + ASSERT_TRUE(tx5->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx5->request_hostname, "www.example.com")); + ASSERT_EQ(80, tx5->request_port_number); +} + +TEST_F(ConnectionParsing, Http_0_9) { + int rc = test_run(home, "21-http09.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + ASSERT_FALSE(connp->conn->flags & HTP_CONN_HTTP_0_9_EXTRA); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); +} + +TEST_F(ConnectionParsing, PhpParamProcessing) { + cfg->parameter_processor = htp_php_parameter_processor; + + int rc = test_run(home, "22-php-param-processing.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + htp_param_t *p1 = htp_tx_req_get_param(tx, "p_q_", 4); + ASSERT_TRUE(p1 != NULL); + ASSERT_EQ(0, bstr_cmp_c(p1->value, "1")); + + htp_param_t *p2 = htp_tx_req_get_param(tx, "q", 1); + ASSERT_TRUE(p2 != NULL); + ASSERT_EQ(0, bstr_cmp_c(p2->value, "2")); + + htp_param_t *p3 = htp_tx_req_get_param(tx, "z_w", 3); + ASSERT_TRUE(p3 != NULL); + ASSERT_EQ(0, bstr_cmp_c(p3->value, "3")); +} + +TEST_F(ConnectionParsing, Http11HostMissing) { + int rc = test_run(home, "22-http_1_1-host_missing", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_HOST_MISSING); +} + +TEST_F(ConnectionParsing, Http_0_9_Multiple) { + int rc = test_run(home, "23-http09-multiple.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); +} + +TEST_F(ConnectionParsing, Http_0_9_Explicit) { + int rc = test_run(home, "24-http09-explicit.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, tx->is_protocol_0_9); +} + +TEST_F(ConnectionParsing, SmallChunks) { + int rc = test_run(home, "25-small-chunks.t", cfg, &connp); + ASSERT_GE(rc, 0); +} + +static int ConnectionParsing_RequestHeaderData_REQUEST_HEADER_DATA(htp_tx_data_t *d) { + static int counter = 0; + + switch (counter) { + case 0: + if (!((d->len == 11) && (memcmp(d->data, "User-Agent:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 0"); + counter = -1; + } + break; + + case 1: + if (!((d->len == 5) && (memcmp(d->data, " Test", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -1; + } + break; + + case 2: + if (!((d->len == 5) && (memcmp(d->data, " User", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 2"); + counter = -1; + } + break; + + case 3: + if (!((d->len == 30) && (memcmp(d->data, " Agent\nHost: www.example.com\n\n", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 3"); + counter = -1; + } + break; + + default: + if (counter >= 0) { + SCOPED_TRACE("Seen more than 4 chunks"); + counter = -1; + } + break; + } + + if (counter >= 0) { + counter++; + } + + htp_tx_set_user_data(d->tx, &counter); + + return HTP_OK; +} + +TEST_F(ConnectionParsing, RequestHeaderData) { + htp_config_register_request_header_data(cfg, ConnectionParsing_RequestHeaderData_REQUEST_HEADER_DATA); + + int rc = test_run(home, "26-request-headers-raw.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + int *counter = (int *) htp_tx_get_user_data(tx); + ASSERT_TRUE(counter != NULL); + ASSERT_EQ(4, *counter); +} + +static int ConnectionParsing_RequestTrailerData_REQUEST_TRAILER_DATA(htp_tx_data_t *d) { + static int counter = 0; + + switch (counter) { + case 0: + if (!((d->len == 7) && (memcmp(d->data, "Cookie:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 0"); + counter = -1; + } + break; + + case 1: + if (!((d->len == 6) && (memcmp(d->data, " 2\r\n\r\n", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -2; + } + break; + + default: + if (counter >= 0) { + SCOPED_TRACE("Seen more than 4 chunks"); + counter = -3; + } + break; + } + + if (counter >= 0) { + counter++; + } + + htp_tx_set_user_data(d->tx, &counter); + + return HTP_OK; +} + +TEST_F(ConnectionParsing, RequestTrailerData) { + htp_config_register_request_trailer_data(cfg, ConnectionParsing_RequestTrailerData_REQUEST_TRAILER_DATA); + + int rc = test_run(home, "27-request-trailer-raw.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + int *counter = (int *) htp_tx_get_user_data(tx); + ASSERT_TRUE(counter != NULL); + ASSERT_EQ(2, *counter); +} + +static int ConnectionParsing_ResponseHeaderData_RESPONSE_HEADER_DATA(htp_tx_data_t *d) { + static int counter = 0; + + switch (counter) { + case 0: + if (!((d->len == 5) && (memcmp(d->data, "Date:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 0"); + counter = -1; + } + break; + + case 1: + if (!((d->len == 5) && (memcmp(d->data, " Mon,", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -2; + } + break; + + case 2: + if (!((d->len == 34) && (memcmp(d->data, " 31 Aug 2009 20:25:50 GMT\r\nServer:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 2"); + counter = -3; + } + break; + + case 3: + if (!((d->len == 83) && (memcmp(d->data, " Apache\r\nConnection: close\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 3"); + counter = -4; + } + break; + + default: + if (counter >= 0) { + SCOPED_TRACE("Seen more than 4 chunks"); + counter = -5; + } + break; + } + + if (counter >= 0) { + counter++; + } + + htp_tx_set_user_data(d->tx, &counter); + + return HTP_OK; +} + +TEST_F(ConnectionParsing, ResponseHeaderData) { + htp_config_register_response_header_data(cfg, ConnectionParsing_ResponseHeaderData_RESPONSE_HEADER_DATA); + + int rc = test_run(home, "28-response-headers-raw.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + int *counter = (int *) htp_tx_get_user_data(tx); + ASSERT_TRUE(counter != NULL); + ASSERT_EQ(4, *counter); +} + +static int ConnectionParsing_ResponseTrailerData_RESPONSE_TRAILER_DATA(htp_tx_data_t *d) { + static int counter = 0; + + switch (counter) { + case 0: + if (!((d->len == 11) && (memcmp(d->data, "Set-Cookie:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 0"); + counter = -1; + } + break; + + case 1: + if (!((d->len == 6) && (memcmp(d->data, " name=", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -2; + } + break; + + case 2: + if (!((d->len == 22) && (memcmp(d->data, "value\r\nAnother-Header:", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -3; + } + break; + + case 3: + if (!((d->len == 17) && (memcmp(d->data, " Header-Value\r\n\r\n", d->len) == 0))) { + SCOPED_TRACE("Mismatch in chunk 1"); + counter = -4; + } + break; + + default: + if (counter >= 0) { + SCOPED_TRACE("Seen more than 4 chunks"); + counter = -5; + } + break; + } + + if (counter >= 0) { + counter++; + } + + htp_tx_set_user_data(d->tx, &counter); + + return HTP_OK; +} + +TEST_F(ConnectionParsing, ResponseTrailerData) { + htp_config_register_response_trailer_data(cfg, ConnectionParsing_ResponseTrailerData_RESPONSE_TRAILER_DATA); + + int rc = test_run(home, "29-response-trailer-raw.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + int *counter = (int *) htp_tx_get_user_data(tx); + ASSERT_TRUE(counter != NULL); + ASSERT_EQ(4, *counter); +} + +TEST_F(ConnectionParsing, GetIPv6) { + int rc = test_run(home, "30-get-ipv6.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->request_method != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + + ASSERT_TRUE(tx->request_uri != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "http://[::1]:8080/?p=%20")); + + ASSERT_TRUE(tx->parsed_uri != NULL); + + ASSERT_TRUE(tx->parsed_uri->hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->hostname, "[::1]")); + ASSERT_EQ(8080, tx->parsed_uri->port_number); + + ASSERT_TRUE(tx->parsed_uri->query != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->query, "p=%20")); + + htp_param_t *p = htp_tx_req_get_param(tx, "p", 1); + ASSERT_TRUE(p != NULL); + ASSERT_TRUE(p->value != NULL); + ASSERT_EQ(0, bstr_cmp_c(p->value, " ")); +} + +TEST_F(ConnectionParsing, GetRequestLineNul) { + int rc = test_run(home, "31-get-request-line-nul.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->request_uri != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/?p=%20")); +} + +TEST_F(ConnectionParsing, InvalidHostname1) { + int rc = test_run(home, "32-invalid-hostname.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_HOSTH_INVALID); + ASSERT_TRUE(tx->flags & HTP_HOSTU_INVALID); + ASSERT_TRUE(tx->flags & HTP_HOST_INVALID); +} + +TEST_F(ConnectionParsing, InvalidHostname2) { + int rc = test_run(home, "33-invalid-hostname.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_FALSE(tx->flags & HTP_HOSTH_INVALID); + ASSERT_TRUE(tx->flags & HTP_HOSTU_INVALID); + ASSERT_TRUE(tx->flags & HTP_HOST_INVALID); +} + +TEST_F(ConnectionParsing, InvalidHostname3) { + int rc = test_run(home, "34-invalid-hostname.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_HOSTH_INVALID); + ASSERT_FALSE(tx->flags & HTP_HOSTU_INVALID); + ASSERT_TRUE(tx->flags & HTP_HOST_INVALID); +} + +TEST_F(ConnectionParsing, API_connp_get_connection) { + int rc = test_run(home, "34-invalid-hostname.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(connp->conn, htp_connp_get_connection(connp)); +} + +TEST_F(ConnectionParsing, EarlyResponse) { + int rc = test_run(home, "35-early-response.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); +} + +TEST_F(ConnectionParsing, InvalidRequest1) { + int rc = test_run(home, "36-invalid-request-1-invalid-c-l.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_HEADERS, tx->request_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_INVALID); + ASSERT_TRUE(tx->flags & HTP_REQUEST_INVALID_C_L); + + ASSERT_TRUE(tx->request_hostname != NULL); +} + +TEST_F(ConnectionParsing, InvalidRequest2) { + int rc = test_run(home, "37-invalid-request-2-t-e-and-c-l.t", cfg, &connp); + ASSERT_GE(rc, 0); // No error, flags only. + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_SMUGGLING); + + ASSERT_TRUE(tx->request_hostname != NULL); +} + +TEST_F(ConnectionParsing, InvalidRequest3) { + int rc = test_run(home, "38-invalid-request-3-invalid-t-e.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_HEADERS, tx->request_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_INVALID); + ASSERT_TRUE(tx->flags & HTP_REQUEST_INVALID_T_E); + + ASSERT_TRUE(tx->request_hostname != NULL); +} + +TEST_F(ConnectionParsing, AutoDestroyCrash) { + htp_config_set_tx_auto_destroy(cfg, 1); + + int rc = test_run(home, "39-auto-destroy-crash.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(4, htp_list_size(connp->conn->transactions)); +} + +TEST_F(ConnectionParsing, AuthBasic) { + int rc = test_run(home, "40-auth-basic.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_BASIC, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_auth_username, "ivanr")); + + ASSERT_TRUE(tx->request_auth_password != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_auth_password, "secret")); +} + +TEST_F(ConnectionParsing, AuthDigest) { + int rc = test_run(home, "41-auth-digest.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_DIGEST, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_auth_username, "ivanr")); + + ASSERT_TRUE(tx->request_auth_password == NULL); +} + +TEST_F(ConnectionParsing, AuthBearer) { + int rc = test_run(home, "100-auth-bearer.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_BEARER, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); +} + +TEST_F(ConnectionParsing, Unknown_MethodOnly) { + int rc = test_run(home, "42-unknown-method_only.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_TRUE(tx->request_method != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "HELLO")); + + ASSERT_TRUE(tx->request_uri == NULL); + + ASSERT_EQ(1, tx->is_protocol_0_9); +} + +TEST_F(ConnectionParsing, InvalidProtocol) { + int rc = test_run(home, "43-invalid-protocol.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_PROTOCOL_INVALID, tx->request_protocol_number); +} + +TEST_F(ConnectionParsing, AuthBasicInvalid) { + int rc = test_run(home, "44-auth-basic-invalid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_BASIC, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); + + ASSERT_TRUE(tx->flags & HTP_AUTH_INVALID); +} + +TEST_F(ConnectionParsing, AuthDigestUnquotedUsername) { + int rc = test_run(home, "45-auth-digest-unquoted-username.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_DIGEST, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); + + ASSERT_TRUE(tx->flags & HTP_AUTH_INVALID); +} + +TEST_F(ConnectionParsing, AuthDigestInvalidUsername1) { + int rc = test_run(home, "46-auth-digest-invalid-username.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_DIGEST, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); + + ASSERT_TRUE(tx->flags & HTP_AUTH_INVALID); +} + +TEST_F(ConnectionParsing, AuthUnrecognized) { + int rc = test_run(home, "47-auth-unrecognized.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_UNRECOGNIZED, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); +} + +TEST_F(ConnectionParsing, InvalidResponseHeaders1) { + int rc = test_run(home, "48-invalid-response-headers-1.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_EQ(8, htp_table_size(tx->response_headers)); + + htp_header_t *h_empty = (htp_header_t *) htp_table_get_c(tx->response_headers, ""); + ASSERT_TRUE(h_empty != NULL); + ASSERT_EQ(0, bstr_cmp_c(h_empty->value, "No Colon")); + ASSERT_TRUE(h_empty->flags & HTP_FIELD_INVALID); + ASSERT_TRUE(h_empty->flags & HTP_FIELD_UNPARSEABLE); + + htp_header_t *h_lws = (htp_header_t *) htp_table_get_c(tx->response_headers, "Lws"); + ASSERT_TRUE(h_lws != NULL); + ASSERT_EQ(0, bstr_cmp_c(h_lws->value, "After Header Name")); + ASSERT_TRUE(h_lws->flags & HTP_FIELD_INVALID); + + htp_header_t *h_nottoken = (htp_header_t *) htp_table_get_c(tx->response_headers, "Header@Name"); + ASSERT_TRUE(h_nottoken != NULL); + ASSERT_EQ(0, bstr_cmp_c(h_nottoken->value, "Not Token")); + ASSERT_TRUE(h_nottoken->flags & HTP_FIELD_INVALID); +} + +TEST_F(ConnectionParsing, InvalidResponseHeaders2) { + int rc = test_run(home, "49-invalid-response-headers-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_EQ(6, htp_table_size(tx->response_headers)); + + htp_header_t *h_empty = (htp_header_t *) htp_table_get_c(tx->response_headers, ""); + ASSERT_TRUE(h_empty != NULL); + ASSERT_EQ(0, bstr_cmp_c(h_empty->value, "Empty Name")); + ASSERT_TRUE(h_empty->flags & HTP_FIELD_INVALID); +} + +TEST_F(ConnectionParsing, Util) { + int rc = test_run(home, "50-util.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + char *in_state = htp_connp_in_state_as_string(tx->connp); + ASSERT_TRUE(in_state != NULL); + + char *out_state = htp_connp_out_state_as_string(tx->connp); + ASSERT_TRUE(out_state != NULL); + + char *request_progress = htp_tx_request_progress_as_string(tx); + ASSERT_TRUE(request_progress != NULL); + + char *response_progress = htp_tx_response_progress_as_string(tx); + ASSERT_TRUE(response_progress != NULL); + + FILE *null = fopen("/dev/null", "w"); + ASSERT_TRUE(null != NULL); + + fprint_bstr(null, "test", NULL); + + fprint_bstr(null, "test", tx->request_line); + + fprint_raw_data(null, "test", bstr_ptr(tx->request_line), bstr_len(tx->request_line)); + + fprint_raw_data_ex(null, "test", bstr_ptr(tx->request_line), 0, bstr_len(tx->request_line)); + + // Message too long. + tx->connp->cfg->log_level = HTP_LOG_ERROR; + char long_message[1300]; + for (size_t i = 0; i < 1299; i++) { + long_message[i] = 'X'; + } + long_message[1299] = '\0'; + + htp_log(tx->connp, __FILE__, __LINE__, HTP_LOG_ERROR, 0, long_message); + ASSERT_TRUE(tx->connp->last_error != NULL); + ASSERT_TRUE(tx->connp->last_error->msg != NULL); + ASSERT_EQ(1023, strlen(tx->connp->last_error->msg)); + ASSERT_EQ('+', tx->connp->last_error->msg[1022]); + + // A message that should not be logged. + size_t log_message_count = htp_list_size(tx->connp->conn->messages); + tx->connp->cfg->log_level = HTP_LOG_NONE; + htp_log(tx->connp, __FILE__, __LINE__, HTP_LOG_ERROR, 0, "Log message"); + ASSERT_EQ(log_message_count, htp_list_size(tx->connp->conn->messages)); +} + +TEST_F(ConnectionParsing, GetIPv6Invalid) { + int rc = test_run(home, "51-get-ipv6-invalid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->request_method != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + + ASSERT_TRUE(tx->request_uri != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "http://[::1:8080/?p=%20")); + + ASSERT_TRUE(tx->parsed_uri != NULL); + + ASSERT_TRUE(tx->parsed_uri->hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->hostname, "[::1:8080")); +} + +TEST_F(ConnectionParsing, InvalidPath) { + int rc = test_run(home, "52-invalid-path.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->request_method != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + + ASSERT_TRUE(tx->request_uri != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "invalid/path?p=%20")); + + ASSERT_TRUE(tx->parsed_uri != NULL); + + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "invalid/path")); +} + +TEST_F(ConnectionParsing, PathUtf8_None) { + int rc = test_run(home, "53-path-utf8-none.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_FALSE(tx->flags & HTP_PATH_UTF8_VALID); + ASSERT_FALSE(tx->flags & HTP_PATH_UTF8_OVERLONG); + ASSERT_FALSE(tx->flags & HTP_PATH_HALF_FULL_RANGE); +} + +TEST_F(ConnectionParsing, PathUtf8_Valid) { + int rc = test_run(home, "54-path-utf8-valid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_VALID); +} + +TEST_F(ConnectionParsing, PathUtf8_Overlong2) { + int rc = test_run(home, "55-path-utf8-overlong-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); +} + +TEST_F(ConnectionParsing, PathUtf8_Overlong3) { + int rc = test_run(home, "56-path-utf8-overlong-3.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); +} + +TEST_F(ConnectionParsing, PathUtf8_Overlong4) { + int rc = test_run(home, "57-path-utf8-overlong-4.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); +} + +TEST_F(ConnectionParsing, PathUtf8_Invalid) { + int rc = test_run(home, "58-path-utf8-invalid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_INVALID); + ASSERT_FALSE(tx->flags & HTP_PATH_UTF8_VALID); +} + +TEST_F(ConnectionParsing, PathUtf8_FullWidth) { + int rc = test_run(home, "59-path-utf8-fullwidth.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_HALF_FULL_RANGE); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_Valid) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "54-path-utf8-valid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/Ristic.txt")); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_Overlong2) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "55-path-utf8-overlong-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/&.txt")); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_Overlong3) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "56-path-utf8-overlong-3.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/&.txt")); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_Overlong4) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "57-path-utf8-overlong-4.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_OVERLONG); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/&.txt")); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_Invalid) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "58-path-utf8-invalid.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_UTF8_INVALID); + ASSERT_FALSE(tx->flags & HTP_PATH_UTF8_VALID); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/Ristic?.txt")); +} + +TEST_F(ConnectionParsing, PathUtf8_Decode_FullWidth) { + htp_config_set_utf8_convert_bestfit(cfg, HTP_DECODER_URL_PATH, 1); + + int rc = test_run(home, "59-path-utf8-fullwidth.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->flags & HTP_PATH_HALF_FULL_RANGE); + + ASSERT_TRUE(tx->parsed_uri != NULL); + ASSERT_TRUE(tx->parsed_uri->path != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->path, "/&.txt")); +} + +TEST_F(ConnectionParsing, RequestCookies) { + int rc = test_run(home, "60-request-cookies.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(3, htp_table_size(tx->request_cookies)); + + bstr *key = NULL; + bstr *value = NULL; + + value = (bstr *) htp_table_get_index(tx->request_cookies, 0, &key); + ASSERT_TRUE(key != NULL); + ASSERT_TRUE(value != NULL); + ASSERT_EQ(0, bstr_cmp_c(key, "p")); + ASSERT_EQ(0, bstr_cmp_c(value, "1")); + + value = (bstr *) htp_table_get_index(tx->request_cookies, 1, &key); + ASSERT_TRUE(key != NULL); + ASSERT_TRUE(value != NULL); + ASSERT_EQ(0, bstr_cmp_c(key, "q")); + ASSERT_EQ(0, bstr_cmp_c(value, "2")); + + value = (bstr *) htp_table_get_index(tx->request_cookies, 2, &key); + ASSERT_TRUE(key != NULL); + ASSERT_TRUE(value != NULL); + ASSERT_EQ(0, bstr_cmp_c(key, "z")); + ASSERT_EQ(0, bstr_cmp_c(value, "")); +} + +TEST_F(ConnectionParsing, EmptyLineBetweenRequests) { + int rc = test_run(home, "61-empty-line-between-requests.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx != NULL); + + /*part of previous request body ASSERT_EQ(1, tx->request_ignored_lines);*/ +} + +TEST_F(ConnectionParsing, PostNoBody) { + int rc = test_run(home, "62-post-no-body.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx1->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx1->response_progress); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx2->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx2->response_progress); +} + +TEST_F(ConnectionParsing, PostChunkedInvalid1) { + int rc = test_run(home, "63-post-chunked-invalid-1.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. +} + +TEST_F(ConnectionParsing, PostChunkedInvalid2) { + int rc = test_run(home, "64-post-chunked-invalid-2.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. +} + +TEST_F(ConnectionParsing, PostChunkedInvalid3) { + int rc = test_run(home, "65-post-chunked-invalid-3.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. +} + +TEST_F(ConnectionParsing, PostChunkedSplitChunk) { + int rc = test_run(home, "66-post-chunked-split-chunk.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + htp_param_t *p = htp_tx_req_get_param(tx, "p", 1); + ASSERT_TRUE(p != NULL); + ASSERT_TRUE(p->value != NULL); + ASSERT_EQ(0, bstr_cmp_c(p->value, "0123456789")); +} + +TEST_F(ConnectionParsing, LongRequestLine1) { + int rc = test_run(home, "67-long-request-line.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/0123456789/0123456789/")); +} + +TEST_F(ConnectionParsing, LongRequestLine2) { + htp_config_set_field_limits(cfg, 0, 16); + + int rc = test_run(home, "67-long-request-line.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_LINE, tx->request_progress); +} + +TEST_F(ConnectionParsing, InvalidRequestHeader) { + int rc = test_run(home, "68-invalid-request-header.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + htp_header_t *h = (htp_header_t *) htp_table_get_c(tx->request_headers, "Header-With-NUL"); + ASSERT_TRUE(h != NULL); + ASSERT_EQ(0, bstr_cmp_c_nocasenorzero(h->value, "BEFORE AFTER")); +} + +TEST_F(ConnectionParsing, TestGenericPersonality) { + htp_config_set_server_personality(cfg, HTP_SERVER_IDS); + + int rc = test_run(home, "02-header-test-apache2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); +} + +TEST_F(ConnectionParsing, LongResponseHeader) { + htp_config_set_field_limits(cfg, 0, 16); + + int rc = test_run(home, "69-long-response-header.t", cfg, &connp); + ASSERT_LT(rc, 0); // Expect error. + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + //error first ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_HEADERS, tx->response_progress); +} + +TEST_F(ConnectionParsing, ResponseInvalidChunkLength) { + int rc = test_run(home, "70-response-invalid-chunk-length.t", cfg, &connp); + ASSERT_EQ(rc, 1); // Expect success as we're very liberal +} + +TEST_F(ConnectionParsing, ResponseSplitChunk) { + int rc = test_run(home, "71-response-split-chunk.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, ResponseBody) { + int rc = test_run(home, "72-response-split-body.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, ResponseContainsTeAndCl) { + int rc = test_run(home, "73-response-te-and-cl.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_SMUGGLING); +} + +TEST_F(ConnectionParsing, ResponseMultipleCl) { + int rc = test_run(home, "74-response-multiple-cl.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_SMUGGLING); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, "Content-Length"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + ASSERT_TRUE(h->flags & HTP_FIELD_REPEATED); + + ASSERT_EQ(0, bstr_cmp_c(h->value, "12")); +} + +TEST_F(ConnectionParsing, ResponseMultipleClMismatch) { + int rc = test_run(home, "88-response-multiple-cl-mismatch.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_TRUE(tx->flags & HTP_REQUEST_SMUGGLING); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, "Content-Length"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + ASSERT_TRUE(h->flags & HTP_FIELD_REPEATED); + + ASSERT_EQ(0, bstr_cmp_c(h->value, "12")); + + ASSERT_EQ(2, htp_list_size(tx->conn->messages)); + htp_log_t *log = (htp_log_t *) htp_list_get(tx->conn->messages, 1); + ASSERT_TRUE(log != NULL); + ASSERT_EQ(0, strcmp(log->msg, "Ambiguous response C-L value")); + ASSERT_EQ(HTP_LOG_WARNING, log->level); +} + +TEST_F(ConnectionParsing, ResponseInvalidCl) { + int rc = test_run(home, "75-response-invalid-cl.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + ASSERT_FALSE(tx->flags & HTP_REQUEST_SMUGGLING); +} + +TEST_F(ConnectionParsing, ResponseNoBody) { + int rc = test_run(home, "76-response-no-body.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx1->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx1->response_progress); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx1->response_headers, "Server"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + + ASSERT_EQ(0, bstr_cmp_c(h->value, "Apache")); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx2->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx2->response_progress); + + ASSERT_TRUE(tx1 != tx2); +} + +TEST_F(ConnectionParsing, ResponseFoldedHeaders) { + int rc = test_run(home, "77-response-folded-headers.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx1 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx1 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx1->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx1->response_progress); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx1->response_headers, "Server"); + ASSERT_TRUE(h != NULL); + ASSERT_TRUE(h->value != NULL); + + ASSERT_EQ(0, bstr_cmp_c(h->value, "Apache Server")); + + htp_tx_t *tx2 = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx2 != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx2->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx2->response_progress); +} + +TEST_F(ConnectionParsing, ResponseNoStatusHeaders) { + int rc = test_run(home, "78-response-no-status-headers.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, ConnectInvalidHostport) { + int rc = test_run(home, "79-connect-invalid-hostport.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); +} + +TEST_F(ConnectionParsing, HostnameInvalid1) { + int rc = test_run(home, "80-hostname-invalid-1.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); +} + +TEST_F(ConnectionParsing, HostnameInvalid2) { + int rc = test_run(home, "81-hostname-invalid-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); +} + +TEST_F(ConnectionParsing, Put) { + int rc = test_run(home, "82-put.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_hostname, "www.example.com")); +} + +TEST_F(ConnectionParsing, AuthDigestInvalidUsername2) { + int rc = test_run(home, "83-auth-digest-invalid-username-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_EQ(HTP_AUTH_DIGEST, tx->request_auth_type); + + ASSERT_TRUE(tx->request_auth_username == NULL); + + ASSERT_TRUE(tx->request_auth_password == NULL); + + ASSERT_TRUE(tx->flags & HTP_AUTH_INVALID); +} + +TEST_F(ConnectionParsing, ResponseNoStatusHeaders2) { + int rc = test_run(home, "84-response-no-status-headers-2.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +/* +TEST_F(ConnectionParsing, ZeroByteRequestTimeout) { + int rc = test_run(home, "85-zero-byte-request-timeout.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_NOT_STARTED, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} +*/ + +TEST_F(ConnectionParsing, PartialRequestTimeout) { + int rc = test_run(home, "86-partial-request-timeout.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, IncorrectHostAmbiguousWarning) { + int rc = test_run(home, "87-issue-55-incorrect-host-ambiguous-warning.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(tx->parsed_uri_raw != NULL); + + ASSERT_TRUE(tx->parsed_uri_raw->port != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri_raw->port, "443")); + + ASSERT_TRUE(tx->parsed_uri_raw->hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri_raw->hostname, "www.example.com")); + + ASSERT_EQ(443, tx->parsed_uri_raw->port_number); + + ASSERT_TRUE(tx->request_hostname != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_hostname, "www.example.com")); + + ASSERT_FALSE(tx->flags & HTP_HOST_AMBIGUOUS); +} + +TEST_F(ConnectionParsing, GetWhitespace) { + int rc = test_run(home, "89-get-whitespace.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, " GET")); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/?p=%20")); + + ASSERT_TRUE(tx->parsed_uri != NULL); + + ASSERT_TRUE(tx->parsed_uri->query != NULL); + + ASSERT_EQ(0, bstr_cmp_c(tx->parsed_uri->query, "p=%20")); + + htp_param_t *p = htp_tx_req_get_param(tx, "p", 1); + ASSERT_TRUE(p != NULL); + + ASSERT_EQ(0, bstr_cmp_c(p->value, " ")); +} + +TEST_F(ConnectionParsing, RequestUriTooLarge) { + int rc = test_run(home, "90-request-uri-too-large.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, RequestInvalid) { + int rc = test_run(home, "91-request-unexpected-body.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "POST")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_NOT_STARTED, tx->response_progress); +} + +TEST_F(ConnectionParsing, Http_0_9_MethodOnly) { + int rc = test_run(home, "92-http_0_9-method_only.t", cfg, &connp); + ASSERT_GE(rc, 0); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + ASSERT_TRUE(tx->request_method != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + + ASSERT_EQ(0, bstr_cmp_c(tx->request_uri, "/")); + + ASSERT_EQ(1, tx->is_protocol_0_9); +} + +TEST_F(ConnectionParsing, CompressedResponseDeflateAsGzip) { + int rc = test_run(home, "93-compressed-response-deflateasgzip.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(755, tx->response_message_len); + + ASSERT_EQ(1433, tx->response_entity_len); +} + +TEST_F(ConnectionParsing, CompressedResponseMultiple) { + int rc = test_run(home, "94-compressed-response-multiple.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(51, tx->response_message_len); + + ASSERT_EQ(25, tx->response_entity_len); +} + +TEST_F(ConnectionParsing, CompressedResponseGzipAsDeflate) { + int rc = test_run(home, "95-compressed-response-gzipasdeflate.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(187, tx->response_message_len); + + ASSERT_EQ(225, tx->response_entity_len); +} + +#ifdef HAVE_LIBLZMA +TEST_F(ConnectionParsing, CompressedResponseLzma) { + int rc = test_run(home, "96-compressed-response-lzma.t", cfg, &connp); + + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + + ASSERT_TRUE(htp_tx_is_complete(tx)); + + ASSERT_EQ(90, tx->response_message_len); + + ASSERT_EQ(68, tx->response_entity_len); +} +#endif + +TEST_F(ConnectionParsing, RequestsCut) { + int rc = test_run(home, "97-requests-cut.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + + tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); +} + +TEST_F(ConnectionParsing, ResponsesCut) { + int rc = test_run(home, "98-responses-cut.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(200, tx->response_status_number); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(200, tx->response_status_number); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +TEST_F(ConnectionParsing, Expect100) { + int rc = test_run(home, "99-expect-100.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "PUT")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(401, tx->response_status_number); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "POST")); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(200, tx->response_status_number); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); +} + +// emplace_back needs at least C++ 11 +#if __cplusplus > 199711L +struct ResponseBodyDataCallback { + std::vector<std::string> data; +}; + +static int callback_RESPONSE_BODY_DATA(htp_tx_data_t *d) { + struct ResponseBodyDataCallback *user_data = (struct ResponseBodyDataCallback *) htp_tx_get_user_data(d->tx); + + if (!user_data) { + user_data = new ResponseBodyDataCallback(); + htp_tx_set_user_data(d->tx, user_data); + } + + if(d->data) user_data->data.emplace_back(std::string(reinterpret_cast<const char *>(d->data), d->len)); + + return HTP_OK; +} + +TEST_F(ConnectionParsing, ResponseBodyData) { + htp_config_register_response_body_data(cfg, callback_RESPONSE_BODY_DATA); + + int rc = test_run(home, "100-response-body-data.t", cfg, &connp); + ASSERT_GE(rc, 0); + + ASSERT_EQ(1, htp_list_size(connp->conn->transactions)); + htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); + ASSERT_TRUE(tx != NULL); + ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); + ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); + + struct ResponseBodyDataCallback *user_data = (struct ResponseBodyDataCallback *) htp_tx_get_user_data(tx); + ASSERT_TRUE(user_data); + + ASSERT_EQ(3, user_data->data.size()); + EXPECT_EQ("1\n", user_data->data[0]); + EXPECT_EQ("23\n", user_data->data[1]); + EXPECT_EQ("4", user_data->data[2]); + + delete user_data; +} +#endif |