Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / http / http_chunked_decoder_unittest.cc
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_chunked_decoder.h"
6
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "net/base/net_errors.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace net {
13
14 namespace {
15
16 typedef testing::Test HttpChunkedDecoderTest;
17
18 void RunTest(const char* inputs[], size_t num_inputs,
19              const char* expected_output,
20              bool expected_eof,
21              int bytes_after_eof) {
22   HttpChunkedDecoder decoder;
23   EXPECT_FALSE(decoder.reached_eof());
24
25   std::string result;
26
27   for (size_t i = 0; i < num_inputs; ++i) {
28     std::string input = inputs[i];
29     int n = decoder.FilterBuf(&input[0], static_cast<int>(input.size()));
30     EXPECT_GE(n, 0);
31     if (n > 0)
32       result.append(input.data(), n);
33   }
34
35   EXPECT_EQ(expected_output, result);
36   EXPECT_EQ(expected_eof, decoder.reached_eof());
37   EXPECT_EQ(bytes_after_eof, decoder.bytes_after_eof());
38 }
39
40 // Feed the inputs to the decoder, until it returns an error.
41 void RunTestUntilFailure(const char* inputs[],
42                          size_t num_inputs,
43                          size_t fail_index) {
44   HttpChunkedDecoder decoder;
45   EXPECT_FALSE(decoder.reached_eof());
46
47   for (size_t i = 0; i < num_inputs; ++i) {
48     std::string input = inputs[i];
49     int n = decoder.FilterBuf(&input[0], static_cast<int>(input.size()));
50     if (n < 0) {
51       EXPECT_EQ(ERR_INVALID_CHUNKED_ENCODING, n);
52       EXPECT_EQ(fail_index, i);
53       return;
54     }
55   }
56   FAIL();  // We should have failed on the |fail_index| iteration of the loop.
57 }
58
59 TEST(HttpChunkedDecoderTest, Basic) {
60   const char* inputs[] = {
61     "B\r\nhello hello\r\n0\r\n\r\n"
62   };
63   RunTest(inputs, arraysize(inputs), "hello hello", true, 0);
64 }
65
66 TEST(HttpChunkedDecoderTest, OneChunk) {
67   const char* inputs[] = {
68     "5\r\nhello\r\n"
69   };
70   RunTest(inputs, arraysize(inputs), "hello", false, 0);
71 }
72
73 TEST(HttpChunkedDecoderTest, Typical) {
74   const char* inputs[] = {
75     "5\r\nhello\r\n",
76     "1\r\n \r\n",
77     "5\r\nworld\r\n",
78     "0\r\n\r\n"
79   };
80   RunTest(inputs, arraysize(inputs), "hello world", true, 0);
81 }
82
83 TEST(HttpChunkedDecoderTest, Incremental) {
84   const char* inputs[] = {
85     "5",
86     "\r",
87     "\n",
88     "hello",
89     "\r",
90     "\n",
91     "0",
92     "\r",
93     "\n",
94     "\r",
95     "\n"
96   };
97   RunTest(inputs, arraysize(inputs), "hello", true, 0);
98 }
99
100 // Same as above, but group carriage returns with previous input.
101 TEST(HttpChunkedDecoderTest, Incremental2) {
102   const char* inputs[] = {
103     "5\r",
104     "\n",
105     "hello\r",
106     "\n",
107     "0\r",
108     "\n\r",
109     "\n"
110   };
111   RunTest(inputs, arraysize(inputs), "hello", true, 0);
112 }
113
114 TEST(HttpChunkedDecoderTest, LF_InsteadOf_CRLF) {
115   // Compatibility: [RFC 2616 - Invalid]
116   // {Firefox3} - Valid
117   // {IE7, Safari3.1, Opera9.51} - Invalid
118   const char* inputs[] = {
119     "5\nhello\n",
120     "1\n \n",
121     "5\nworld\n",
122     "0\n\n"
123   };
124   RunTest(inputs, arraysize(inputs), "hello world", true, 0);
125 }
126
127 TEST(HttpChunkedDecoderTest, Extensions) {
128   const char* inputs[] = {
129     "5;x=0\r\nhello\r\n",
130     "0;y=\"2 \"\r\n\r\n"
131   };
132   RunTest(inputs, arraysize(inputs), "hello", true, 0);
133 }
134
135 TEST(HttpChunkedDecoderTest, Trailers) {
136   const char* inputs[] = {
137     "5\r\nhello\r\n",
138     "0\r\n",
139     "Foo: 1\r\n",
140     "Bar: 2\r\n",
141     "\r\n"
142   };
143   RunTest(inputs, arraysize(inputs), "hello", true, 0);
144 }
145
146 TEST(HttpChunkedDecoderTest, TrailersUnfinished) {
147   const char* inputs[] = {
148     "5\r\nhello\r\n",
149     "0\r\n",
150     "Foo: 1\r\n"
151   };
152   RunTest(inputs, arraysize(inputs), "hello", false, 0);
153 }
154
155 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TooBig) {
156   const char* inputs[] = {
157     // This chunked body is not terminated.
158     // However we will fail decoding because the chunk-size
159     // number is larger than we can handle.
160     "48469410265455838241\r\nhello\r\n",
161     "0\r\n\r\n"
162   };
163   RunTestUntilFailure(inputs, arraysize(inputs), 0);
164 }
165
166 TEST(HttpChunkedDecoderTest, InvalidChunkSize_0X) {
167   const char* inputs[] = {
168     // Compatibility [RFC 2616 - Invalid]:
169     // {Safari3.1, IE7} - Invalid
170     // {Firefox3, Opera 9.51} - Valid
171     "0x5\r\nhello\r\n",
172     "0\r\n\r\n"
173   };
174   RunTestUntilFailure(inputs, arraysize(inputs), 0);
175 }
176
177 TEST(HttpChunkedDecoderTest, ChunkSize_TrailingSpace) {
178   const char* inputs[] = {
179     // Compatibility [RFC 2616 - Invalid]:
180     // {IE7, Safari3.1, Firefox3, Opera 9.51} - Valid
181     //
182     // At least yahoo.com depends on this being valid.
183     "5      \r\nhello\r\n",
184     "0\r\n\r\n"
185   };
186   RunTest(inputs, arraysize(inputs), "hello", true, 0);
187 }
188
189 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingTab) {
190   const char* inputs[] = {
191     // Compatibility [RFC 2616 - Invalid]:
192     // {IE7, Safari3.1, Firefox3, Opera 9.51} - Valid
193     "5\t\r\nhello\r\n",
194     "0\r\n\r\n"
195   };
196   RunTestUntilFailure(inputs, arraysize(inputs), 0);
197 }
198
199 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingFormFeed) {
200   const char* inputs[] = {
201     // Compatibility [RFC 2616- Invalid]:
202     // {Safari3.1} - Invalid
203     // {IE7, Firefox3, Opera 9.51} - Valid
204     "5\f\r\nhello\r\n",
205     "0\r\n\r\n"
206   };
207   RunTestUntilFailure(inputs, arraysize(inputs), 0);
208 }
209
210 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingVerticalTab) {
211   const char* inputs[] = {
212     // Compatibility [RFC 2616 - Invalid]:
213     // {Safari 3.1} - Invalid
214     // {IE7, Firefox3, Opera 9.51} - Valid
215     "5\v\r\nhello\r\n",
216     "0\r\n\r\n"
217   };
218   RunTestUntilFailure(inputs, arraysize(inputs), 0);
219 }
220
221 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingNonHexDigit) {
222   const char* inputs[] = {
223     // Compatibility [RFC 2616 - Invalid]:
224     // {Safari 3.1} - Invalid
225     // {IE7, Firefox3, Opera 9.51} - Valid
226     "5H\r\nhello\r\n",
227     "0\r\n\r\n"
228   };
229   RunTestUntilFailure(inputs, arraysize(inputs), 0);
230 }
231
232 TEST(HttpChunkedDecoderTest, InvalidChunkSize_LeadingSpace) {
233   const char* inputs[] = {
234     // Compatibility [RFC 2616 - Invalid]:
235     // {IE7} - Invalid
236     // {Safari 3.1, Firefox3, Opera 9.51} - Valid
237     " 5\r\nhello\r\n",
238     "0\r\n\r\n"
239   };
240   RunTestUntilFailure(inputs, arraysize(inputs), 0);
241 }
242
243 TEST(HttpChunkedDecoderTest, InvalidLeadingSeparator) {
244   const char* inputs[] = {
245     "\r\n5\r\nhello\r\n",
246     "0\r\n\r\n"
247   };
248   RunTestUntilFailure(inputs, arraysize(inputs), 0);
249 }
250
251 TEST(HttpChunkedDecoderTest, InvalidChunkSize_NoSeparator) {
252   const char* inputs[] = {
253     "5\r\nhello",
254     "1\r\n \r\n",
255     "0\r\n\r\n"
256   };
257   RunTestUntilFailure(inputs, arraysize(inputs), 1);
258 }
259
260 TEST(HttpChunkedDecoderTest, InvalidChunkSize_Negative) {
261   const char* inputs[] = {
262     "8\r\n12345678\r\n-5\r\nhello\r\n",
263     "0\r\n\r\n"
264   };
265   RunTestUntilFailure(inputs, arraysize(inputs), 0);
266 }
267
268 TEST(HttpChunkedDecoderTest, InvalidChunkSize_Plus) {
269   const char* inputs[] = {
270     // Compatibility [RFC 2616 - Invalid]:
271     // {IE7, Safari 3.1} - Invalid
272     // {Firefox3, Opera 9.51} - Valid
273     "+5\r\nhello\r\n",
274     "0\r\n\r\n"
275   };
276   RunTestUntilFailure(inputs, arraysize(inputs), 0);
277 }
278
279 TEST(HttpChunkedDecoderTest, InvalidConsecutiveCRLFs) {
280   const char* inputs[] = {
281     "5\r\nhello\r\n",
282     "\r\n\r\n\r\n\r\n",
283     "0\r\n\r\n"
284   };
285   RunTestUntilFailure(inputs, arraysize(inputs), 1);
286 }
287
288 TEST(HttpChunkedDecoderTest, ExcessiveChunkLen) {
289   const char* inputs[] = {
290     "c0000000\r\nhello\r\n"
291   };
292   RunTestUntilFailure(inputs, arraysize(inputs), 0);
293 }
294
295 TEST(HttpChunkedDecoderTest, BasicExtraData) {
296   const char* inputs[] = {
297     "5\r\nhello\r\n0\r\n\r\nextra bytes"
298   };
299   RunTest(inputs, arraysize(inputs), "hello", true, 11);
300 }
301
302 TEST(HttpChunkedDecoderTest, IncrementalExtraData) {
303   const char* inputs[] = {
304     "5",
305     "\r",
306     "\n",
307     "hello",
308     "\r",
309     "\n",
310     "0",
311     "\r",
312     "\n",
313     "\r",
314     "\nextra bytes"
315   };
316   RunTest(inputs, arraysize(inputs), "hello", true, 11);
317 }
318
319 TEST(HttpChunkedDecoderTest, MultipleExtraDataBlocks) {
320   const char* inputs[] = {
321     "5\r\nhello\r\n0\r\n\r\nextra",
322     " bytes"
323   };
324   RunTest(inputs, arraysize(inputs), "hello", true, 11);
325 }
326
327 // Test when the line with the chunk length is too long.
328 TEST(HttpChunkedDecoderTest, LongChunkLengthLine) {
329   int big_chunk_length = HttpChunkedDecoder::kMaxLineBufLen;
330   scoped_ptr<char[]> big_chunk(new char[big_chunk_length + 1]);
331   memset(big_chunk.get(), '0', big_chunk_length);
332   big_chunk[big_chunk_length] = 0;
333   const char* inputs[] = {
334     big_chunk.get(),
335     "5"
336   };
337   RunTestUntilFailure(inputs, arraysize(inputs), 1);
338 }
339
340 // Test when the extension portion of the line with the chunk length is too
341 // long.
342 TEST(HttpChunkedDecoderTest, LongLengthLengthLine) {
343   int big_chunk_length = HttpChunkedDecoder::kMaxLineBufLen;
344   scoped_ptr<char[]> big_chunk(new char[big_chunk_length + 1]);
345   memset(big_chunk.get(), '0', big_chunk_length);
346   big_chunk[big_chunk_length] = 0;
347   const char* inputs[] = {
348     "5;",
349     big_chunk.get()
350   };
351   RunTestUntilFailure(inputs, arraysize(inputs), 1);
352 }
353
354 }  // namespace
355
356 }  // namespace net