Chromium Code Reviews| 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 |