Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(543)

Side by Side Diff: net/http/http_stream_parser_unittest.cc

Issue 921453003: Allow URLRequest::AppendChunkToUpload to take 0-byte final chunks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reduce tests, refactor out some of the boilerplate, merge some lines Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | net/url_request/url_request.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_stream_parser.h" 5 #include "net/http/http_stream_parser.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 22 matching lines...) Expand all
33 33
34 namespace net { 34 namespace net {
35 35
36 namespace { 36 namespace {
37 37
38 const size_t kOutputSize = 1024; // Just large enough for this test. 38 const size_t kOutputSize = 1024; // Just large enough for this test.
39 // The number of bytes that can fit in a buffer of kOutputSize. 39 // The number of bytes that can fit in a buffer of kOutputSize.
40 const size_t kMaxPayloadSize = 40 const size_t kMaxPayloadSize =
41 kOutputSize - HttpStreamParser::kChunkHeaderFooterSize; 41 kOutputSize - HttpStreamParser::kChunkHeaderFooterSize;
42 42
43 // Helper method to create a connected ClientSocketHandle using |data|.
44 // Modifies |data|.
45 scoped_ptr<ClientSocketHandle> CreateConnectedSocketHandle(
46 DeterministicSocketData* data) {
47 data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
48
49 scoped_ptr<DeterministicMockTCPClientSocket> transport(
50 new DeterministicMockTCPClientSocket(nullptr, data));
51 data->set_delegate(transport->AsWeakPtr());
52
53 TestCompletionCallback callback;
54 EXPECT_EQ(OK, transport->Connect(callback.callback()));
55
56 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
57 socket_handle->SetSocket(transport.Pass());
58 return socket_handle.Pass();
59 }
60
43 // The empty payload is how the last chunk is encoded. 61 // The empty payload is how the last chunk is encoded.
44 TEST(HttpStreamParser, EncodeChunk_EmptyPayload) { 62 TEST(HttpStreamParser, EncodeChunk_EmptyPayload) {
45 char output[kOutputSize]; 63 char output[kOutputSize];
46 64
47 const base::StringPiece kPayload = ""; 65 const base::StringPiece kPayload = "";
48 const base::StringPiece kExpected = "0\r\n\r\n"; 66 const base::StringPiece kExpected = "0\r\n\r\n";
49 const int num_bytes_written = 67 const int num_bytes_written =
50 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output)); 68 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
51 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written)); 69 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
52 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written)); 70 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 195
178 scoped_ptr<UploadDataStream> body( 196 scoped_ptr<UploadDataStream> body(
179 new ElementsUploadDataStream(element_readers.Pass(), 0)); 197 new ElementsUploadDataStream(element_readers.Pass(), 0));
180 ASSERT_EQ(OK, body->Init(CompletionCallback())); 198 ASSERT_EQ(OK, body->Init(CompletionCallback()));
181 // Shouldn't be merged if the in-memory body is large here. 199 // Shouldn't be merged if the in-memory body is large here.
182 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody( 200 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
183 "some header", body.get())); 201 "some header", body.get()));
184 } 202 }
185 203
186 // Test to ensure the HttpStreamParser state machine does not get confused 204 // Test to ensure the HttpStreamParser state machine does not get confused
205 // when sending a request with a chunked body with only one chunk that becomes
206 // available asynchronously.
207 TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
208 static const char kChunk[] = "Chunk";
209
210 MockWrite writes[] = {
211 MockWrite(ASYNC, 0,
212 "GET /one.html HTTP/1.1\r\n"
213 "Transfer-Encoding: chunked\r\n\r\n"),
214 MockWrite(ASYNC, 1, "5\r\nChunk\r\n"),
215 MockWrite(ASYNC, 2, "0\r\n\r\n"),
216 };
217
218 // The size of the response body, as reflected in the Content-Length of the
219 // MockRead below.
220 static const int kBodySize = 8;
221
222 MockRead reads[] = {
223 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n"),
224 MockRead(ASYNC, 4, "Content-Length: 8\r\n\r\n"),
225 MockRead(ASYNC, 5, "one.html"),
226 MockRead(SYNCHRONOUS, 0, 6), // EOF
227 };
228
229 ChunkedUploadDataStream upload_stream(0);
230 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
231
232 DeterministicSocketData data(reads, arraysize(reads), writes,
233 arraysize(writes));
234 scoped_ptr<ClientSocketHandle> socket_handle =
235 CreateConnectedSocketHandle(&data);
236
237 HttpRequestInfo request_info;
238 request_info.method = "GET";
239 request_info.url = GURL("http://localhost");
240 request_info.upload_data_stream = &upload_stream;
241
242 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
243 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
244 BoundNetLog());
245
246 HttpRequestHeaders request_headers;
247 request_headers.SetHeader("Transfer-Encoding", "chunked");
248
249 HttpResponseInfo response_info;
250 TestCompletionCallback callback;
251 // This will attempt to Write() the initial request and headers, which will
252 // complete asynchronously.
253 ASSERT_EQ(ERR_IO_PENDING,
254 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
255 &response_info, callback.callback()));
256
257 // Complete the initial request write.
258 data.RunFor(1);
259 ASSERT_FALSE(callback.have_result());
260
261 // Now append the only chunk.
262 upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
263 // Write the chunk.
264 data.RunFor(1);
265 ASSERT_FALSE(callback.have_result());
266
267 // Write the trailer.
268 data.RunFor(1);
269 ASSERT_TRUE(callback.have_result());
270 ASSERT_EQ(OK, callback.WaitForResult());
271
272 // Attempt to read the response status and the response headers.
273 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
274 data.RunFor(2);
275 ASSERT_TRUE(callback.have_result());
276 ASSERT_GT(callback.WaitForResult(), 0);
277
278 // Finally, attempt to read the response body.
279 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
280 ASSERT_EQ(ERR_IO_PENDING,
281 parser.ReadResponseBody(body_buffer.get(), kBodySize,
282 callback.callback()));
283 data.RunFor(1);
284 ASSERT_TRUE(callback.have_result());
285 ASSERT_EQ(kBodySize, callback.WaitForResult());
286 }
287
288 // Test to ensure the HttpStreamParser state machine does not get confused
289 // when sending a request with a chunked body with only one chunk that is
290 // available synchronously.
291 TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
292 static const char kChunk[] = "Chunk";
293
294 MockWrite writes[] = {
295 MockWrite(ASYNC, 0,
296 "GET /one.html HTTP/1.1\r\n"
297 "Transfer-Encoding: chunked\r\n\r\n"),
298 MockWrite(ASYNC, 1, "5\r\nChunk\r\n"),
299 MockWrite(ASYNC, 2, "0\r\n\r\n"),
300 };
301
302 // The size of the response body, as reflected in the Content-Length of the
303 // MockRead below.
304 static const int kBodySize = 8;
305
306 MockRead reads[] = {
307 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n"),
308 MockRead(ASYNC, 4, "Content-Length: 8\r\n\r\n"),
309 MockRead(ASYNC, 5, "one.html"),
310 MockRead(SYNCHRONOUS, 0, 6), // EOF
311 };
312
313 ChunkedUploadDataStream upload_stream(0);
314 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
315 // Append the only chunk.
316 upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
317
318 DeterministicSocketData data(reads, arraysize(reads), writes,
319 arraysize(writes));
320 scoped_ptr<ClientSocketHandle> socket_handle =
321 CreateConnectedSocketHandle(&data);
322
323 HttpRequestInfo request_info;
324 request_info.method = "GET";
325 request_info.url = GURL("http://localhost");
326 request_info.upload_data_stream = &upload_stream;
327
328 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
329 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
330 BoundNetLog());
331
332 HttpRequestHeaders request_headers;
333 request_headers.SetHeader("Transfer-Encoding", "chunked");
334
335 HttpResponseInfo response_info;
336 TestCompletionCallback callback;
337 // This will attempt to Write() the initial request and headers, which will
338 // complete asynchronously.
339 ASSERT_EQ(ERR_IO_PENDING,
340 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
341 &response_info, callback.callback()));
342
343 // Write the request and the only chunk.
344 data.RunFor(2);
345
346 // Write the trailer.
347 data.RunFor(1);
348 ASSERT_TRUE(callback.have_result());
349 ASSERT_EQ(OK, callback.WaitForResult());
350
351 // Attempt to read the response status and the response headers.
352 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
353 data.RunFor(2);
354 ASSERT_TRUE(callback.have_result());
355 ASSERT_GT(callback.WaitForResult(), 0);
356
357 // Finally, attempt to read the response body.
358 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
359 ASSERT_EQ(ERR_IO_PENDING,
360 parser.ReadResponseBody(body_buffer.get(), kBodySize,
361 callback.callback()));
362 data.RunFor(1);
363 ASSERT_TRUE(callback.have_result());
364 ASSERT_EQ(kBodySize, callback.WaitForResult());
365 }
366
367 // Test to ensure the HttpStreamParser state machine does not get confused
187 // when sending a request with a chunked body, where chunks become available 368 // when sending a request with a chunked body, where chunks become available
188 // asynchronously, over a socket where writes may also complete 369 // asynchronously, over a socket where writes may also complete
189 // asynchronously. 370 // asynchronously.
190 // This is a regression test for http://crbug.com/132243 371 // This is a regression test for http://crbug.com/132243
191 TEST(HttpStreamParser, AsyncChunkAndAsyncSocket) { 372 TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
192 // The chunks that will be written in the request, as reflected in the 373 // The chunks that will be written in the request, as reflected in the
193 // MockWrites below. 374 // MockWrites below.
194 static const char kChunk1[] = "Chunk 1"; 375 static const char kChunk1[] = "Chunk 1";
195 static const char kChunk2[] = "Chunky 2"; 376 static const char kChunk2[] = "Chunky 2";
196 static const char kChunk3[] = "Test 3"; 377 static const char kChunk3[] = "Test 3";
197 378
198 MockWrite writes[] = { 379 MockWrite writes[] = {
199 MockWrite(ASYNC, 0, 380 MockWrite(ASYNC, 0,
200 "GET /one.html HTTP/1.1\r\n" 381 "GET /one.html HTTP/1.1\r\n"
201 "Host: localhost\r\n" 382 "Transfer-Encoding: chunked\r\n\r\n"),
202 "Transfer-Encoding: chunked\r\n" 383 MockWrite(ASYNC, 1, "7\r\nChunk 1\r\n"),
203 "Connection: keep-alive\r\n\r\n"), 384 MockWrite(ASYNC, 2, "8\r\nChunky 2\r\n"),
204 MockWrite(ASYNC, 1, "7\r\nChunk 1\r\n"), 385 MockWrite(ASYNC, 3, "6\r\nTest 3\r\n"),
205 MockWrite(ASYNC, 2, "8\r\nChunky 2\r\n"), 386 MockWrite(ASYNC, 4, "0\r\n\r\n"),
206 MockWrite(ASYNC, 3, "6\r\nTest 3\r\n"),
207 MockWrite(ASYNC, 4, "0\r\n\r\n"),
208 }; 387 };
209 388
210 // The size of the response body, as reflected in the Content-Length of the 389 // The size of the response body, as reflected in the Content-Length of the
211 // MockRead below. 390 // MockRead below.
212 static const int kBodySize = 8; 391 static const int kBodySize = 8;
213 392
214 MockRead reads[] = { 393 MockRead reads[] = {
215 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"), 394 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"),
216 MockRead(ASYNC, 6, "Content-Length: 8\r\n\r\n"), 395 MockRead(ASYNC, 6, "Content-Length: 8\r\n\r\n"),
217 MockRead(ASYNC, 7, "one.html"), 396 MockRead(ASYNC, 7, "one.html"),
218 MockRead(SYNCHRONOUS, 0, 8), // EOF 397 MockRead(SYNCHRONOUS, 0, 8), // EOF
219 }; 398 };
220 399
221 ChunkedUploadDataStream upload_stream(0); 400 ChunkedUploadDataStream upload_stream(0);
222 upload_stream.AppendData(kChunk1, arraysize(kChunk1) - 1, false); 401 upload_stream.AppendData(kChunk1, arraysize(kChunk1) - 1, false);
223 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); 402 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
224 403
225 DeterministicSocketData data(reads, arraysize(reads), 404 DeterministicSocketData data(reads, arraysize(reads), writes,
226 writes, arraysize(writes)); 405 arraysize(writes));
227 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); 406 scoped_ptr<ClientSocketHandle> socket_handle =
228 407 CreateConnectedSocketHandle(&data);
229 scoped_ptr<DeterministicMockTCPClientSocket> transport(
230 new DeterministicMockTCPClientSocket(NULL, &data));
231 data.set_delegate(transport->AsWeakPtr());
232
233 TestCompletionCallback callback;
234 int rv = transport->Connect(callback.callback());
235 rv = callback.GetResult(rv);
236 ASSERT_EQ(OK, rv);
237
238 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
239 socket_handle->SetSocket(transport.Pass());
240 408
241 HttpRequestInfo request_info; 409 HttpRequestInfo request_info;
242 request_info.method = "GET"; 410 request_info.method = "GET";
243 request_info.url = GURL("http://localhost"); 411 request_info.url = GURL("http://localhost");
244 request_info.load_flags = LOAD_NORMAL;
245 request_info.upload_data_stream = &upload_stream; 412 request_info.upload_data_stream = &upload_stream;
246 413
247 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer); 414 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
248 HttpStreamParser parser( 415 HttpStreamParser parser(
249 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog()); 416 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
250 417
251 HttpRequestHeaders request_headers; 418 HttpRequestHeaders request_headers;
252 request_headers.SetHeader("Host", "localhost");
253 request_headers.SetHeader("Transfer-Encoding", "chunked"); 419 request_headers.SetHeader("Transfer-Encoding", "chunked");
254 request_headers.SetHeader("Connection", "keep-alive");
255 420
256 HttpResponseInfo response_info; 421 HttpResponseInfo response_info;
422 TestCompletionCallback callback;
257 // This will attempt to Write() the initial request and headers, which will 423 // This will attempt to Write() the initial request and headers, which will
258 // complete asynchronously. 424 // complete asynchronously.
259 rv = parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, 425 ASSERT_EQ(ERR_IO_PENDING,
260 &response_info, callback.callback()); 426 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
261 ASSERT_EQ(ERR_IO_PENDING, rv); 427 &response_info, callback.callback()));
262 428
263 // Complete the initial request write. Additionally, this should enqueue the 429 // Complete the initial request write. Additionally, this should enqueue the
264 // first chunk. 430 // first chunk.
265 data.RunFor(1); 431 data.RunFor(1);
266 ASSERT_FALSE(callback.have_result()); 432 ASSERT_FALSE(callback.have_result());
267 433
268 // Now append another chunk (while the first write is still pending), which 434 // Now append another chunk (while the first write is still pending), which
269 // should not confuse the state machine. 435 // should not confuse the state machine.
270 upload_stream.AppendData(kChunk2, arraysize(kChunk2) - 1, false); 436 upload_stream.AppendData(kChunk2, arraysize(kChunk2) - 1, false);
271 ASSERT_FALSE(callback.have_result()); 437 ASSERT_FALSE(callback.have_result());
(...skipping 15 matching lines...) Expand all
287 upload_stream.AppendData(kChunk3, arraysize(kChunk3) - 1, true); 453 upload_stream.AppendData(kChunk3, arraysize(kChunk3) - 1, true);
288 ASSERT_FALSE(callback.have_result()); 454 ASSERT_FALSE(callback.have_result());
289 455
290 // Finalize writing the last chunk, which will enqueue the trailer. 456 // Finalize writing the last chunk, which will enqueue the trailer.
291 data.RunFor(1); 457 data.RunFor(1);
292 ASSERT_FALSE(callback.have_result()); 458 ASSERT_FALSE(callback.have_result());
293 459
294 // Finalize writing the trailer. 460 // Finalize writing the trailer.
295 data.RunFor(1); 461 data.RunFor(1);
296 ASSERT_TRUE(callback.have_result()); 462 ASSERT_TRUE(callback.have_result());
297 463 ASSERT_EQ(OK, callback.WaitForResult());
298 // Warning: This will hang if the callback doesn't already have a result,
299 // due to the deterministic socket provider. Do not remove the above
300 // ASSERT_TRUE, which will avoid this hang.
301 rv = callback.WaitForResult();
302 ASSERT_EQ(OK, rv);
303 464
304 // Attempt to read the response status and the response headers. 465 // Attempt to read the response status and the response headers.
305 rv = parser.ReadResponseHeaders(callback.callback()); 466 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
306 ASSERT_EQ(ERR_IO_PENDING, rv);
307 data.RunFor(2); 467 data.RunFor(2);
308
309 ASSERT_TRUE(callback.have_result()); 468 ASSERT_TRUE(callback.have_result());
310 rv = callback.WaitForResult(); 469 ASSERT_GT(callback.WaitForResult(), 0);
311 ASSERT_GT(rv, 0);
312 470
313 // Finally, attempt to read the response body. 471 // Finally, attempt to read the response body.
314 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); 472 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
315 rv = parser.ReadResponseBody( 473 ASSERT_EQ(ERR_IO_PENDING,
316 body_buffer.get(), kBodySize, callback.callback()); 474 parser.ReadResponseBody(body_buffer.get(), kBodySize,
317 ASSERT_EQ(ERR_IO_PENDING, rv); 475 callback.callback()));
318 data.RunFor(1); 476 data.RunFor(1);
477 ASSERT_TRUE(callback.have_result());
478 ASSERT_EQ(kBodySize, callback.WaitForResult());
479 }
319 480
481 // Test to ensure the HttpStreamParser state machine does not get confused
482 // when there's only one "chunk" with 0 bytes, and is received from the
483 // UploadStream only after sending the request headers successfully.
484 TEST(HttpStreamParser, AsyncEmptyChunkedUpload) {
485 MockWrite writes[] = {
486 MockWrite(ASYNC, 0,
487 "GET /one.html HTTP/1.1\r\n"
488 "Transfer-Encoding: chunked\r\n\r\n"),
489 MockWrite(ASYNC, 1, "0\r\n\r\n"),
490 };
491
492 // The size of the response body, as reflected in the Content-Length of the
493 // MockRead below.
494 const int kBodySize = 8;
495
496 MockRead reads[] = {
497 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"),
498 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"),
499 MockRead(ASYNC, 4, "one.html"),
500 MockRead(SYNCHRONOUS, 0, 5), // EOF
501 };
502
503 ChunkedUploadDataStream upload_stream(0);
504 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
505
506 DeterministicSocketData data(reads, arraysize(reads), writes,
507 arraysize(writes));
508 scoped_ptr<ClientSocketHandle> socket_handle =
509 CreateConnectedSocketHandle(&data);
510
511 HttpRequestInfo request_info;
512 request_info.method = "GET";
513 request_info.url = GURL("http://localhost");
514 request_info.upload_data_stream = &upload_stream;
515
516 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
517 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
518 BoundNetLog());
519
520 HttpRequestHeaders request_headers;
521 request_headers.SetHeader("Transfer-Encoding", "chunked");
522
523 HttpResponseInfo response_info;
524 TestCompletionCallback callback;
525 // This will attempt to Write() the initial request and headers, which will
526 // complete asynchronously.
527 ASSERT_EQ(ERR_IO_PENDING,
528 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
529 &response_info, callback.callback()));
530
531 // Complete writing the request headers.
532 data.RunFor(1);
533 ASSERT_FALSE(callback.have_result());
534
535 // Now append the terminal 0-byte "chunk".
536 upload_stream.AppendData(nullptr, 0, true);
537 ASSERT_FALSE(callback.have_result());
538
539 // Finalize writing the trailer.
540 data.RunFor(1);
320 ASSERT_TRUE(callback.have_result()); 541 ASSERT_TRUE(callback.have_result());
321 rv = callback.WaitForResult(); 542 ASSERT_EQ(OK, callback.WaitForResult());
322 ASSERT_EQ(kBodySize, rv); 543
544 // Attempt to read the response status and the response headers.
545 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
546 data.RunFor(2);
547 ASSERT_TRUE(callback.have_result());
548 ASSERT_GT(callback.WaitForResult(), 0);
549
550 // Finally, attempt to read the response body.
551 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
552 ASSERT_EQ(ERR_IO_PENDING,
553 parser.ReadResponseBody(body_buffer.get(), kBodySize,
554 callback.callback()));
555 data.RunFor(1);
556 ASSERT_TRUE(callback.have_result());
557 ASSERT_EQ(kBodySize, callback.WaitForResult());
558 }
559
560 // Test to ensure the HttpStreamParser state machine does not get confused
561 // when there's only one "chunk" with 0 bytes, which was already appended before
562 // the request was started.
563 TEST(HttpStreamParser, SyncEmptyChunkedUpload) {
564 MockWrite writes[] = {
565 MockWrite(ASYNC, 0,
566 "GET /one.html HTTP/1.1\r\n"
567 "Transfer-Encoding: chunked\r\n\r\n"),
568 MockWrite(ASYNC, 1, "0\r\n\r\n"),
569 };
570
571 // The size of the response body, as reflected in the Content-Length of the
572 // MockRead below.
573 const int kBodySize = 8;
574
575 MockRead reads[] = {
576 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"),
577 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"),
578 MockRead(ASYNC, 4, "one.html"),
579 MockRead(SYNCHRONOUS, 0, 5), // EOF
580 };
581
582 ChunkedUploadDataStream upload_stream(0);
583 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
584 // Append final empty chunk.
585 upload_stream.AppendData(nullptr, 0, true);
586
587 DeterministicSocketData data(reads, arraysize(reads), writes,
588 arraysize(writes));
589 scoped_ptr<ClientSocketHandle> socket_handle =
590 CreateConnectedSocketHandle(&data);
591
592 HttpRequestInfo request_info;
593 request_info.method = "GET";
594 request_info.url = GURL("http://localhost");
595 request_info.upload_data_stream = &upload_stream;
596
597 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
598 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
599 BoundNetLog());
600
601 HttpRequestHeaders request_headers;
602 request_headers.SetHeader("Transfer-Encoding", "chunked");
603
604 HttpResponseInfo response_info;
605 TestCompletionCallback callback;
606 // This will attempt to Write() the initial request and headers, which will
607 // complete asynchronously.
608 ASSERT_EQ(ERR_IO_PENDING,
609 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
610 &response_info, callback.callback()));
611
612 // Complete writing the request headers and body.
613 data.RunFor(2);
614 ASSERT_TRUE(callback.have_result());
615 ASSERT_EQ(OK, callback.WaitForResult());
616
617 // Attempt to read the response status and the response headers.
618 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
619 data.RunFor(2);
620 ASSERT_TRUE(callback.have_result());
621 ASSERT_GT(callback.WaitForResult(), 0);
622
623 // Finally, attempt to read the response body.
624 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
625 ASSERT_EQ(ERR_IO_PENDING,
626 parser.ReadResponseBody(body_buffer.get(), kBodySize,
627 callback.callback()));
628 data.RunFor(1);
629 ASSERT_TRUE(callback.have_result());
630 ASSERT_EQ(kBodySize, callback.WaitForResult());
323 } 631 }
324 632
325 TEST(HttpStreamParser, TruncatedHeaders) { 633 TEST(HttpStreamParser, TruncatedHeaders) {
326 MockRead truncated_status_reads[] = { 634 MockRead truncated_status_reads[] = {
327 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"), 635 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"),
328 MockRead(SYNCHRONOUS, 0, 2), // EOF 636 MockRead(SYNCHRONOUS, 0, 2), // EOF
329 }; 637 };
330 638
331 MockRead truncated_after_status_reads[] = { 639 MockRead truncated_after_status_reads[] = {
332 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"), 640 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"),
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 DeterministicSocketData data(reads[i], 2, writes, arraysize(writes)); 688 DeterministicSocketData data(reads[i], 2, writes, arraysize(writes));
381 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); 689 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
382 data.SetStop(3); 690 data.SetStop(3);
383 691
384 scoped_ptr<DeterministicMockTCPClientSocket> transport( 692 scoped_ptr<DeterministicMockTCPClientSocket> transport(
385 new DeterministicMockTCPClientSocket(NULL, &data)); 693 new DeterministicMockTCPClientSocket(NULL, &data));
386 data.set_delegate(transport->AsWeakPtr()); 694 data.set_delegate(transport->AsWeakPtr());
387 695
388 TestCompletionCallback callback; 696 TestCompletionCallback callback;
389 int rv = transport->Connect(callback.callback()); 697 int rv = transport->Connect(callback.callback());
390 rv = callback.GetResult(rv);
391 ASSERT_EQ(OK, rv); 698 ASSERT_EQ(OK, rv);
392 699
393 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); 700 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
394 socket_handle->SetSocket(transport.Pass()); 701 socket_handle->SetSocket(transport.Pass());
395 702
396 HttpRequestInfo request_info; 703 HttpRequestInfo request_info;
397 request_info.method = "GET"; 704 request_info.method = "GET";
398 if (protocol == HTTP) { 705 if (protocol == HTTP) {
399 request_info.url = GURL("http://localhost"); 706 request_info.url = GURL("http://localhost");
400 } else { 707 } else {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 writes, arraysize(writes)); 756 writes, arraysize(writes));
450 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); 757 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
451 data.SetStop(2); 758 data.SetStop(2);
452 759
453 scoped_ptr<DeterministicMockTCPClientSocket> transport( 760 scoped_ptr<DeterministicMockTCPClientSocket> transport(
454 new DeterministicMockTCPClientSocket(NULL, &data)); 761 new DeterministicMockTCPClientSocket(NULL, &data));
455 data.set_delegate(transport->AsWeakPtr()); 762 data.set_delegate(transport->AsWeakPtr());
456 763
457 TestCompletionCallback callback; 764 TestCompletionCallback callback;
458 int rv = transport->Connect(callback.callback()); 765 int rv = transport->Connect(callback.callback());
459 rv = callback.GetResult(rv);
460 ASSERT_EQ(OK, rv); 766 ASSERT_EQ(OK, rv);
461 767
462 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); 768 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
463 socket_handle->SetSocket(transport.Pass()); 769 socket_handle->SetSocket(transport.Pass());
464 770
465 HttpRequestInfo request_info; 771 HttpRequestInfo request_info;
466 request_info.method = "GET"; 772 request_info.method = "GET";
467 request_info.url = GURL("http://localhost"); 773 request_info.url = GURL("http://localhost");
468 request_info.load_flags = LOAD_NORMAL; 774 request_info.load_flags = LOAD_NORMAL;
469 775
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 response_info.reset(); 1164 response_info.reset();
859 1165
860 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); 1166 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
861 ASSERT_EQ(kBodySize, parser.ReadResponseBody( 1167 ASSERT_EQ(kBodySize, parser.ReadResponseBody(
862 body_buffer.get(), kBodySize, callback.callback())); 1168 body_buffer.get(), kBodySize, callback.callback()));
863 } 1169 }
864 1170
865 } // namespace 1171 } // namespace
866 1172
867 } // namespace net 1173 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/url_request/url_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698