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 };