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