1 #include "HttpHeaderProcessor.h"
2
3 #include <iostream>
4
5 #include <cppunit/extensions/HelperMacros.h>
6
7 #include "HttpHeader.h"
8 #include "DlRetryEx.h"
9 #include "DlAbortEx.h"
10
11 namespace aria2 {
12
13 class HttpHeaderProcessorTest : public CppUnit::TestFixture {
14
15 CPPUNIT_TEST_SUITE(HttpHeaderProcessorTest);
16 CPPUNIT_TEST(testParse1);
17 CPPUNIT_TEST(testParse2);
18 CPPUNIT_TEST(testParse3);
19 CPPUNIT_TEST(testGetLastBytesProcessed);
20 CPPUNIT_TEST(testGetLastBytesProcessed_nullChar);
21 CPPUNIT_TEST(testGetHttpResponseHeader);
22 CPPUNIT_TEST(testGetHttpResponseHeader_statusOnly);
23 CPPUNIT_TEST(testGetHttpResponseHeader_insufficientStatusLength);
24 CPPUNIT_TEST(testGetHttpResponseHeader_nameStartsWs);
25 CPPUNIT_TEST(testGetHttpResponseHeader_teAndCl);
26 CPPUNIT_TEST(testBeyondLimit);
27 CPPUNIT_TEST(testGetHeaderString);
28 CPPUNIT_TEST(testGetHttpRequestHeader);
29 CPPUNIT_TEST_SUITE_END();
30
31 public:
32 void testParse1();
33 void testParse2();
34 void testParse3();
35 void testGetLastBytesProcessed();
36 void testGetLastBytesProcessed_nullChar();
37 void testGetHttpResponseHeader();
38 void testGetHttpResponseHeader_statusOnly();
39 void testGetHttpResponseHeader_insufficientStatusLength();
40 void testGetHttpResponseHeader_nameStartsWs();
41 void testGetHttpResponseHeader_teAndCl();
42 void testBeyondLimit();
43 void testGetHeaderString();
44 void testGetHttpRequestHeader();
45 };
46
47 CPPUNIT_TEST_SUITE_REGISTRATION(HttpHeaderProcessorTest);
48
testParse1()49 void HttpHeaderProcessorTest::testParse1()
50 {
51 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
52 std::string hd1 = "HTTP/1.1 200 OK\r\n";
53 CPPUNIT_ASSERT(!proc.parse(hd1));
54 CPPUNIT_ASSERT(proc.parse("\r\n"));
55 }
56
testParse2()57 void HttpHeaderProcessorTest::testParse2()
58 {
59 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
60 std::string hd1 = "HTTP/1.1 200 OK\n";
61 CPPUNIT_ASSERT(!proc.parse(hd1));
62 CPPUNIT_ASSERT(proc.parse("\n"));
63 }
64
testParse3()65 void HttpHeaderProcessorTest::testParse3()
66 {
67 HttpHeaderProcessor proc(HttpHeaderProcessor::SERVER_PARSER);
68 std::string s = "GET / HTTP/1.1\r\n"
69 "Host: aria2.sourceforge.net\r\n"
70 "Connection: close \r\n" // trailing white space (BWS)
71 "Accept-Encoding: text1\r\n" // Multi-line header
72 " text2\r\n"
73 " text3\r\n"
74 "Authorization: foo\r\n"
75 "Authorization: bar\r\n"
76 "Content-Type:\r\n"
77 "\r\n";
78 CPPUNIT_ASSERT(proc.parse(s));
79 auto h = proc.getResult();
80 CPPUNIT_ASSERT_EQUAL(std::string("close"), h->find(HttpHeader::CONNECTION));
81 CPPUNIT_ASSERT_EQUAL(std::string("text1 text2 text3"),
82 h->find(HttpHeader::ACCEPT_ENCODING));
83 CPPUNIT_ASSERT_EQUAL(std::string("foo"),
84 h->findAll(HttpHeader::AUTHORIZATION)[0]);
85 CPPUNIT_ASSERT_EQUAL(std::string("bar"),
86 h->findAll(HttpHeader::AUTHORIZATION)[1]);
87 CPPUNIT_ASSERT_EQUAL(std::string(""), h->find(HttpHeader::CONTENT_TYPE));
88 CPPUNIT_ASSERT(h->defined(HttpHeader::CONTENT_TYPE));
89 }
90
testGetLastBytesProcessed()91 void HttpHeaderProcessorTest::testGetLastBytesProcessed()
92 {
93 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
94 std::string hd1 = "HTTP/1.1 200 OK\r\n"
95 "\r\nputbackme";
96 CPPUNIT_ASSERT(proc.parse(hd1));
97 CPPUNIT_ASSERT_EQUAL((size_t)19, proc.getLastBytesProcessed());
98
99 proc.clear();
100
101 std::string hd2 = "HTTP/1.1 200 OK\n"
102 "\nputbackme";
103 CPPUNIT_ASSERT(proc.parse(hd2));
104 CPPUNIT_ASSERT_EQUAL((size_t)17, proc.getLastBytesProcessed());
105 }
106
testGetLastBytesProcessed_nullChar()107 void HttpHeaderProcessorTest::testGetLastBytesProcessed_nullChar()
108 {
109 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
110 const char x[] = "HTTP/1.1 200 OK\r\n"
111 "foo: foo\0bar\r\n"
112 "\r\nputbackme";
113 std::string hd1(&x[0], &x[sizeof(x) - 1]);
114 CPPUNIT_ASSERT(proc.parse(hd1));
115 CPPUNIT_ASSERT_EQUAL((size_t)33, proc.getLastBytesProcessed());
116 }
117
testGetHttpResponseHeader()118 void HttpHeaderProcessorTest::testGetHttpResponseHeader()
119 {
120 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
121 std::string hd = "HTTP/1.1 404 Not Found\r\n"
122 "Date: Mon, 25 Jun 2007 16:04:59 GMT\r\n"
123 "Server: Apache/2.2.3 (Debian)\r\n"
124 "Last-Modified: Tue, 12 Jun 2007 14:28:43 GMT\r\n"
125 "ETag: \"594065-23e3-50825cc0\"\r\n"
126 "Accept-Ranges: bytes\r\n"
127 "Content-Length: 9187\r\n"
128 "Connection: close\r\n"
129 "Content-Type: text/html; charset=UTF-8\r\n"
130 "\r\n"
131 "Content-Encoding: body";
132
133 CPPUNIT_ASSERT(proc.parse(hd));
134
135 auto header = proc.getResult();
136 CPPUNIT_ASSERT_EQUAL(404, header->getStatusCode());
137 CPPUNIT_ASSERT_EQUAL(std::string("Not Found"), header->getReasonPhrase());
138 CPPUNIT_ASSERT_EQUAL(std::string("HTTP/1.1"), header->getVersion());
139 CPPUNIT_ASSERT_EQUAL(std::string("9187"),
140 header->find(HttpHeader::CONTENT_LENGTH));
141 CPPUNIT_ASSERT_EQUAL(std::string("text/html; charset=UTF-8"),
142 header->find(HttpHeader::CONTENT_TYPE));
143 CPPUNIT_ASSERT(!header->defined(HttpHeader::CONTENT_ENCODING));
144 }
145
testGetHttpResponseHeader_statusOnly()146 void HttpHeaderProcessorTest::testGetHttpResponseHeader_statusOnly()
147 {
148 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
149
150 std::string hd = "HTTP/1.1 200\r\n\r\n";
151 CPPUNIT_ASSERT(proc.parse(hd));
152 auto header = proc.getResult();
153 CPPUNIT_ASSERT_EQUAL(200, header->getStatusCode());
154 }
155
156 void HttpHeaderProcessorTest::
testGetHttpResponseHeader_insufficientStatusLength()157 testGetHttpResponseHeader_insufficientStatusLength()
158 {
159 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
160
161 std::string hd = "HTTP/1.1 20\r\n\r\n";
162 try {
163 proc.parse(hd);
164 CPPUNIT_FAIL("Exception must be thrown.");
165 }
166 catch (DlAbortEx& ex) {
167 // Success
168 }
169 }
170
testGetHttpResponseHeader_nameStartsWs()171 void HttpHeaderProcessorTest::testGetHttpResponseHeader_nameStartsWs()
172 {
173 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
174
175 std::string hd = "HTTP/1.1 200\r\n"
176 " foo:bar\r\n"
177 "\r\n";
178 try {
179 proc.parse(hd);
180 CPPUNIT_FAIL("Exception must be thrown.");
181 }
182 catch (DlAbortEx& ex) {
183 // Success
184 }
185
186 proc.clear();
187 hd = "HTTP/1.1 200\r\n"
188 ":foo:bar\r\n"
189 "\r\n";
190 try {
191 proc.parse(hd);
192 CPPUNIT_FAIL("Exception must be thrown.");
193 }
194 catch (DlAbortEx& ex) {
195 // Success
196 }
197
198 proc.clear();
199 hd = "HTTP/1.1 200\r\n"
200 ":foo\r\n"
201 "\r\n";
202 try {
203 proc.parse(hd);
204 CPPUNIT_FAIL("Exception must be thrown.");
205 }
206 catch (DlAbortEx& ex) {
207 // Success
208 }
209 }
210
testGetHttpResponseHeader_teAndCl()211 void HttpHeaderProcessorTest::testGetHttpResponseHeader_teAndCl()
212 {
213 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
214
215 std::string hd = "HTTP/1.1 200\r\n"
216 "Content-Length: 200\r\n"
217 "Transfer-Encoding: chunked\r\n"
218 "Content-Range: 1-200/300\r\n"
219 "\r\n";
220
221 CPPUNIT_ASSERT(proc.parse(hd));
222
223 auto httpHeader = proc.getResult();
224 CPPUNIT_ASSERT_EQUAL(std::string("chunked"),
225 httpHeader->find(HttpHeader::TRANSFER_ENCODING));
226 CPPUNIT_ASSERT(!httpHeader->defined(HttpHeader::CONTENT_LENGTH));
227 CPPUNIT_ASSERT(!httpHeader->defined(HttpHeader::CONTENT_RANGE));
228 }
229
testBeyondLimit()230 void HttpHeaderProcessorTest::testBeyondLimit()
231 {
232 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
233
234 std::string hd1 = "HTTP/1.1 200 OK\r\n";
235 std::string hd2 = std::string(1025, 'A');
236
237 proc.parse(hd1);
238 try {
239 proc.parse(hd2);
240 CPPUNIT_FAIL("Exception must be thrown.");
241 }
242 catch (DlAbortEx& ex) {
243 // Success
244 }
245 }
246
testGetHeaderString()247 void HttpHeaderProcessorTest::testGetHeaderString()
248 {
249 HttpHeaderProcessor proc(HttpHeaderProcessor::CLIENT_PARSER);
250 std::string hd = "HTTP/1.1 200 OK\r\n"
251 "Date: Mon, 25 Jun 2007 16:04:59 GMT\r\n"
252 "Server: Apache/2.2.3 (Debian)\r\n"
253 "Last-Modified: Tue, 12 Jun 2007 14:28:43 GMT\r\n"
254 "ETag: \"594065-23e3-50825cc0\"\r\n"
255 "Accept-Ranges: bytes\r\n"
256 "Content-Length: 9187\r\n"
257 "Connection: close\r\n"
258 "Content-Type: text/html; charset=UTF-8\r\n"
259 "\r\nputbackme";
260
261 CPPUNIT_ASSERT(proc.parse(hd));
262
263 CPPUNIT_ASSERT_EQUAL(
264 std::string("HTTP/1.1 200 OK\r\n"
265 "Date: Mon, 25 Jun 2007 16:04:59 GMT\r\n"
266 "Server: Apache/2.2.3 (Debian)\r\n"
267 "Last-Modified: Tue, 12 Jun 2007 14:28:43 GMT\r\n"
268 "ETag: \"594065-23e3-50825cc0\"\r\n"
269 "Accept-Ranges: bytes\r\n"
270 "Content-Length: 9187\r\n"
271 "Connection: close\r\n"
272 "Content-Type: text/html; charset=UTF-8\r\n"
273 "\r\n"),
274 proc.getHeaderString());
275 }
276
testGetHttpRequestHeader()277 void HttpHeaderProcessorTest::testGetHttpRequestHeader()
278 {
279 HttpHeaderProcessor proc(HttpHeaderProcessor::SERVER_PARSER);
280 std::string request = "GET /index.html HTTP/1.1\r\n"
281 "Host: host\r\n"
282 "Connection: close\r\n"
283 "\r\n"
284 "Content-Encoding: body";
285
286 CPPUNIT_ASSERT(proc.parse(request));
287
288 auto httpHeader = proc.getResult();
289 CPPUNIT_ASSERT_EQUAL(std::string("GET"), httpHeader->getMethod());
290 CPPUNIT_ASSERT_EQUAL(std::string("/index.html"),
291 httpHeader->getRequestPath());
292 CPPUNIT_ASSERT_EQUAL(std::string("HTTP/1.1"), httpHeader->getVersion());
293 CPPUNIT_ASSERT_EQUAL(std::string("close"),
294 httpHeader->find(HttpHeader::CONNECTION));
295 CPPUNIT_ASSERT(!httpHeader->defined(HttpHeader::CONTENT_ENCODING));
296 }
297
298 } // namespace aria2
299