summaryrefslogtreecommitdiffstats
path: root/test/test_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/test_main.cpp2148
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