OLD | NEW |
---|---|
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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
315 rv = parser.ReadResponseBody( | 315 rv = parser.ReadResponseBody( |
316 body_buffer.get(), kBodySize, callback.callback()); | 316 body_buffer.get(), kBodySize, callback.callback()); |
317 ASSERT_EQ(ERR_IO_PENDING, rv); | 317 ASSERT_EQ(ERR_IO_PENDING, rv); |
318 data.RunFor(1); | 318 data.RunFor(1); |
319 | 319 |
320 ASSERT_TRUE(callback.have_result()); | 320 ASSERT_TRUE(callback.have_result()); |
321 rv = callback.WaitForResult(); | 321 rv = callback.WaitForResult(); |
322 ASSERT_EQ(kBodySize, rv); | 322 ASSERT_EQ(kBodySize, rv); |
323 } | 323 } |
324 | 324 |
325 // Test to ensure the HttpStreamParser state machine does not get confused | |
326 // when the final "chunk" has 0 bytes, and is received from the UploadStream | |
327 // only after sending other chunk. | |
328 TEST(HttpStreamParser, AsyncChunkWithEmptyFinalChunk) { | |
329 const char kChunk[] = "Chunk"; | |
330 | |
331 MockWrite writes[] = { | |
332 MockWrite(ASYNC, 0, | |
333 "GET /one.html HTTP/1.1\r\n" | |
334 "Host: localhost\r\n" | |
335 "Transfer-Encoding: chunked\r\n" | |
336 "Connection: keep-alive\r\n\r\n"), | |
337 MockWrite(ASYNC, 1, "5\r\nChunk\r\n"), | |
338 MockWrite(ASYNC, 2, "0\r\n\r\n"), | |
339 }; | |
340 | |
341 // The size of the response body, as reflected in the Content-Length of the | |
342 // MockRead below. | |
343 const int kBodySize = 8; | |
344 | |
345 MockRead reads[] = { | |
346 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n"), | |
347 MockRead(ASYNC, 4, "Content-Length: 8\r\n\r\n"), | |
348 MockRead(ASYNC, 5, "one.html"), | |
349 MockRead(SYNCHRONOUS, 0, 6), // EOF | |
350 }; | |
351 | |
352 ChunkedUploadDataStream upload_stream(0); | |
353 upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, false); | |
354 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); | |
355 | |
356 DeterministicSocketData data(reads, arraysize(reads), writes, | |
357 arraysize(writes)); | |
358 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
359 | |
360 scoped_ptr<DeterministicMockTCPClientSocket> transport( | |
361 new DeterministicMockTCPClientSocket(NULL, &data)); | |
362 data.set_delegate(transport->AsWeakPtr()); | |
363 | |
364 TestCompletionCallback callback; | |
365 int rv = transport->Connect(callback.callback()); | |
366 rv = callback.GetResult(rv); | |
367 ASSERT_EQ(OK, rv); | |
368 | |
369 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); | |
370 socket_handle->SetSocket(transport.Pass()); | |
371 | |
372 HttpRequestInfo request_info; | |
373 request_info.method = "GET"; | |
374 request_info.url = GURL("http://localhost"); | |
375 request_info.load_flags = LOAD_NORMAL; | |
376 request_info.upload_data_stream = &upload_stream; | |
mef
2015/02/11 21:32:10
is it possible to set upload_data_stream to stream
mmenke
2015/02/11 22:37:22
Yes...SyncEmptyChunkedUpload is the only test in t
| |
377 | |
378 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer); | |
379 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(), | |
380 BoundNetLog()); | |
381 | |
382 HttpRequestHeaders request_headers; | |
383 request_headers.SetHeader("Host", "localhost"); | |
384 request_headers.SetHeader("Transfer-Encoding", "chunked"); | |
385 request_headers.SetHeader("Connection", "keep-alive"); | |
386 | |
387 HttpResponseInfo response_info; | |
388 // This will attempt to Write() the initial request and headers, which will | |
389 // complete asynchronously. | |
390 rv = parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, | |
391 &response_info, callback.callback()); | |
392 ASSERT_EQ(ERR_IO_PENDING, rv); | |
393 | |
394 // Complete the initial request write and the chunk with data. | |
395 data.RunFor(2); | |
396 ASSERT_FALSE(callback.have_result()); | |
397 | |
398 // Now append the terminal 0-byte "chunk". | |
399 upload_stream.AppendData(nullptr, 0, true); | |
400 ASSERT_FALSE(callback.have_result()); | |
401 | |
402 // Finalize writing the trailer. | |
403 data.RunFor(1); | |
404 ASSERT_TRUE(callback.have_result()); | |
405 | |
406 // Warning: This will hang if the callback doesn't already have a result, | |
407 // due to the deterministic socket provider. Do not remove the above | |
408 // ASSERT_TRUE, which will avoid this hang. | |
409 rv = callback.WaitForResult(); | |
410 ASSERT_EQ(OK, rv); | |
411 | |
412 // Attempt to read the response status and the response headers. | |
413 rv = parser.ReadResponseHeaders(callback.callback()); | |
414 ASSERT_EQ(ERR_IO_PENDING, rv); | |
415 data.RunFor(2); | |
416 | |
417 ASSERT_TRUE(callback.have_result()); | |
418 rv = callback.WaitForResult(); | |
419 ASSERT_GT(rv, 0); | |
420 | |
421 // Finally, attempt to read the response body. | |
422 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); | |
423 rv = parser.ReadResponseBody(body_buffer.get(), kBodySize, | |
424 callback.callback()); | |
425 ASSERT_EQ(ERR_IO_PENDING, rv); | |
426 data.RunFor(1); | |
427 | |
428 ASSERT_TRUE(callback.have_result()); | |
429 rv = callback.WaitForResult(); | |
430 ASSERT_EQ(kBodySize, rv); | |
431 } | |
432 | |
433 // Test to ensure the HttpStreamParser state machine does not get confused | |
434 // when there's only one "chunk" with 0 bytes, and is received from the | |
435 // UploadStream only after sending the request headers successfully. | |
436 TEST(HttpStreamParser, AsyncEmptyChunkedUpload) { | |
437 MockWrite writes[] = { | |
438 MockWrite(ASYNC, 0, | |
439 "GET /one.html HTTP/1.1\r\n" | |
440 "Host: localhost\r\n" | |
441 "Transfer-Encoding: chunked\r\n" | |
442 "Connection: keep-alive\r\n\r\n"), | |
443 MockWrite(ASYNC, 1, "0\r\n\r\n"), | |
444 }; | |
445 | |
446 // The size of the response body, as reflected in the Content-Length of the | |
447 // MockRead below. | |
448 const int kBodySize = 8; | |
449 | |
450 MockRead reads[] = { | |
451 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"), | |
452 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"), | |
453 MockRead(ASYNC, 4, "one.html"), | |
454 MockRead(SYNCHRONOUS, 0, 5), // EOF | |
455 }; | |
456 | |
457 ChunkedUploadDataStream upload_stream(0); | |
458 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); | |
459 | |
460 DeterministicSocketData data(reads, arraysize(reads), writes, | |
461 arraysize(writes)); | |
462 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
463 | |
464 scoped_ptr<DeterministicMockTCPClientSocket> transport( | |
465 new DeterministicMockTCPClientSocket(NULL, &data)); | |
466 data.set_delegate(transport->AsWeakPtr()); | |
467 | |
468 TestCompletionCallback callback; | |
469 int rv = transport->Connect(callback.callback()); | |
470 rv = callback.GetResult(rv); | |
471 ASSERT_EQ(OK, rv); | |
472 | |
473 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); | |
474 socket_handle->SetSocket(transport.Pass()); | |
475 | |
476 HttpRequestInfo request_info; | |
477 request_info.method = "GET"; | |
478 request_info.url = GURL("http://localhost"); | |
479 request_info.load_flags = LOAD_NORMAL; | |
480 request_info.upload_data_stream = &upload_stream; | |
481 | |
482 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer); | |
483 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(), | |
484 BoundNetLog()); | |
485 | |
486 HttpRequestHeaders request_headers; | |
487 request_headers.SetHeader("Host", "localhost"); | |
488 request_headers.SetHeader("Transfer-Encoding", "chunked"); | |
489 request_headers.SetHeader("Connection", "keep-alive"); | |
490 | |
491 HttpResponseInfo response_info; | |
492 // This will attempt to Write() the initial request and headers, which will | |
493 // complete asynchronously. | |
494 rv = parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, | |
495 &response_info, callback.callback()); | |
496 ASSERT_EQ(ERR_IO_PENDING, rv); | |
497 | |
498 // Complete writing the request headers. | |
499 data.RunFor(1); | |
500 ASSERT_FALSE(callback.have_result()); | |
501 | |
502 // Now append the terminal 0-byte "chunk". | |
503 upload_stream.AppendData(nullptr, 0, true); | |
504 ASSERT_FALSE(callback.have_result()); | |
505 | |
506 // Finalize writing the trailer. | |
507 data.RunFor(1); | |
508 ASSERT_TRUE(callback.have_result()); | |
509 | |
510 // Warning: This will hang if the callback doesn't already have a result, | |
511 // due to the deterministic socket provider. Do not remove the above | |
512 // ASSERT_TRUE, which will avoid this hang. | |
513 rv = callback.WaitForResult(); | |
514 ASSERT_EQ(OK, rv); | |
515 | |
516 // Attempt to read the response status and the response headers. | |
517 rv = parser.ReadResponseHeaders(callback.callback()); | |
518 ASSERT_EQ(ERR_IO_PENDING, rv); | |
519 data.RunFor(2); | |
520 | |
521 ASSERT_TRUE(callback.have_result()); | |
522 rv = callback.WaitForResult(); | |
523 ASSERT_GT(rv, 0); | |
524 | |
525 // Finally, attempt to read the response body. | |
526 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); | |
527 rv = parser.ReadResponseBody(body_buffer.get(), kBodySize, | |
528 callback.callback()); | |
529 ASSERT_EQ(ERR_IO_PENDING, rv); | |
530 data.RunFor(1); | |
531 | |
532 ASSERT_TRUE(callback.have_result()); | |
533 rv = callback.WaitForResult(); | |
534 ASSERT_EQ(kBodySize, rv); | |
535 } | |
536 | |
537 // Test to ensure the HttpStreamParser state machine does not get confused | |
538 // when there's only one "chunk" with 0 bytes, which was already appended before | |
539 // the request was started. | |
540 TEST(HttpStreamParser, SyncEmptyChunkedUpload) { | |
541 MockWrite writes[] = { | |
542 MockWrite(ASYNC, 0, | |
543 "GET /one.html HTTP/1.1\r\n" | |
544 "Host: localhost\r\n" | |
545 "Transfer-Encoding: chunked\r\n" | |
546 "Connection: keep-alive\r\n\r\n"), | |
547 MockWrite(ASYNC, 1, "0\r\n\r\n"), | |
548 }; | |
549 | |
550 // The size of the response body, as reflected in the Content-Length of the | |
551 // MockRead below. | |
552 const int kBodySize = 8; | |
553 | |
554 MockRead reads[] = { | |
555 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"), | |
556 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"), | |
557 MockRead(ASYNC, 4, "one.html"), | |
558 MockRead(SYNCHRONOUS, 0, 5), // EOF | |
559 }; | |
560 | |
561 ChunkedUploadDataStream upload_stream(0); | |
562 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback())); | |
563 // Append final empty chunk. | |
564 upload_stream.AppendData(nullptr, 0, true); | |
565 | |
566 DeterministicSocketData data(reads, arraysize(reads), writes, | |
567 arraysize(writes)); | |
568 data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
569 | |
570 scoped_ptr<DeterministicMockTCPClientSocket> transport( | |
571 new DeterministicMockTCPClientSocket(NULL, &data)); | |
572 data.set_delegate(transport->AsWeakPtr()); | |
573 | |
574 TestCompletionCallback callback; | |
575 int rv = transport->Connect(callback.callback()); | |
576 rv = callback.GetResult(rv); | |
577 ASSERT_EQ(OK, rv); | |
578 | |
579 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); | |
580 socket_handle->SetSocket(transport.Pass()); | |
581 | |
582 HttpRequestInfo request_info; | |
583 request_info.method = "GET"; | |
584 request_info.url = GURL("http://localhost"); | |
585 request_info.load_flags = LOAD_NORMAL; | |
586 request_info.upload_data_stream = &upload_stream; | |
587 | |
588 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer); | |
589 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(), | |
590 BoundNetLog()); | |
591 | |
592 HttpRequestHeaders request_headers; | |
593 request_headers.SetHeader("Host", "localhost"); | |
594 request_headers.SetHeader("Transfer-Encoding", "chunked"); | |
595 request_headers.SetHeader("Connection", "keep-alive"); | |
596 | |
597 HttpResponseInfo response_info; | |
598 // This will attempt to Write() the initial request and headers, which will | |
599 // complete asynchronously. | |
600 rv = parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, | |
601 &response_info, callback.callback()); | |
602 ASSERT_EQ(ERR_IO_PENDING, rv); | |
603 | |
604 // Complete writing the request headers and body. | |
605 data.RunFor(2); | |
606 ASSERT_TRUE(callback.have_result()); | |
607 | |
608 // Warning: This will hang if the callback doesn't already have a result, | |
609 // due to the deterministic socket provider. Do not remove the above | |
610 // ASSERT_TRUE, which will avoid this hang. | |
611 rv = callback.WaitForResult(); | |
612 ASSERT_EQ(OK, rv); | |
613 | |
614 // Attempt to read the response status and the response headers. | |
615 rv = parser.ReadResponseHeaders(callback.callback()); | |
616 ASSERT_EQ(ERR_IO_PENDING, rv); | |
617 data.RunFor(2); | |
618 | |
619 ASSERT_TRUE(callback.have_result()); | |
620 rv = callback.WaitForResult(); | |
621 ASSERT_GT(rv, 0); | |
622 | |
623 // Finally, attempt to read the response body. | |
624 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); | |
625 rv = parser.ReadResponseBody(body_buffer.get(), kBodySize, | |
626 callback.callback()); | |
627 ASSERT_EQ(ERR_IO_PENDING, rv); | |
628 data.RunFor(1); | |
629 | |
630 ASSERT_TRUE(callback.have_result()); | |
631 rv = callback.WaitForResult(); | |
632 ASSERT_EQ(kBodySize, rv); | |
633 } | |
634 | |
325 TEST(HttpStreamParser, TruncatedHeaders) { | 635 TEST(HttpStreamParser, TruncatedHeaders) { |
326 MockRead truncated_status_reads[] = { | 636 MockRead truncated_status_reads[] = { |
327 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"), | 637 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"), |
328 MockRead(SYNCHRONOUS, 0, 2), // EOF | 638 MockRead(SYNCHRONOUS, 0, 2), // EOF |
329 }; | 639 }; |
330 | 640 |
331 MockRead truncated_after_status_reads[] = { | 641 MockRead truncated_after_status_reads[] = { |
332 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"), | 642 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"), |
333 MockRead(SYNCHRONOUS, 0, 2), // EOF | 643 MockRead(SYNCHRONOUS, 0, 2), // EOF |
334 }; | 644 }; |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
858 response_info.reset(); | 1168 response_info.reset(); |
859 | 1169 |
860 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); | 1170 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize)); |
861 ASSERT_EQ(kBodySize, parser.ReadResponseBody( | 1171 ASSERT_EQ(kBodySize, parser.ReadResponseBody( |
862 body_buffer.get(), kBodySize, callback.callback())); | 1172 body_buffer.get(), kBodySize, callback.callback())); |
863 } | 1173 } |
864 | 1174 |
865 } // namespace | 1175 } // namespace |
866 | 1176 |
867 } // namespace net | 1177 } // namespace net |
OLD | NEW |