LCOV - code coverage report
Current view: top level - test - test_proto_http.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 72 72 100.0 %
Date: 2021-11-24 03:28:48 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /**
       5             :  * \file test_proto_http.c
       6             :  * \brief Tests for our HTTP protocol parser code
       7             :  */
       8             : 
       9             : #include "core/or/or.h"
      10             : #include "test/test.h"
      11             : #include "lib/buf/buffers.h"
      12             : #include "core/proto/proto_http.h"
      13             : #include "test/log_test_helpers.h"
      14             : 
      15             : #define S(str) str, sizeof(str)-1
      16             : 
      17             : static void
      18           1 : test_proto_http_peek(void *arg)
      19             : {
      20           1 :   (void) arg;
      21           1 :   const struct {
      22             :     int is_http;
      23             :     const char *message;
      24             :     size_t len;
      25           1 :   } cases[] = {
      26             :     { 1, S("GET /index HTTP/1.0\r\n") },
      27             :     { 1, S("GET /index HTTP/1.1\r\n") },
      28             :     { 1, S("GET ") },
      29             :     { 0, S("GIT ") },
      30             :     { 0, S("GET") },
      31             :     { 0, S("get ") },
      32             :     { 0, S("GETAWAY") },
      33             :   };
      34           1 :   unsigned i;
      35           1 :   buf_t *buf = buf_new();
      36           9 :   for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
      37           7 :     TT_BLATHER(("Trying case %u", i));
      38           7 :     buf_add(buf, cases[i].message, cases[i].len);
      39           7 :     tt_int_op(cases[i].is_http, OP_EQ, peek_buf_has_http_command(buf));
      40           7 :     buf_clear(buf);
      41             :   }
      42           1 :  done:
      43           1 :   buf_free(buf);
      44           1 : }
      45             : 
      46             : static void
      47           1 : test_proto_http_valid(void *arg)
      48             : {
      49           1 :   (void) arg;
      50           1 :   const struct {
      51             :     const char *message;
      52             :     size_t len;
      53             :     const char *headers;
      54             :     const char *body;
      55             :     size_t bodylen;
      56             :     int should_detect_truncated;
      57             :     int bytes_left_over;
      58           1 :   } cases[] = {
      59             :     { S("GET /index.html HTTP/1.0\r\n\r\n"),
      60             :       "GET /index.html HTTP/1.0\r\n\r\n",
      61             :       S(""),
      62             :       1, 0,
      63             :     },
      64             :     { S("PUT /tor/foo HTTP/1.1\r\n"
      65             :         "Content-Length: 51\r\n\r\n"
      66             :         "this is a test of the http parsing system . test te"),
      67             :       "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 51\r\n\r\n",
      68             :       S("this is a test of the http parsing system . test te"),
      69             :       1, 0,
      70             :     },
      71             :     { S("PUT /tor/foo HTTP/1.1\r\n"
      72             :         "Content-Length: 5\r\n\r\n"
      73             :         "there are more than 5 characters in this body."),
      74             :       "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 5\r\n\r\n",
      75             :       S("there"),
      76             :       0, 41,
      77             :     },
      78             :     { S("PUT /tor/bar HTTP/1.1\r\n\r\n"
      79             :         "this is another \x00test"),
      80             :       "PUT /tor/bar HTTP/1.1\r\n\r\n",
      81             :       S("this is another \x00test"),
      82             :       0, 0,
      83             :     }
      84             :   };
      85           1 :   unsigned i;
      86           1 :   buf_t *buf = buf_new();
      87           1 :   char *h = NULL, *b = NULL;
      88             : 
      89           5 :   for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
      90           4 :     TT_BLATHER(("Trying case %u", i));
      91           4 :     size_t bl = 0;
      92             :     // truncate by 2 chars
      93           4 :     buf_add(buf, cases[i].message, cases[i].len - 2);
      94             : 
      95           4 :     if (cases[i].should_detect_truncated) {
      96           2 :       tt_int_op(0, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
      97             :                                               &b, &bl, 1024*16, 0));
      98           2 :       tt_ptr_op(h, OP_EQ, NULL);
      99           2 :       tt_ptr_op(b, OP_EQ, NULL);
     100           2 :       tt_u64_op(bl, OP_EQ, 0);
     101           2 :       tt_int_op(buf_datalen(buf), OP_EQ, cases[i].len - 2);
     102             :     }
     103             : 
     104             :     // add the rest.
     105           4 :     buf_add(buf, cases[i].message+cases[i].len-2, 2);
     106           4 :     tt_int_op(1, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
     107             :                                             &b, &bl, 1024*16, 0));
     108           4 :     tt_str_op(h, OP_EQ, cases[i].headers);
     109           4 :     tt_u64_op(bl, OP_EQ, cases[i].bodylen);
     110           4 :     tt_mem_op(b, OP_EQ, cases[i].body, bl);
     111           4 :     tt_int_op(buf_datalen(buf), OP_EQ, cases[i].bytes_left_over);
     112             : 
     113           4 :     buf_clear(buf);
     114           4 :     tor_free(h);
     115           4 :     tor_free(b);
     116             :   }
     117           1 :  done:
     118           1 :   tor_free(h);
     119           1 :   tor_free(b);
     120           1 :   buf_free(buf);
     121           1 : }
     122             : 
     123             : static void
     124           1 : test_proto_http_invalid(void *arg)
     125             : {
     126           1 :   (void) arg;
     127           1 :   const struct {
     128             :     const char *message;
     129             :     size_t len;
     130             :     const char *expect;
     131           1 :   } cases[] = {
     132             :     /* Overlong headers, headers not finished. */
     133             :     { S("GET /index.xhml HTTP/1.0\r\n"
     134             :         "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
     135             :         "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
     136             :         "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"),
     137             :       "headers too long." },
     138             :     /* Overlong finished headers. */
     139             :     { S("GET /index.xhml HTTP/1.0\r\n"
     140             :         "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
     141             :         "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
     142             :         "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"
     143             :         "\r\n"),
     144             :         "headers too long." },
     145             :     /* Exactly too long finished headers. */
     146             :     { S("GET /index.xhml HTTP/1.0\r\n"
     147             :         "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
     148             :         "X-My-headers-are-too-long: normal un\r\n\r\n"),
     149             :       "headerlen 129 larger than 127. Failing." },
     150             :     /* Body too long, with content-length */
     151             :     { S("GET /index.html HTTP/1.0\r\n"
     152             :         "Content-Length: 129\r\n\r\n"
     153             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     154             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     155             :         "xxxxxxxxxxxxxxxxxxx"),
     156             :       "bodylen 129 larger than 127" },
     157             :     /* Body too long, with content-length lying */
     158             :     { S("GET /index.html HTTP/1.0\r\n"
     159             :         "Content-Length: 99999\r\n\r\n"
     160             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     161             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     162             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
     163             :       "bodylen 138 larger than 127" },
     164             :     /* Body too long, no content-length. */
     165             :     { S("GET /index.html HTTP/1.0\r\n\r\n"
     166             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     167             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     168             :         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxz"),
     169             :       "bodylen 139 larger than 127" },
     170             :     /* Content-Length is junk. */
     171             :     { S("GET /index.html HTTP/1.0\r\n"
     172             :         "Content-Length: Cheese\r\n\r\n"
     173             :         "foo"),
     174             :       "Content-Length is bogus; maybe someone is trying to crash us." },
     175             :     };
     176           1 :   unsigned i;
     177           1 :   buf_t *buf = buf_new();
     178           1 :   char *h = NULL, *b = NULL;
     179           1 :   setup_capture_of_logs(LOG_DEBUG);
     180             : 
     181           9 :   for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
     182           7 :     TT_BLATHER(("Trying case %u", i));
     183           7 :     size_t bl = 0;
     184           7 :     buf_add(buf, cases[i].message, cases[i].len);
     185             : 
     186             :     /* Use low body limits here so we can force over-sized object warnings */
     187           7 :     tt_int_op(-1, OP_EQ, fetch_from_buf_http(buf, &h, 128,
     188             :                                              &b, &bl, 128, 0));
     189           7 :     tt_ptr_op(h, OP_EQ, NULL);
     190           7 :     tt_ptr_op(b, OP_EQ, NULL);
     191           7 :     tt_u64_op(bl, OP_EQ, 0);
     192           7 :     expect_log_msg_containing(cases[i].expect);
     193             : 
     194           7 :     buf_clear(buf);
     195           7 :     tor_free(h);
     196           7 :     tor_free(b);
     197           7 :     mock_clean_saved_logs();
     198             :   }
     199           1 :  done:
     200           1 :   tor_free(h);
     201           1 :   tor_free(b);
     202           1 :   buf_free(buf);
     203           1 :   teardown_capture_of_logs();
     204           1 : }
     205             : 
     206             : struct testcase_t proto_http_tests[] = {
     207             :   { "peek", test_proto_http_peek, 0, NULL, NULL },
     208             :   { "valid", test_proto_http_valid, 0, NULL, NULL },
     209             :   { "invalid", test_proto_http_invalid, 0, NULL, NULL },
     210             : 
     211             :   END_OF_TESTCASES
     212             : };
     213             : 

Generated by: LCOV version 1.14