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 :
|