Chromecast Android buildfix: rework CommandLine initialization logic.
[chromium-blink-merge.git] / net / http / http_stream_parser_unittest.cc
blob38279a423458291cfee4b5b538f94b410db767b2
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/files/file_path.h"
12 #include "base/files/file_util.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(
559 buffer.get(), user_buf_len, callback.callback());
560 EXPECT_EQ(read_lengths[i], rv);
561 i++;
562 if (rv <= 0)
563 return;
567 private:
568 HttpRequestHeaders request_headers_;
569 HttpResponseInfo response_info_;
570 HttpRequestInfo request_info_;
571 scoped_refptr<GrowableIOBuffer> read_buffer_;
572 std::vector<MockRead> reads_;
573 std::vector<MockWrite> writes_;
574 scoped_ptr<ClientSocketHandle> socket_handle_;
575 scoped_ptr<DeterministicSocketData> data_;
576 scoped_ptr<DeterministicMockTCPClientSocket> transport_;
577 scoped_ptr<HttpStreamParser> parser_;
578 int sequence_number_;
581 // Test that HTTP/0.9 response size is correctly calculated.
582 TEST(HttpStreamParser, ReceivedBytesNoHeaders) {
583 std::string response = "hello\r\nworld\r\n";
585 SimpleGetRunner get_runner;
586 get_runner.AddRead(response);
587 get_runner.SetupParserAndSendRequest();
588 get_runner.ReadHeaders();
589 EXPECT_EQ(0, get_runner.parser()->received_bytes());
590 int response_size = response.size();
591 int read_lengths[] = {response_size, 0};
592 get_runner.ReadBody(response_size, read_lengths);
593 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
596 // Test basic case where there is no keep-alive or extra data from the socket,
597 // and the entire response is received in a single read.
598 TEST(HttpStreamParser, ReceivedBytesNormal) {
599 std::string headers = "HTTP/1.1 200 OK\r\n"
600 "Content-Length: 7\r\n\r\n";
601 std::string body = "content";
602 std::string response = headers + body;
604 SimpleGetRunner get_runner;
605 get_runner.AddRead(response);
606 get_runner.SetupParserAndSendRequest();
607 get_runner.ReadHeaders();
608 int64 headers_size = headers.size();
609 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
610 int body_size = body.size();
611 int read_lengths[] = {body_size, 0};
612 get_runner.ReadBody(body_size, read_lengths);
613 int64 response_size = response.size();
614 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
617 // Test that bytes that represent "next" response are not counted
618 // as current response "received_bytes".
619 TEST(HttpStreamParser, ReceivedBytesExcludesNextResponse) {
620 std::string headers = "HTTP/1.1 200 OK\r\n"
621 "Content-Length: 8\r\n\r\n";
622 std::string body = "content8";
623 std::string response = headers + body;
624 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
625 std::string data = response + next_response;
627 SimpleGetRunner get_runner;
628 get_runner.AddRead(data);
629 get_runner.SetupParserAndSendRequest();
630 get_runner.ReadHeaders();
631 EXPECT_EQ(39, get_runner.parser()->received_bytes());
632 int64 headers_size = headers.size();
633 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
634 int body_size = body.size();
635 int read_lengths[] = {body_size, 0};
636 get_runner.ReadBody(body_size, read_lengths);
637 int64 response_size = response.size();
638 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
639 int64 next_response_size = next_response.size();
640 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
643 // Test that "received_bytes" calculation works fine when last read
644 // contains more data than requested by user.
645 // We send data in two reads:
646 // 1) Headers + beginning of response
647 // 2) remaining part of response + next response start
648 // We setup user read buffer so it fully accepts the beginnig of response
649 // body, but it is larger that remaining part of body.
650 TEST(HttpStreamParser, ReceivedBytesMultiReadExcludesNextResponse) {
651 std::string headers = "HTTP/1.1 200 OK\r\n"
652 "Content-Length: 36\r\n\r\n";
653 int64 user_buf_len = 32;
654 std::string body_start = std::string(user_buf_len, '#');
655 int body_start_size = body_start.size();
656 EXPECT_EQ(user_buf_len, body_start_size);
657 std::string response_start = headers + body_start;
658 std::string body_end = "abcd";
659 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
660 std::string response_end = body_end + next_response;
662 SimpleGetRunner get_runner;
663 get_runner.AddRead(response_start);
664 get_runner.AddRead(response_end);
665 get_runner.SetupParserAndSendRequest();
666 get_runner.ReadHeaders();
667 int64 headers_size = headers.size();
668 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
669 int body_end_size = body_end.size();
670 int read_lengths[] = {body_start_size, body_end_size, 0};
671 get_runner.ReadBody(body_start_size, read_lengths);
672 int64 response_size = response_start.size() + body_end_size;
673 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
674 int64 next_response_size = next_response.size();
675 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
678 // Test that "received_bytes" calculation works fine when there is no
679 // network activity at all; that is when all data is read from read buffer.
680 // In this case read buffer contains two responses. We expect that only
681 // bytes that correspond to the first one are taken into account.
682 TEST(HttpStreamParser, ReceivedBytesFromReadBufExcludesNextResponse) {
683 std::string headers = "HTTP/1.1 200 OK\r\n"
684 "Content-Length: 7\r\n\r\n";
685 std::string body = "content";
686 std::string response = headers + body;
687 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
688 std::string data = response + next_response;
690 SimpleGetRunner get_runner;
691 get_runner.AddInitialData(data);
692 get_runner.SetupParserAndSendRequest();
693 get_runner.ReadHeaders();
694 int64 headers_size = headers.size();
695 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
696 int body_size = body.size();
697 int read_lengths[] = {body_size, 0};
698 get_runner.ReadBody(body_size, read_lengths);
699 int64 response_size = response.size();
700 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
701 int64 next_response_size = next_response.size();
702 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
705 // Test calculating "received_bytes" when part of request has been already
706 // loaded and placed to read buffer by previous stream parser.
707 TEST(HttpStreamParser, ReceivedBytesUseReadBuf) {
708 std::string buffer = "HTTP/1.1 200 OK\r\n";
709 std::string remaining_headers = "Content-Length: 7\r\n\r\n";
710 int64 headers_size = buffer.size() + remaining_headers.size();
711 std::string body = "content";
712 std::string response = remaining_headers + body;
714 SimpleGetRunner get_runner;
715 get_runner.AddInitialData(buffer);
716 get_runner.AddRead(response);
717 get_runner.SetupParserAndSendRequest();
718 get_runner.ReadHeaders();
719 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
720 int body_size = body.size();
721 int read_lengths[] = {body_size, 0};
722 get_runner.ReadBody(body_size, read_lengths);
723 EXPECT_EQ(headers_size + body_size, get_runner.parser()->received_bytes());
724 EXPECT_EQ(0, get_runner.read_buffer()->offset());
727 // Test the case when the resulting read_buf contains both unused bytes and
728 // bytes ejected by chunked-encoding filter.
729 TEST(HttpStreamParser, ReceivedBytesChunkedTransferExcludesNextResponse) {
730 std::string response = "HTTP/1.1 200 OK\r\n"
731 "Transfer-Encoding: chunked\r\n\r\n"
732 "7\r\nChunk 1\r\n"
733 "8\r\nChunky 2\r\n"
734 "6\r\nTest 3\r\n"
735 "0\r\n\r\n";
736 std::string next_response = "foo bar\r\n";
737 std::string data = response + next_response;
739 SimpleGetRunner get_runner;
740 get_runner.AddInitialData(data);
741 get_runner.SetupParserAndSendRequest();
742 get_runner.ReadHeaders();
743 int read_lengths[] = {4, 3, 6, 2, 6, 0};
744 get_runner.ReadBody(7, read_lengths);
745 int64 response_size = response.size();
746 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
747 int64 next_response_size = next_response.size();
748 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
751 // Test that data transfered in multiple reads is correctly processed.
752 // We feed data into 4-bytes reads. Also we set length of read
753 // buffer to 5-bytes to test all possible buffer misaligments.
754 TEST(HttpStreamParser, ReceivedBytesMultipleReads) {
755 std::string headers = "HTTP/1.1 200 OK\r\n"
756 "Content-Length: 33\r\n\r\n";
757 std::string body = "foo bar baz\r\n"
758 "sputnik mir babushka";
759 std::string response = headers + body;
761 size_t receive_length = 4;
762 std::vector<std::string> blocks;
763 for (size_t i = 0; i < response.size(); i += receive_length) {
764 size_t length = std::min(receive_length, response.size() - i);
765 blocks.push_back(response.substr(i, length));
768 SimpleGetRunner get_runner;
769 for (std::vector<std::string>::size_type i = 0; i < blocks.size(); ++i)
770 get_runner.AddRead(blocks[i]);
771 get_runner.SetupParserAndSendRequest();
772 get_runner.ReadHeaders();
773 int64 headers_size = headers.size();
774 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
775 int read_lengths[] = {1, 4, 4, 4, 4, 4, 4, 4, 4, 0};
776 get_runner.ReadBody(receive_length + 1, read_lengths);
777 int64 response_size = response.size();
778 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
781 // Test that "continue" HTTP header is counted as "received_bytes".
782 TEST(HttpStreamParser, ReceivedBytesIncludesContinueHeader) {
783 std::string status100 = "HTTP/1.1 100 OK\r\n\r\n";
784 std::string headers = "HTTP/1.1 200 OK\r\n"
785 "Content-Length: 7\r\n\r\n";
786 int64 headers_size = status100.size() + headers.size();
787 std::string body = "content";
788 std::string response = headers + body;
790 SimpleGetRunner get_runner;
791 get_runner.AddRead(status100);
792 get_runner.AddRead(response);
793 get_runner.SetupParserAndSendRequest();
794 get_runner.ReadHeaders();
795 EXPECT_EQ(100, get_runner.response_info()->headers->response_code());
796 int64 status100_size = status100.size();
797 EXPECT_EQ(status100_size, get_runner.parser()->received_bytes());
798 get_runner.ReadHeaders();
799 EXPECT_EQ(200, get_runner.response_info()->headers->response_code());
800 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
801 int64 response_size = headers_size + body.size();
802 int body_size = body.size();
803 int read_lengths[] = {body_size, 0};
804 get_runner.ReadBody(body_size, read_lengths);
805 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
808 // Test that an HttpStreamParser can be read from after it's received headers
809 // and data structures owned by its owner have been deleted. This happens
810 // when a ResponseBodyDrainer is used.
811 TEST(HttpStreamParser, ReadAfterUnownedObjectsDestroyed) {
812 MockWrite writes[] = {
813 MockWrite(SYNCHRONOUS, 0,
814 "GET /foo.html HTTP/1.1\r\n\r\n"),
815 MockWrite(SYNCHRONOUS, 1, "1"),
818 const int kBodySize = 1;
819 MockRead reads[] = {
820 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
821 MockRead(SYNCHRONOUS, 6, "Content-Length: 1\r\n\r\n"),
822 MockRead(SYNCHRONOUS, 6, "Connection: Keep-Alive\r\n\r\n"),
823 MockRead(SYNCHRONOUS, 7, "1"),
824 MockRead(SYNCHRONOUS, 0, 8), // EOF
827 StaticSocketDataProvider data(reads, arraysize(reads), writes,
828 arraysize(writes));
829 data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
831 scoped_ptr<MockTCPClientSocket> transport(
832 new MockTCPClientSocket(AddressList(), NULL, &data));
834 TestCompletionCallback callback;
835 ASSERT_EQ(OK, transport->Connect(callback.callback()));
837 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
838 socket_handle->SetSocket(transport.PassAs<StreamSocket>());
840 scoped_ptr<HttpRequestInfo> request_info(new HttpRequestInfo());
841 request_info->method = "GET";
842 request_info->url = GURL("http://somewhere/foo.html");
844 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
845 HttpStreamParser parser(socket_handle.get(), request_info.get(),
846 read_buffer.get(), BoundNetLog());
848 scoped_ptr<HttpRequestHeaders> request_headers(new HttpRequestHeaders());
849 scoped_ptr<HttpResponseInfo> response_info(new HttpResponseInfo());
850 ASSERT_EQ(OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n",
851 *request_headers, response_info.get(), callback.callback()));
852 ASSERT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
854 // If the object that owns the HttpStreamParser is deleted, it takes the
855 // objects passed to the HttpStreamParser with it.
856 request_info.reset();
857 request_headers.reset();
858 response_info.reset();
860 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
861 ASSERT_EQ(kBodySize, parser.ReadResponseBody(
862 body_buffer.get(), kBodySize, callback.callback()));
865 } // namespace
867 } // namespace net