Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / http / http_stream_parser_unittest.cc
blob33910395cbcaabad9689498a2696be47c211633f
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
3 // found in the LICENSE file.
5 #include "net/http/http_stream_parser.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/file_util.h"
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/stringprintf.h"
18 #include "net/base/io_buffer.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/base/upload_bytes_element_reader.h"
22 #include "net/base/upload_data_stream.h"
23 #include "net/base/upload_file_element_reader.h"
24 #include "net/http/http_request_headers.h"
25 #include "net/http/http_request_info.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_response_info.h"
28 #include "net/socket/client_socket_handle.h"
29 #include "net/socket/socket_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "url/gurl.h"
33 namespace net {
35 namespace {
37 const size_t kOutputSize = 1024; // Just large enough for this test.
38 // The number of bytes that can fit in a buffer of kOutputSize.
39 const size_t kMaxPayloadSize =
40 kOutputSize - HttpStreamParser::kChunkHeaderFooterSize;
42 // The empty payload is how the last chunk is encoded.
43 TEST(HttpStreamParser, EncodeChunk_EmptyPayload) {
44 char output[kOutputSize];
46 const base::StringPiece kPayload = "";
47 const base::StringPiece kExpected = "0\r\n\r\n";
48 const int num_bytes_written =
49 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
50 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
51 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
54 TEST(HttpStreamParser, EncodeChunk_ShortPayload) {
55 char output[kOutputSize];
57 const std::string kPayload("foo\x00\x11\x22", 6);
58 // 11 = payload size + sizeof("6") + CRLF x 2.
59 const std::string kExpected("6\r\nfoo\x00\x11\x22\r\n", 11);
60 const int num_bytes_written =
61 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
62 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
63 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
66 TEST(HttpStreamParser, EncodeChunk_LargePayload) {
67 char output[kOutputSize];
69 const std::string kPayload(1000, '\xff'); // '\xff' x 1000.
70 // 3E8 = 1000 in hex.
71 const std::string kExpected = "3E8\r\n" + kPayload + "\r\n";
72 const int num_bytes_written =
73 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
74 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
75 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
78 TEST(HttpStreamParser, EncodeChunk_FullPayload) {
79 char output[kOutputSize];
81 const std::string kPayload(kMaxPayloadSize, '\xff');
82 // 3F4 = 1012 in hex.
83 const std::string kExpected = "3F4\r\n" + kPayload + "\r\n";
84 const int num_bytes_written =
85 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
86 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
87 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
90 TEST(HttpStreamParser, EncodeChunk_TooLargePayload) {
91 char output[kOutputSize];
93 // The payload is one byte larger the output buffer size.
94 const std::string kPayload(kMaxPayloadSize + 1, '\xff');
95 const int num_bytes_written =
96 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
97 ASSERT_EQ(ERR_INVALID_ARGUMENT, num_bytes_written);
100 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_NoBody) {
101 // Shouldn't be merged if upload data is non-existent.
102 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
103 "some header", NULL));
106 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_EmptyBody) {
107 ScopedVector<UploadElementReader> element_readers;
108 scoped_ptr<UploadDataStream> body(
109 new UploadDataStream(element_readers.Pass(), 0));
110 ASSERT_EQ(OK, body->Init(CompletionCallback()));
111 // Shouldn't be merged if upload data is empty.
112 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
113 "some header", body.get()));
116 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_ChunkedBody) {
117 const std::string payload = "123";
118 scoped_ptr<UploadDataStream> body(
119 new UploadDataStream(UploadDataStream::CHUNKED, 0));
120 body->AppendChunk(payload.data(), payload.size(), true);
121 ASSERT_EQ(OK, body->Init(CompletionCallback()));
122 // Shouldn't be merged if upload data carries chunked data.
123 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
124 "some header", body.get()));
127 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_FileBody) {
129 ScopedVector<UploadElementReader> element_readers;
131 // Create an empty temporary file.
132 base::ScopedTempDir temp_dir;
133 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
134 base::FilePath temp_file_path;
135 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(),
136 &temp_file_path));
138 element_readers.push_back(
139 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
140 temp_file_path,
143 base::Time()));
145 scoped_ptr<UploadDataStream> body(
146 new UploadDataStream(element_readers.Pass(), 0));
147 TestCompletionCallback callback;
148 ASSERT_EQ(ERR_IO_PENDING, body->Init(callback.callback()));
149 ASSERT_EQ(OK, callback.WaitForResult());
150 // Shouldn't be merged if upload data carries a file, as it's not in-memory.
151 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
152 "some header", body.get()));
154 // UploadFileElementReaders may post clean-up tasks on destruction.
155 base::RunLoop().RunUntilIdle();
158 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory) {
159 ScopedVector<UploadElementReader> element_readers;
160 const std::string payload = "123";
161 element_readers.push_back(new UploadBytesElementReader(
162 payload.data(), payload.size()));
164 scoped_ptr<UploadDataStream> body(
165 new UploadDataStream(element_readers.Pass(), 0));
166 ASSERT_EQ(OK, body->Init(CompletionCallback()));
167 // Yes, should be merged if the in-memory body is small here.
168 ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
169 "some header", body.get()));
172 TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_LargeBodyInMemory) {
173 ScopedVector<UploadElementReader> element_readers;
174 const std::string payload(10000, 'a'); // 'a' x 10000.
175 element_readers.push_back(new UploadBytesElementReader(
176 payload.data(), payload.size()));
178 scoped_ptr<UploadDataStream> body(
179 new UploadDataStream(element_readers.Pass(), 0));
180 ASSERT_EQ(OK, body->Init(CompletionCallback()));
181 // Shouldn't be merged if the in-memory body is large here.
182 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
183 "some header", body.get()));
186 // Test to ensure the HttpStreamParser state machine does not get confused
187 // when sending a request with a chunked body, where chunks become available
188 // asynchronously, over a socket where writes may also complete
189 // asynchronously.
190 // This is a regression test for http://crbug.com/132243
191 TEST(HttpStreamParser, AsyncChunkAndAsyncSocket) {
192 // The chunks that will be written in the request, as reflected in the
193 // MockWrites below.
194 static const char kChunk1[] = "Chunk 1";
195 static const char kChunk2[] = "Chunky 2";
196 static const char kChunk3[] = "Test 3";
198 MockWrite writes[] = {
199 MockWrite(ASYNC, 0,
200 "GET /one.html HTTP/1.1\r\n"
201 "Host: localhost\r\n"
202 "Transfer-Encoding: chunked\r\n"
203 "Connection: keep-alive\r\n\r\n"),
204 MockWrite(ASYNC, 1, "7\r\nChunk 1\r\n"),
205 MockWrite(ASYNC, 2, "8\r\nChunky 2\r\n"),
206 MockWrite(ASYNC, 3, "6\r\nTest 3\r\n"),
207 MockWrite(ASYNC, 4, "0\r\n\r\n"),
210 // The size of the response body, as reflected in the Content-Length of the
211 // MockRead below.
212 static const int kBodySize = 8;
214 MockRead reads[] = {
215 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"),
216 MockRead(ASYNC, 6, "Content-Length: 8\r\n\r\n"),
217 MockRead(ASYNC, 7, "one.html"),
218 MockRead(SYNCHRONOUS, 0, 8), // EOF
221 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
222 upload_stream.AppendChunk(kChunk1, arraysize(kChunk1) - 1, false);
223 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
225 DeterministicSocketData data(reads, arraysize(reads),
226 writes, arraysize(writes));
227 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
229 scoped_ptr<DeterministicMockTCPClientSocket> transport(
230 new DeterministicMockTCPClientSocket(NULL, &data));
231 data.set_delegate(transport->AsWeakPtr());
233 TestCompletionCallback callback;
234 int rv = transport->Connect(callback.callback());
235 rv = callback.GetResult(rv);
236 ASSERT_EQ(OK, rv);
238 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
239 socket_handle->SetSocket(transport.PassAs<StreamSocket>());
241 HttpRequestInfo request_info;
242 request_info.method = "GET";
243 request_info.url = GURL("http://localhost");
244 request_info.load_flags = LOAD_NORMAL;
245 request_info.upload_data_stream = &upload_stream;
247 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
248 HttpStreamParser parser(
249 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
251 HttpRequestHeaders request_headers;
252 request_headers.SetHeader("Host", "localhost");
253 request_headers.SetHeader("Transfer-Encoding", "chunked");
254 request_headers.SetHeader("Connection", "keep-alive");
256 HttpResponseInfo response_info;
257 // This will attempt to Write() the initial request and headers, which will
258 // complete asynchronously.
259 rv = parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
260 &response_info, callback.callback());
261 ASSERT_EQ(ERR_IO_PENDING, rv);
263 // Complete the initial request write. Additionally, this should enqueue the
264 // first chunk.
265 data.RunFor(1);
266 ASSERT_FALSE(callback.have_result());
268 // Now append another chunk (while the first write is still pending), which
269 // should not confuse the state machine.
270 upload_stream.AppendChunk(kChunk2, arraysize(kChunk2) - 1, false);
271 ASSERT_FALSE(callback.have_result());
273 // Complete writing the first chunk, which should then enqueue the second
274 // chunk for writing and return, because it is set to complete
275 // asynchronously.
276 data.RunFor(1);
277 ASSERT_FALSE(callback.have_result());
279 // Complete writing the second chunk. However, because no chunks are
280 // available yet, no further writes should be called until a new chunk is
281 // added.
282 data.RunFor(1);
283 ASSERT_FALSE(callback.have_result());
285 // Add the final chunk. This will enqueue another write, but it will not
286 // complete due to the async nature.
287 upload_stream.AppendChunk(kChunk3, arraysize(kChunk3) - 1, true);
288 ASSERT_FALSE(callback.have_result());
290 // Finalize writing the last chunk, which will enqueue the trailer.
291 data.RunFor(1);
292 ASSERT_FALSE(callback.have_result());
294 // Finalize writing the trailer.
295 data.RunFor(1);
296 ASSERT_TRUE(callback.have_result());
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);
304 // Attempt to read the response status and the response headers.
305 rv = parser.ReadResponseHeaders(callback.callback());
306 ASSERT_EQ(ERR_IO_PENDING, rv);
307 data.RunFor(2);
309 ASSERT_TRUE(callback.have_result());
310 rv = callback.WaitForResult();
311 ASSERT_GT(rv, 0);
313 // Finally, attempt to read the response body.
314 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
315 rv = parser.ReadResponseBody(
316 body_buffer.get(), kBodySize, callback.callback());
317 ASSERT_EQ(ERR_IO_PENDING, rv);
318 data.RunFor(1);
320 ASSERT_TRUE(callback.have_result());
321 rv = callback.WaitForResult();
322 ASSERT_EQ(kBodySize, rv);
325 TEST(HttpStreamParser, TruncatedHeaders) {
326 MockRead truncated_status_reads[] = {
327 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"),
328 MockRead(SYNCHRONOUS, 0, 2), // EOF
331 MockRead truncated_after_status_reads[] = {
332 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"),
333 MockRead(SYNCHRONOUS, 0, 2), // EOF
336 MockRead truncated_in_header_reads[] = {
337 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHead"),
338 MockRead(SYNCHRONOUS, 0, 2), // EOF
341 MockRead truncated_after_header_reads[] = {
342 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n"),
343 MockRead(SYNCHRONOUS, 0, 2), // EOF
346 MockRead truncated_after_final_newline_reads[] = {
347 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r"),
348 MockRead(SYNCHRONOUS, 0, 2), // EOF
351 MockRead not_truncated_reads[] = {
352 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r\n"),
353 MockRead(SYNCHRONOUS, 0, 2), // EOF
356 MockRead* reads[] = {
357 truncated_status_reads,
358 truncated_after_status_reads,
359 truncated_in_header_reads,
360 truncated_after_header_reads,
361 truncated_after_final_newline_reads,
362 not_truncated_reads,
365 MockWrite writes[] = {
366 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
369 enum {
370 HTTP = 0,
371 HTTPS,
372 NUM_PROTOCOLS,
375 for (size_t protocol = 0; protocol < NUM_PROTOCOLS; protocol++) {
376 SCOPED_TRACE(protocol);
378 for (size_t i = 0; i < arraysize(reads); i++) {
379 SCOPED_TRACE(i);
380 DeterministicSocketData data(reads[i], 2, writes, arraysize(writes));
381 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
382 data.SetStop(3);
384 scoped_ptr<DeterministicMockTCPClientSocket> transport(
385 new DeterministicMockTCPClientSocket(NULL, &data));
386 data.set_delegate(transport->AsWeakPtr());
388 TestCompletionCallback callback;
389 int rv = transport->Connect(callback.callback());
390 rv = callback.GetResult(rv);
391 ASSERT_EQ(OK, rv);
393 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
394 socket_handle->SetSocket(transport.PassAs<StreamSocket>());
396 HttpRequestInfo request_info;
397 request_info.method = "GET";
398 if (protocol == HTTP) {
399 request_info.url = GURL("http://localhost");
400 } else {
401 request_info.url = GURL("https://localhost");
403 request_info.load_flags = LOAD_NORMAL;
405 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
406 HttpStreamParser parser(
407 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
409 HttpRequestHeaders request_headers;
410 HttpResponseInfo response_info;
411 rv = parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
412 &response_info, callback.callback());
413 ASSERT_EQ(OK, rv);
415 rv = parser.ReadResponseHeaders(callback.callback());
416 if (i == arraysize(reads) - 1) {
417 EXPECT_EQ(OK, rv);
418 EXPECT_TRUE(response_info.headers.get());
419 } else {
420 if (protocol == HTTP) {
421 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
422 EXPECT_TRUE(response_info.headers.get());
423 } else {
424 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, rv);
425 EXPECT_FALSE(response_info.headers.get());
432 // Confirm that on 101 response, the headers are parsed but the data that
433 // follows remains in the buffer.
434 TEST(HttpStreamParser, Websocket101Response) {
435 MockRead reads[] = {
436 MockRead(SYNCHRONOUS, 1,
437 "HTTP/1.1 101 Switching Protocols\r\n"
438 "Upgrade: websocket\r\n"
439 "Connection: Upgrade\r\n"
440 "\r\n"
441 "a fake websocket frame"),
444 MockWrite writes[] = {
445 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
448 DeterministicSocketData data(reads, arraysize(reads),
449 writes, arraysize(writes));
450 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
451 data.SetStop(2);
453 scoped_ptr<DeterministicMockTCPClientSocket> transport(
454 new DeterministicMockTCPClientSocket(NULL, &data));
455 data.set_delegate(transport->AsWeakPtr());
457 TestCompletionCallback callback;
458 int rv = transport->Connect(callback.callback());
459 rv = callback.GetResult(rv);
460 ASSERT_EQ(OK, rv);
462 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
463 socket_handle->SetSocket(transport.PassAs<StreamSocket>());
465 HttpRequestInfo request_info;
466 request_info.method = "GET";
467 request_info.url = GURL("http://localhost");
468 request_info.load_flags = LOAD_NORMAL;
470 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
471 HttpStreamParser parser(
472 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
474 HttpRequestHeaders request_headers;
475 HttpResponseInfo response_info;
476 rv = parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
477 &response_info, callback.callback());
478 ASSERT_EQ(OK, rv);
480 rv = parser.ReadResponseHeaders(callback.callback());
481 EXPECT_EQ(OK, rv);
482 ASSERT_TRUE(response_info.headers.get());
483 EXPECT_EQ(101, response_info.headers->response_code());
484 EXPECT_TRUE(response_info.headers->HasHeaderValue("Connection", "Upgrade"));
485 EXPECT_TRUE(response_info.headers->HasHeaderValue("Upgrade", "websocket"));
486 EXPECT_EQ(read_buffer->capacity(), read_buffer->offset());
487 EXPECT_EQ("a fake websocket frame",
488 base::StringPiece(read_buffer->StartOfBuffer(),
489 read_buffer->capacity()));
492 // Helper class for constructing HttpStreamParser and running GET requests.
493 class SimpleGetRunner {
494 public:
495 SimpleGetRunner() : read_buffer_(new GrowableIOBuffer), sequence_number_(0) {
496 writes_.push_back(MockWrite(
497 SYNCHRONOUS, sequence_number_++, "GET / HTTP/1.1\r\n\r\n"));
500 HttpStreamParser* parser() { return parser_.get(); }
501 GrowableIOBuffer* read_buffer() { return read_buffer_.get(); }
502 HttpResponseInfo* response_info() { return &response_info_; }
504 void AddInitialData(const std::string& data) {
505 int offset = read_buffer_->offset();
506 int size = data.size();
507 read_buffer_->SetCapacity(offset + size);
508 memcpy(read_buffer_->StartOfBuffer() + offset, data.data(), size);
509 read_buffer_->set_offset(offset + size);
512 void AddRead(const std::string& data) {
513 reads_.push_back(MockRead(SYNCHRONOUS, sequence_number_++, data.data()));
516 void SetupParserAndSendRequest() {
517 reads_.push_back(MockRead(SYNCHRONOUS, 0, sequence_number_++)); // EOF
519 socket_handle_.reset(new ClientSocketHandle);
520 data_.reset(new DeterministicSocketData(
521 &reads_.front(), reads_.size(), &writes_.front(), writes_.size()));
522 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
523 data_->SetStop(reads_.size() + writes_.size());
525 transport_.reset(new DeterministicMockTCPClientSocket(NULL, data_.get()));
526 data_->set_delegate(transport_->AsWeakPtr());
528 TestCompletionCallback callback;
529 int rv = transport_->Connect(callback.callback());
530 rv = callback.GetResult(rv);
531 ASSERT_EQ(OK, rv);
533 socket_handle_->SetSocket(transport_.PassAs<StreamSocket>());
535 request_info_.method = "GET";
536 request_info_.url = GURL("http://localhost");
537 request_info_.load_flags = LOAD_NORMAL;
539 parser_.reset(new HttpStreamParser(
540 socket_handle_.get(), &request_info_, read_buffer(), BoundNetLog()));
542 rv = parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_,
543 &response_info_, callback.callback());
544 ASSERT_EQ(OK, rv);
547 void ReadHeaders() {
548 TestCompletionCallback callback;
549 EXPECT_EQ(OK, parser_->ReadResponseHeaders(callback.callback()));
552 void ReadBody(int user_buf_len, int* read_lengths) {
553 TestCompletionCallback callback;
554 scoped_refptr<IOBuffer> buffer = new IOBuffer(user_buf_len);
555 int rv;
556 int i = 0;
557 while (true) {
558 rv = parser_->ReadResponseBody(buffer, user_buf_len, callback.callback());
559 EXPECT_EQ(read_lengths[i], rv);
560 i++;
561 if (rv <= 0)
562 return;
566 private:
567 HttpRequestHeaders request_headers_;
568 HttpResponseInfo response_info_;
569 HttpRequestInfo request_info_;
570 scoped_refptr<GrowableIOBuffer> read_buffer_;
571 std::vector<MockRead> reads_;
572 std::vector<MockWrite> writes_;
573 scoped_ptr<ClientSocketHandle> socket_handle_;
574 scoped_ptr<DeterministicSocketData> data_;
575 scoped_ptr<DeterministicMockTCPClientSocket> transport_;
576 scoped_ptr<HttpStreamParser> parser_;
577 int sequence_number_;
580 // Test that HTTP/0.9 response size is correctly calculated.
581 TEST(HttpStreamParser, ReceivedBytesNoHeaders) {
582 std::string response = "hello\r\nworld\r\n";
584 SimpleGetRunner get_runner;
585 get_runner.AddRead(response);
586 get_runner.SetupParserAndSendRequest();
587 get_runner.ReadHeaders();
588 EXPECT_EQ(0, get_runner.parser()->received_bytes());
589 int response_size = response.size();
590 int read_lengths[] = {response_size, 0};
591 get_runner.ReadBody(response_size, read_lengths);
592 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
595 // Test basic case where there is no keep-alive or extra data from the socket,
596 // and the entire response is received in a single read.
597 TEST(HttpStreamParser, ReceivedBytesNormal) {
598 std::string headers = "HTTP/1.1 200 OK\r\n"
599 "Content-Length: 7\r\n\r\n";
600 std::string body = "content";
601 std::string response = headers + body;
603 SimpleGetRunner get_runner;
604 get_runner.AddRead(response);
605 get_runner.SetupParserAndSendRequest();
606 get_runner.ReadHeaders();
607 int64 headers_size = headers.size();
608 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
609 int body_size = body.size();
610 int read_lengths[] = {body_size, 0};
611 get_runner.ReadBody(body_size, read_lengths);
612 int64 response_size = response.size();
613 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
616 // Test that bytes that represent "next" response are not counted
617 // as current response "received_bytes".
618 TEST(HttpStreamParser, ReceivedBytesExcludesNextResponse) {
619 std::string headers = "HTTP/1.1 200 OK\r\n"
620 "Content-Length: 8\r\n\r\n";
621 std::string body = "content8";
622 std::string response = headers + body;
623 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
624 std::string data = response + next_response;
626 SimpleGetRunner get_runner;
627 get_runner.AddRead(data);
628 get_runner.SetupParserAndSendRequest();
629 get_runner.ReadHeaders();
630 EXPECT_EQ(39, get_runner.parser()->received_bytes());
631 int64 headers_size = headers.size();
632 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
633 int body_size = body.size();
634 int read_lengths[] = {body_size, 0};
635 get_runner.ReadBody(body_size, read_lengths);
636 int64 response_size = response.size();
637 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
638 int64 next_response_size = next_response.size();
639 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
642 // Test that "received_bytes" calculation works fine when last read
643 // contains more data than requested by user.
644 // We send data in two reads:
645 // 1) Headers + beginning of response
646 // 2) remaining part of response + next response start
647 // We setup user read buffer so it fully accepts the beginnig of response
648 // body, but it is larger that remaining part of body.
649 TEST(HttpStreamParser, ReceivedBytesMultiReadExcludesNextResponse) {
650 std::string headers = "HTTP/1.1 200 OK\r\n"
651 "Content-Length: 36\r\n\r\n";
652 int64 user_buf_len = 32;
653 std::string body_start = std::string(user_buf_len, '#');
654 int body_start_size = body_start.size();
655 EXPECT_EQ(user_buf_len, body_start_size);
656 std::string response_start = headers + body_start;
657 std::string body_end = "abcd";
658 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
659 std::string response_end = body_end + next_response;
661 SimpleGetRunner get_runner;
662 get_runner.AddRead(response_start);
663 get_runner.AddRead(response_end);
664 get_runner.SetupParserAndSendRequest();
665 get_runner.ReadHeaders();
666 int64 headers_size = headers.size();
667 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
668 int body_end_size = body_end.size();
669 int read_lengths[] = {body_start_size, body_end_size, 0};
670 get_runner.ReadBody(body_start_size, read_lengths);
671 int64 response_size = response_start.size() + body_end_size;
672 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
673 int64 next_response_size = next_response.size();
674 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
677 // Test that "received_bytes" calculation works fine when there is no
678 // network activity at all; that is when all data is read from read buffer.
679 // In this case read buffer contains two responses. We expect that only
680 // bytes that correspond to the first one are taken into account.
681 TEST(HttpStreamParser, ReceivedBytesFromReadBufExcludesNextResponse) {
682 std::string headers = "HTTP/1.1 200 OK\r\n"
683 "Content-Length: 7\r\n\r\n";
684 std::string body = "content";
685 std::string response = headers + body;
686 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
687 std::string data = response + next_response;
689 SimpleGetRunner get_runner;
690 get_runner.AddInitialData(data);
691 get_runner.SetupParserAndSendRequest();
692 get_runner.ReadHeaders();
693 int64 headers_size = headers.size();
694 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
695 int body_size = body.size();
696 int read_lengths[] = {body_size, 0};
697 get_runner.ReadBody(body_size, read_lengths);
698 int64 response_size = response.size();
699 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
700 int64 next_response_size = next_response.size();
701 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
704 // Test calculating "received_bytes" when part of request has been already
705 // loaded and placed to read buffer by previous stream parser.
706 TEST(HttpStreamParser, ReceivedBytesUseReadBuf) {
707 std::string buffer = "HTTP/1.1 200 OK\r\n";
708 std::string remaining_headers = "Content-Length: 7\r\n\r\n";
709 int64 headers_size = buffer.size() + remaining_headers.size();
710 std::string body = "content";
711 std::string response = remaining_headers + body;
713 SimpleGetRunner get_runner;
714 get_runner.AddInitialData(buffer);
715 get_runner.AddRead(response);
716 get_runner.SetupParserAndSendRequest();
717 get_runner.ReadHeaders();
718 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
719 int body_size = body.size();
720 int read_lengths[] = {body_size, 0};
721 get_runner.ReadBody(body_size, read_lengths);
722 EXPECT_EQ(headers_size + body_size, get_runner.parser()->received_bytes());
723 EXPECT_EQ(0, get_runner.read_buffer()->offset());
726 // Test the case when the resulting read_buf contains both unused bytes and
727 // bytes ejected by chunked-encoding filter.
728 TEST(HttpStreamParser, ReceivedBytesChunkedTransferExcludesNextResponse) {
729 std::string response = "HTTP/1.1 200 OK\r\n"
730 "Transfer-Encoding: chunked\r\n\r\n"
731 "7\r\nChunk 1\r\n"
732 "8\r\nChunky 2\r\n"
733 "6\r\nTest 3\r\n"
734 "0\r\n\r\n";
735 std::string next_response = "foo bar\r\n";
736 std::string data = response + next_response;
738 SimpleGetRunner get_runner;
739 get_runner.AddInitialData(data);
740 get_runner.SetupParserAndSendRequest();
741 get_runner.ReadHeaders();
742 int read_lengths[] = {4, 3, 6, 2, 6, 0};
743 get_runner.ReadBody(7, read_lengths);
744 int64 response_size = response.size();
745 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
746 int64 next_response_size = next_response.size();
747 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
750 // Test that data transfered in multiple reads is correctly processed.
751 // We feed data into 4-bytes reads. Also we set length of read
752 // buffer to 5-bytes to test all possible buffer misaligments.
753 TEST(HttpStreamParser, ReceivedBytesMultipleReads) {
754 std::string headers = "HTTP/1.1 200 OK\r\n"
755 "Content-Length: 33\r\n\r\n";
756 std::string body = "foo bar baz\r\n"
757 "sputnik mir babushka";
758 std::string response = headers + body;
760 size_t receive_length = 4;
761 std::vector<std::string> blocks;
762 for (size_t i = 0; i < response.size(); i += receive_length) {
763 size_t length = std::min(receive_length, response.size() - i);
764 blocks.push_back(response.substr(i, length));
767 SimpleGetRunner get_runner;
768 for (std::vector<std::string>::size_type i = 0; i < blocks.size(); ++i)
769 get_runner.AddRead(blocks[i]);
770 get_runner.SetupParserAndSendRequest();
771 get_runner.ReadHeaders();
772 int64 headers_size = headers.size();
773 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
774 int read_lengths[] = {1, 4, 4, 4, 4, 4, 4, 4, 4, 0};
775 get_runner.ReadBody(receive_length + 1, read_lengths);
776 int64 response_size = response.size();
777 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
780 // Test that "continue" HTTP header is counted as "received_bytes".
781 TEST(HttpStreamParser, ReceivedBytesIncludesContinueHeader) {
782 std::string status100 = "HTTP/1.1 100 OK\r\n\r\n";
783 std::string headers = "HTTP/1.1 200 OK\r\n"
784 "Content-Length: 7\r\n\r\n";
785 int64 headers_size = status100.size() + headers.size();
786 std::string body = "content";
787 std::string response = headers + body;
789 SimpleGetRunner get_runner;
790 get_runner.AddRead(status100);
791 get_runner.AddRead(response);
792 get_runner.SetupParserAndSendRequest();
793 get_runner.ReadHeaders();
794 EXPECT_EQ(100, get_runner.response_info()->headers->response_code());
795 int64 status100_size = status100.size();
796 EXPECT_EQ(status100_size, get_runner.parser()->received_bytes());
797 get_runner.ReadHeaders();
798 EXPECT_EQ(200, get_runner.response_info()->headers->response_code());
799 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
800 int64 response_size = headers_size + body.size();
801 int body_size = body.size();
802 int read_lengths[] = {body_size, 0};
803 get_runner.ReadBody(body_size, read_lengths);
804 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
807 // Test that an HttpStreamParser can be read from after it's received headers
808 // and data structures owned by its owner have been deleted. This happens
809 // when a ResponseBodyDrainer is used.
810 TEST(HttpStreamParser, ReadAfterUnownedObjectsDestroyed) {
811 MockWrite writes[] = {
812 MockWrite(SYNCHRONOUS, 0,
813 "GET /foo.html HTTP/1.1\r\n\r\n"),
814 MockWrite(SYNCHRONOUS, 1, "1"),
817 const int kBodySize = 1;
818 MockRead reads[] = {
819 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
820 MockRead(SYNCHRONOUS, 6, "Content-Length: 1\r\n\r\n"),
821 MockRead(SYNCHRONOUS, 6, "Connection: Keep-Alive\r\n\r\n"),
822 MockRead(SYNCHRONOUS, 7, "1"),
823 MockRead(SYNCHRONOUS, 0, 8), // EOF
826 StaticSocketDataProvider data(reads, arraysize(reads), writes,
827 arraysize(writes));
828 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
830 scoped_ptr<MockTCPClientSocket> transport(
831 new MockTCPClientSocket(AddressList(), NULL, &data));
833 TestCompletionCallback callback;
834 ASSERT_EQ(OK, transport->Connect(callback.callback()));
836 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
837 socket_handle->SetSocket(transport.PassAs<StreamSocket>());
839 scoped_ptr<HttpRequestInfo> request_info(new HttpRequestInfo());
840 request_info->method = "GET";
841 request_info->url = GURL("http://somewhere/foo.html");
843 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
844 HttpStreamParser parser(socket_handle.get(), request_info.get(),
845 read_buffer.get(), BoundNetLog());
847 scoped_ptr<HttpRequestHeaders> request_headers(new HttpRequestHeaders());
848 scoped_ptr<HttpResponseInfo> response_info(new HttpResponseInfo());
849 ASSERT_EQ(OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n",
850 *request_headers, response_info.get(), callback.callback()));
851 ASSERT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
853 // If the object that owns the HttpStreamParser is deleted, it takes the
854 // objects passed to the HttpStreamParser with it.
855 request_info.reset();
856 request_headers.reset();
857 response_info.reset();
859 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
860 ASSERT_EQ(kBodySize, parser.ReadResponseBody(
861 body_buffer.get(), kBodySize, callback.callback()));
864 } // namespace
866 } // namespace net