Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / http / http_chunked_decoder_unittest.cc
blobf3e83000180b3b3895168a6255c448ba79330cd2
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.
5 #include "net/http/http_chunked_decoder.h"
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"
12 namespace net {
14 namespace {
16 typedef testing::Test HttpChunkedDecoderTest;
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());
25 std::string result;
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);
35 EXPECT_EQ(expected_output, result);
36 EXPECT_EQ(expected_eof, decoder.reached_eof());
37 EXPECT_EQ(bytes_after_eof, decoder.bytes_after_eof());
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());
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;
56 FAIL(); // We should have failed on the |fail_index| iteration of the loop.
59 TEST(HttpChunkedDecoderTest, Basic) {
60 const char* inputs[] = {
61 "B\r\nhello hello\r\n0\r\n\r\n"
63 RunTest(inputs, arraysize(inputs), "hello hello", true, 0);
66 TEST(HttpChunkedDecoderTest, OneChunk) {
67 const char* inputs[] = {
68 "5\r\nhello\r\n"
70 RunTest(inputs, arraysize(inputs), "hello", false, 0);
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"
80 RunTest(inputs, arraysize(inputs), "hello world", true, 0);
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"
97 RunTest(inputs, arraysize(inputs), "hello", true, 0);
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"
111 RunTest(inputs, arraysize(inputs), "hello", true, 0);
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"
124 RunTest(inputs, arraysize(inputs), "hello world", true, 0);
127 TEST(HttpChunkedDecoderTest, Extensions) {
128 const char* inputs[] = {
129 "5;x=0\r\nhello\r\n",
130 "0;y=\"2 \"\r\n\r\n"
132 RunTest(inputs, arraysize(inputs), "hello", true, 0);
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"
143 RunTest(inputs, arraysize(inputs), "hello", true, 0);
146 TEST(HttpChunkedDecoderTest, TrailersUnfinished) {
147 const char* inputs[] = {
148 "5\r\nhello\r\n",
149 "0\r\n",
150 "Foo: 1\r\n"
152 RunTest(inputs, arraysize(inputs), "hello", false, 0);
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"
163 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
174 RunTestUntilFailure(inputs, arraysize(inputs), 0);
177 TEST(HttpChunkedDecoderTest, ChunkSize_TrailingSpace) {
178 const char* inputs[] = {
179 // Compatibility [RFC 2616 - Invalid]:
180 // {IE7, Safari3.1, Firefox3, Opera 9.51} - Valid
182 // At least yahoo.com depends on this being valid.
183 "5 \r\nhello\r\n",
184 "0\r\n\r\n"
186 RunTest(inputs, arraysize(inputs), "hello", true, 0);
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"
196 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
207 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
218 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
229 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
240 RunTestUntilFailure(inputs, arraysize(inputs), 0);
243 TEST(HttpChunkedDecoderTest, InvalidLeadingSeparator) {
244 const char* inputs[] = {
245 "\r\n5\r\nhello\r\n",
246 "0\r\n\r\n"
248 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
257 RunTestUntilFailure(inputs, arraysize(inputs), 1);
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"
265 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
276 RunTestUntilFailure(inputs, arraysize(inputs), 0);
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"
285 RunTestUntilFailure(inputs, arraysize(inputs), 1);
288 TEST(HttpChunkedDecoderTest, ExcessiveChunkLen) {
289 const char* inputs[] = {
290 "c0000000\r\nhello\r\n"
292 RunTestUntilFailure(inputs, arraysize(inputs), 0);
295 TEST(HttpChunkedDecoderTest, BasicExtraData) {
296 const char* inputs[] = {
297 "5\r\nhello\r\n0\r\n\r\nextra bytes"
299 RunTest(inputs, arraysize(inputs), "hello", true, 11);
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"
316 RunTest(inputs, arraysize(inputs), "hello", true, 11);
319 TEST(HttpChunkedDecoderTest, MultipleExtraDataBlocks) {
320 const char* inputs[] = {
321 "5\r\nhello\r\n0\r\n\r\nextra",
322 " bytes"
324 RunTest(inputs, arraysize(inputs), "hello", true, 11);
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(),
337 RunTestUntilFailure(inputs, arraysize(inputs), 1);
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()
351 RunTestUntilFailure(inputs, arraysize(inputs), 1);
354 } // namespace
356 } // namespace net