tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

test_proto_http.c (7194B)


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