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"
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/chunked_upload_data_stream.h"
19 #include "net/base/elements_upload_data_stream.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/base/upload_bytes_element_reader.h"
24 #include "net/base/upload_file_element_reader.h"
25 #include "net/http/http_request_headers.h"
26 #include "net/http/http_request_info.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_response_info.h"
29 #include "net/socket/client_socket_handle.h"
30 #include "net/socket/socket_test_util.h"
31 #include "testing/gtest/include/gtest/gtest.h"
38 const size_t kOutputSize
= 1024; // Just large enough for this test.
39 // The number of bytes that can fit in a buffer of kOutputSize.
40 const size_t kMaxPayloadSize
=
41 kOutputSize
- HttpStreamParser::kChunkHeaderFooterSize
;
43 // Helper method to create a connected ClientSocketHandle using |data|.
45 scoped_ptr
<ClientSocketHandle
> CreateConnectedSocketHandle(
46 DeterministicSocketData
* data
) {
47 data
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
49 scoped_ptr
<DeterministicMockTCPClientSocket
> transport(
50 new DeterministicMockTCPClientSocket(nullptr, data
));
51 data
->set_delegate(transport
->AsWeakPtr());
53 TestCompletionCallback callback
;
54 EXPECT_EQ(OK
, transport
->Connect(callback
.callback()));
56 scoped_ptr
<ClientSocketHandle
> socket_handle(new ClientSocketHandle
);
57 socket_handle
->SetSocket(transport
.Pass());
58 return socket_handle
.Pass();
61 // The empty payload is how the last chunk is encoded.
62 TEST(HttpStreamParser
, EncodeChunk_EmptyPayload
) {
63 char output
[kOutputSize
];
65 const base::StringPiece kPayload
= "";
66 const base::StringPiece kExpected
= "0\r\n\r\n";
67 const int num_bytes_written
=
68 HttpStreamParser::EncodeChunk(kPayload
, output
, sizeof(output
));
69 ASSERT_EQ(kExpected
.size(), static_cast<size_t>(num_bytes_written
));
70 EXPECT_EQ(kExpected
, base::StringPiece(output
, num_bytes_written
));
73 TEST(HttpStreamParser
, EncodeChunk_ShortPayload
) {
74 char output
[kOutputSize
];
76 const std::string
kPayload("foo\x00\x11\x22", 6);
77 // 11 = payload size + sizeof("6") + CRLF x 2.
78 const std::string
kExpected("6\r\nfoo\x00\x11\x22\r\n", 11);
79 const int num_bytes_written
=
80 HttpStreamParser::EncodeChunk(kPayload
, output
, sizeof(output
));
81 ASSERT_EQ(kExpected
.size(), static_cast<size_t>(num_bytes_written
));
82 EXPECT_EQ(kExpected
, base::StringPiece(output
, num_bytes_written
));
85 TEST(HttpStreamParser
, EncodeChunk_LargePayload
) {
86 char output
[kOutputSize
];
88 const std::string
kPayload(1000, '\xff'); // '\xff' x 1000.
90 const std::string kExpected
= "3E8\r\n" + kPayload
+ "\r\n";
91 const int num_bytes_written
=
92 HttpStreamParser::EncodeChunk(kPayload
, output
, sizeof(output
));
93 ASSERT_EQ(kExpected
.size(), static_cast<size_t>(num_bytes_written
));
94 EXPECT_EQ(kExpected
, base::StringPiece(output
, num_bytes_written
));
97 TEST(HttpStreamParser
, EncodeChunk_FullPayload
) {
98 char output
[kOutputSize
];
100 const std::string
kPayload(kMaxPayloadSize
, '\xff');
101 // 3F4 = 1012 in hex.
102 const std::string kExpected
= "3F4\r\n" + kPayload
+ "\r\n";
103 const int num_bytes_written
=
104 HttpStreamParser::EncodeChunk(kPayload
, output
, sizeof(output
));
105 ASSERT_EQ(kExpected
.size(), static_cast<size_t>(num_bytes_written
));
106 EXPECT_EQ(kExpected
, base::StringPiece(output
, num_bytes_written
));
109 TEST(HttpStreamParser
, EncodeChunk_TooLargePayload
) {
110 char output
[kOutputSize
];
112 // The payload is one byte larger the output buffer size.
113 const std::string
kPayload(kMaxPayloadSize
+ 1, '\xff');
114 const int num_bytes_written
=
115 HttpStreamParser::EncodeChunk(kPayload
, output
, sizeof(output
));
116 ASSERT_EQ(ERR_INVALID_ARGUMENT
, num_bytes_written
);
119 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_NoBody
) {
120 // Shouldn't be merged if upload data is non-existent.
121 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
122 "some header", NULL
));
125 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_EmptyBody
) {
126 ScopedVector
<UploadElementReader
> element_readers
;
127 scoped_ptr
<UploadDataStream
> body(
128 new ElementsUploadDataStream(element_readers
.Pass(), 0));
129 ASSERT_EQ(OK
, body
->Init(CompletionCallback()));
130 // Shouldn't be merged if upload data is empty.
131 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
132 "some header", body
.get()));
135 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_ChunkedBody
) {
136 const std::string payload
= "123";
137 scoped_ptr
<ChunkedUploadDataStream
> body(new ChunkedUploadDataStream(0));
138 body
->AppendData(payload
.data(), payload
.size(), true);
139 ASSERT_EQ(OK
, body
->Init(TestCompletionCallback().callback()));
140 // Shouldn't be merged if upload data carries chunked data.
141 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
142 "some header", body
.get()));
145 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_FileBody
) {
147 ScopedVector
<UploadElementReader
> element_readers
;
149 // Create an empty temporary file.
150 base::ScopedTempDir temp_dir
;
151 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
152 base::FilePath temp_file_path
;
153 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir
.path(),
156 element_readers
.push_back(
157 new UploadFileElementReader(base::MessageLoopProxy::current().get(),
163 scoped_ptr
<UploadDataStream
> body(
164 new ElementsUploadDataStream(element_readers
.Pass(), 0));
165 TestCompletionCallback callback
;
166 ASSERT_EQ(ERR_IO_PENDING
, body
->Init(callback
.callback()));
167 ASSERT_EQ(OK
, callback
.WaitForResult());
168 // Shouldn't be merged if upload data carries a file, as it's not in-memory.
169 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
170 "some header", body
.get()));
172 // UploadFileElementReaders may post clean-up tasks on destruction.
173 base::RunLoop().RunUntilIdle();
176 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory
) {
177 ScopedVector
<UploadElementReader
> element_readers
;
178 const std::string payload
= "123";
179 element_readers
.push_back(new UploadBytesElementReader(
180 payload
.data(), payload
.size()));
182 scoped_ptr
<UploadDataStream
> body(
183 new ElementsUploadDataStream(element_readers
.Pass(), 0));
184 ASSERT_EQ(OK
, body
->Init(CompletionCallback()));
185 // Yes, should be merged if the in-memory body is small here.
186 ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
187 "some header", body
.get()));
190 TEST(HttpStreamParser
, ShouldMergeRequestHeadersAndBody_LargeBodyInMemory
) {
191 ScopedVector
<UploadElementReader
> element_readers
;
192 const std::string
payload(10000, 'a'); // 'a' x 10000.
193 element_readers
.push_back(new UploadBytesElementReader(
194 payload
.data(), payload
.size()));
196 scoped_ptr
<UploadDataStream
> body(
197 new ElementsUploadDataStream(element_readers
.Pass(), 0));
198 ASSERT_EQ(OK
, body
->Init(CompletionCallback()));
199 // Shouldn't be merged if the in-memory body is large here.
200 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
201 "some header", body
.get()));
204 // Test to ensure the HttpStreamParser state machine does not get confused
205 // when sending a request with a chunked body with only one chunk that becomes
206 // available asynchronously.
207 TEST(HttpStreamParser
, AsyncSingleChunkAndAsyncSocket
) {
208 static const char kChunk
[] = "Chunk";
210 MockWrite writes
[] = {
212 "GET /one.html HTTP/1.1\r\n"
213 "Transfer-Encoding: chunked\r\n\r\n"),
214 MockWrite(ASYNC
, 1, "5\r\nChunk\r\n"),
215 MockWrite(ASYNC
, 2, "0\r\n\r\n"),
218 // The size of the response body, as reflected in the Content-Length of the
220 static const int kBodySize
= 8;
223 MockRead(ASYNC
, 3, "HTTP/1.1 200 OK\r\n"),
224 MockRead(ASYNC
, 4, "Content-Length: 8\r\n\r\n"),
225 MockRead(ASYNC
, 5, "one.html"),
226 MockRead(SYNCHRONOUS
, 0, 6), // EOF
229 ChunkedUploadDataStream
upload_stream(0);
230 ASSERT_EQ(OK
, upload_stream
.Init(TestCompletionCallback().callback()));
232 DeterministicSocketData
data(reads
, arraysize(reads
), writes
,
234 scoped_ptr
<ClientSocketHandle
> socket_handle
=
235 CreateConnectedSocketHandle(&data
);
237 HttpRequestInfo request_info
;
238 request_info
.method
= "GET";
239 request_info
.url
= GURL("http://localhost");
240 request_info
.upload_data_stream
= &upload_stream
;
242 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
243 HttpStreamParser
parser(socket_handle
.get(), &request_info
, read_buffer
.get(),
246 HttpRequestHeaders request_headers
;
247 request_headers
.SetHeader("Transfer-Encoding", "chunked");
249 HttpResponseInfo response_info
;
250 TestCompletionCallback callback
;
251 // This will attempt to Write() the initial request and headers, which will
252 // complete asynchronously.
253 ASSERT_EQ(ERR_IO_PENDING
,
254 parser
.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers
,
255 &response_info
, callback
.callback()));
257 // Complete the initial request write.
259 ASSERT_FALSE(callback
.have_result());
261 // Now append the only chunk.
262 upload_stream
.AppendData(kChunk
, arraysize(kChunk
) - 1, true);
265 ASSERT_FALSE(callback
.have_result());
267 // Write the trailer.
269 ASSERT_TRUE(callback
.have_result());
270 ASSERT_EQ(OK
, callback
.WaitForResult());
272 // Attempt to read the response status and the response headers.
273 ASSERT_EQ(ERR_IO_PENDING
, parser
.ReadResponseHeaders(callback
.callback()));
275 ASSERT_TRUE(callback
.have_result());
276 ASSERT_GT(callback
.WaitForResult(), 0);
278 // Finally, attempt to read the response body.
279 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
280 ASSERT_EQ(ERR_IO_PENDING
,
281 parser
.ReadResponseBody(body_buffer
.get(), kBodySize
,
282 callback
.callback()));
284 ASSERT_TRUE(callback
.have_result());
285 ASSERT_EQ(kBodySize
, callback
.WaitForResult());
288 // Test to ensure the HttpStreamParser state machine does not get confused
289 // when sending a request with a chunked body with only one chunk that is
290 // available synchronously.
291 TEST(HttpStreamParser
, SyncSingleChunkAndAsyncSocket
) {
292 static const char kChunk
[] = "Chunk";
294 MockWrite writes
[] = {
296 "GET /one.html HTTP/1.1\r\n"
297 "Transfer-Encoding: chunked\r\n\r\n"),
298 MockWrite(ASYNC
, 1, "5\r\nChunk\r\n"),
299 MockWrite(ASYNC
, 2, "0\r\n\r\n"),
302 // The size of the response body, as reflected in the Content-Length of the
304 static const int kBodySize
= 8;
307 MockRead(ASYNC
, 3, "HTTP/1.1 200 OK\r\n"),
308 MockRead(ASYNC
, 4, "Content-Length: 8\r\n\r\n"),
309 MockRead(ASYNC
, 5, "one.html"),
310 MockRead(SYNCHRONOUS
, 0, 6), // EOF
313 ChunkedUploadDataStream
upload_stream(0);
314 ASSERT_EQ(OK
, upload_stream
.Init(TestCompletionCallback().callback()));
315 // Append the only chunk.
316 upload_stream
.AppendData(kChunk
, arraysize(kChunk
) - 1, true);
318 DeterministicSocketData
data(reads
, arraysize(reads
), writes
,
320 scoped_ptr
<ClientSocketHandle
> socket_handle
=
321 CreateConnectedSocketHandle(&data
);
323 HttpRequestInfo request_info
;
324 request_info
.method
= "GET";
325 request_info
.url
= GURL("http://localhost");
326 request_info
.upload_data_stream
= &upload_stream
;
328 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
329 HttpStreamParser
parser(socket_handle
.get(), &request_info
, read_buffer
.get(),
332 HttpRequestHeaders request_headers
;
333 request_headers
.SetHeader("Transfer-Encoding", "chunked");
335 HttpResponseInfo response_info
;
336 TestCompletionCallback callback
;
337 // This will attempt to Write() the initial request and headers, which will
338 // complete asynchronously.
339 ASSERT_EQ(ERR_IO_PENDING
,
340 parser
.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers
,
341 &response_info
, callback
.callback()));
343 // Write the request and the only chunk.
346 // Write the trailer.
348 ASSERT_TRUE(callback
.have_result());
349 ASSERT_EQ(OK
, callback
.WaitForResult());
351 // Attempt to read the response status and the response headers.
352 ASSERT_EQ(ERR_IO_PENDING
, parser
.ReadResponseHeaders(callback
.callback()));
354 ASSERT_TRUE(callback
.have_result());
355 ASSERT_GT(callback
.WaitForResult(), 0);
357 // Finally, attempt to read the response body.
358 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
359 ASSERT_EQ(ERR_IO_PENDING
,
360 parser
.ReadResponseBody(body_buffer
.get(), kBodySize
,
361 callback
.callback()));
363 ASSERT_TRUE(callback
.have_result());
364 ASSERT_EQ(kBodySize
, callback
.WaitForResult());
367 // Test to ensure the HttpStreamParser state machine does not get confused
368 // when sending a request with a chunked body, where chunks become available
369 // asynchronously, over a socket where writes may also complete
371 // This is a regression test for http://crbug.com/132243
372 TEST(HttpStreamParser
, AsyncChunkAndAsyncSocketWithMultipleChunks
) {
373 // The chunks that will be written in the request, as reflected in the
375 static const char kChunk1
[] = "Chunk 1";
376 static const char kChunk2
[] = "Chunky 2";
377 static const char kChunk3
[] = "Test 3";
379 MockWrite writes
[] = {
381 "GET /one.html HTTP/1.1\r\n"
382 "Transfer-Encoding: chunked\r\n\r\n"),
383 MockWrite(ASYNC
, 1, "7\r\nChunk 1\r\n"),
384 MockWrite(ASYNC
, 2, "8\r\nChunky 2\r\n"),
385 MockWrite(ASYNC
, 3, "6\r\nTest 3\r\n"),
386 MockWrite(ASYNC
, 4, "0\r\n\r\n"),
389 // The size of the response body, as reflected in the Content-Length of the
391 static const int kBodySize
= 8;
394 MockRead(ASYNC
, 5, "HTTP/1.1 200 OK\r\n"),
395 MockRead(ASYNC
, 6, "Content-Length: 8\r\n\r\n"),
396 MockRead(ASYNC
, 7, "one.html"),
397 MockRead(SYNCHRONOUS
, 0, 8), // EOF
400 ChunkedUploadDataStream
upload_stream(0);
401 upload_stream
.AppendData(kChunk1
, arraysize(kChunk1
) - 1, false);
402 ASSERT_EQ(OK
, upload_stream
.Init(TestCompletionCallback().callback()));
404 DeterministicSocketData
data(reads
, arraysize(reads
), writes
,
406 scoped_ptr
<ClientSocketHandle
> socket_handle
=
407 CreateConnectedSocketHandle(&data
);
409 HttpRequestInfo request_info
;
410 request_info
.method
= "GET";
411 request_info
.url
= GURL("http://localhost");
412 request_info
.upload_data_stream
= &upload_stream
;
414 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
415 HttpStreamParser
parser(
416 socket_handle
.get(), &request_info
, read_buffer
.get(), BoundNetLog());
418 HttpRequestHeaders request_headers
;
419 request_headers
.SetHeader("Transfer-Encoding", "chunked");
421 HttpResponseInfo response_info
;
422 TestCompletionCallback callback
;
423 // This will attempt to Write() the initial request and headers, which will
424 // complete asynchronously.
425 ASSERT_EQ(ERR_IO_PENDING
,
426 parser
.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers
,
427 &response_info
, callback
.callback()));
429 // Complete the initial request write. Additionally, this should enqueue the
432 ASSERT_FALSE(callback
.have_result());
434 // Now append another chunk (while the first write is still pending), which
435 // should not confuse the state machine.
436 upload_stream
.AppendData(kChunk2
, arraysize(kChunk2
) - 1, false);
437 ASSERT_FALSE(callback
.have_result());
439 // Complete writing the first chunk, which should then enqueue the second
440 // chunk for writing and return, because it is set to complete
443 ASSERT_FALSE(callback
.have_result());
445 // Complete writing the second chunk. However, because no chunks are
446 // available yet, no further writes should be called until a new chunk is
449 ASSERT_FALSE(callback
.have_result());
451 // Add the final chunk. This will enqueue another write, but it will not
452 // complete due to the async nature.
453 upload_stream
.AppendData(kChunk3
, arraysize(kChunk3
) - 1, true);
454 ASSERT_FALSE(callback
.have_result());
456 // Finalize writing the last chunk, which will enqueue the trailer.
458 ASSERT_FALSE(callback
.have_result());
460 // Finalize writing the trailer.
462 ASSERT_TRUE(callback
.have_result());
463 ASSERT_EQ(OK
, callback
.WaitForResult());
465 // Attempt to read the response status and the response headers.
466 ASSERT_EQ(ERR_IO_PENDING
, parser
.ReadResponseHeaders(callback
.callback()));
468 ASSERT_TRUE(callback
.have_result());
469 ASSERT_GT(callback
.WaitForResult(), 0);
471 // Finally, attempt to read the response body.
472 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
473 ASSERT_EQ(ERR_IO_PENDING
,
474 parser
.ReadResponseBody(body_buffer
.get(), kBodySize
,
475 callback
.callback()));
477 ASSERT_TRUE(callback
.have_result());
478 ASSERT_EQ(kBodySize
, callback
.WaitForResult());
481 // Test to ensure the HttpStreamParser state machine does not get confused
482 // when there's only one "chunk" with 0 bytes, and is received from the
483 // UploadStream only after sending the request headers successfully.
484 TEST(HttpStreamParser
, AsyncEmptyChunkedUpload
) {
485 MockWrite writes
[] = {
487 "GET /one.html HTTP/1.1\r\n"
488 "Transfer-Encoding: chunked\r\n\r\n"),
489 MockWrite(ASYNC
, 1, "0\r\n\r\n"),
492 // The size of the response body, as reflected in the Content-Length of the
494 const int kBodySize
= 8;
497 MockRead(ASYNC
, 2, "HTTP/1.1 200 OK\r\n"),
498 MockRead(ASYNC
, 3, "Content-Length: 8\r\n\r\n"),
499 MockRead(ASYNC
, 4, "one.html"),
500 MockRead(SYNCHRONOUS
, 0, 5), // EOF
503 ChunkedUploadDataStream
upload_stream(0);
504 ASSERT_EQ(OK
, upload_stream
.Init(TestCompletionCallback().callback()));
506 DeterministicSocketData
data(reads
, arraysize(reads
), writes
,
508 scoped_ptr
<ClientSocketHandle
> socket_handle
=
509 CreateConnectedSocketHandle(&data
);
511 HttpRequestInfo request_info
;
512 request_info
.method
= "GET";
513 request_info
.url
= GURL("http://localhost");
514 request_info
.upload_data_stream
= &upload_stream
;
516 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
517 HttpStreamParser
parser(socket_handle
.get(), &request_info
, read_buffer
.get(),
520 HttpRequestHeaders request_headers
;
521 request_headers
.SetHeader("Transfer-Encoding", "chunked");
523 HttpResponseInfo response_info
;
524 TestCompletionCallback callback
;
525 // This will attempt to Write() the initial request and headers, which will
526 // complete asynchronously.
527 ASSERT_EQ(ERR_IO_PENDING
,
528 parser
.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers
,
529 &response_info
, callback
.callback()));
531 // Complete writing the request headers.
533 ASSERT_FALSE(callback
.have_result());
535 // Now append the terminal 0-byte "chunk".
536 upload_stream
.AppendData(nullptr, 0, true);
537 ASSERT_FALSE(callback
.have_result());
539 // Finalize writing the trailer.
541 ASSERT_TRUE(callback
.have_result());
542 ASSERT_EQ(OK
, callback
.WaitForResult());
544 // Attempt to read the response status and the response headers.
545 ASSERT_EQ(ERR_IO_PENDING
, parser
.ReadResponseHeaders(callback
.callback()));
547 ASSERT_TRUE(callback
.have_result());
548 ASSERT_GT(callback
.WaitForResult(), 0);
550 // Finally, attempt to read the response body.
551 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
552 ASSERT_EQ(ERR_IO_PENDING
,
553 parser
.ReadResponseBody(body_buffer
.get(), kBodySize
,
554 callback
.callback()));
556 ASSERT_TRUE(callback
.have_result());
557 ASSERT_EQ(kBodySize
, callback
.WaitForResult());
560 // Test to ensure the HttpStreamParser state machine does not get confused
561 // when there's only one "chunk" with 0 bytes, which was already appended before
562 // the request was started.
563 TEST(HttpStreamParser
, SyncEmptyChunkedUpload
) {
564 MockWrite writes
[] = {
566 "GET /one.html HTTP/1.1\r\n"
567 "Transfer-Encoding: chunked\r\n\r\n"),
568 MockWrite(ASYNC
, 1, "0\r\n\r\n"),
571 // The size of the response body, as reflected in the Content-Length of the
573 const int kBodySize
= 8;
576 MockRead(ASYNC
, 2, "HTTP/1.1 200 OK\r\n"),
577 MockRead(ASYNC
, 3, "Content-Length: 8\r\n\r\n"),
578 MockRead(ASYNC
, 4, "one.html"),
579 MockRead(SYNCHRONOUS
, 0, 5), // EOF
582 ChunkedUploadDataStream
upload_stream(0);
583 ASSERT_EQ(OK
, upload_stream
.Init(TestCompletionCallback().callback()));
584 // Append final empty chunk.
585 upload_stream
.AppendData(nullptr, 0, true);
587 DeterministicSocketData
data(reads
, arraysize(reads
), writes
,
589 scoped_ptr
<ClientSocketHandle
> socket_handle
=
590 CreateConnectedSocketHandle(&data
);
592 HttpRequestInfo request_info
;
593 request_info
.method
= "GET";
594 request_info
.url
= GURL("http://localhost");
595 request_info
.upload_data_stream
= &upload_stream
;
597 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
598 HttpStreamParser
parser(socket_handle
.get(), &request_info
, read_buffer
.get(),
601 HttpRequestHeaders request_headers
;
602 request_headers
.SetHeader("Transfer-Encoding", "chunked");
604 HttpResponseInfo response_info
;
605 TestCompletionCallback callback
;
606 // This will attempt to Write() the initial request and headers, which will
607 // complete asynchronously.
608 ASSERT_EQ(ERR_IO_PENDING
,
609 parser
.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers
,
610 &response_info
, callback
.callback()));
612 // Complete writing the request headers and body.
614 ASSERT_TRUE(callback
.have_result());
615 ASSERT_EQ(OK
, callback
.WaitForResult());
617 // Attempt to read the response status and the response headers.
618 ASSERT_EQ(ERR_IO_PENDING
, parser
.ReadResponseHeaders(callback
.callback()));
620 ASSERT_TRUE(callback
.have_result());
621 ASSERT_GT(callback
.WaitForResult(), 0);
623 // Finally, attempt to read the response body.
624 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
625 ASSERT_EQ(ERR_IO_PENDING
,
626 parser
.ReadResponseBody(body_buffer
.get(), kBodySize
,
627 callback
.callback()));
629 ASSERT_TRUE(callback
.have_result());
630 ASSERT_EQ(kBodySize
, callback
.WaitForResult());
633 TEST(HttpStreamParser
, TruncatedHeaders
) {
634 MockRead truncated_status_reads
[] = {
635 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 20"),
636 MockRead(SYNCHRONOUS
, 0, 2), // EOF
639 MockRead truncated_after_status_reads
[] = {
640 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Ok\r\n"),
641 MockRead(SYNCHRONOUS
, 0, 2), // EOF
644 MockRead truncated_in_header_reads
[] = {
645 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Ok\r\nHead"),
646 MockRead(SYNCHRONOUS
, 0, 2), // EOF
649 MockRead truncated_after_header_reads
[] = {
650 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n"),
651 MockRead(SYNCHRONOUS
, 0, 2), // EOF
654 MockRead truncated_after_final_newline_reads
[] = {
655 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r"),
656 MockRead(SYNCHRONOUS
, 0, 2), // EOF
659 MockRead not_truncated_reads
[] = {
660 MockRead(SYNCHRONOUS
, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r\n"),
661 MockRead(SYNCHRONOUS
, 0, 2), // EOF
664 MockRead
* reads
[] = {
665 truncated_status_reads
,
666 truncated_after_status_reads
,
667 truncated_in_header_reads
,
668 truncated_after_header_reads
,
669 truncated_after_final_newline_reads
,
673 MockWrite writes
[] = {
674 MockWrite(SYNCHRONOUS
, 0, "GET / HTTP/1.1\r\n\r\n"),
683 for (size_t protocol
= 0; protocol
< NUM_PROTOCOLS
; protocol
++) {
684 SCOPED_TRACE(protocol
);
686 for (size_t i
= 0; i
< arraysize(reads
); i
++) {
688 DeterministicSocketData
data(reads
[i
], 2, writes
, arraysize(writes
));
689 data
.set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
692 scoped_ptr
<DeterministicMockTCPClientSocket
> transport(
693 new DeterministicMockTCPClientSocket(NULL
, &data
));
694 data
.set_delegate(transport
->AsWeakPtr());
696 TestCompletionCallback callback
;
697 int rv
= transport
->Connect(callback
.callback());
700 scoped_ptr
<ClientSocketHandle
> socket_handle(new ClientSocketHandle
);
701 socket_handle
->SetSocket(transport
.Pass());
703 HttpRequestInfo request_info
;
704 request_info
.method
= "GET";
705 if (protocol
== HTTP
) {
706 request_info
.url
= GURL("http://localhost");
708 request_info
.url
= GURL("https://localhost");
710 request_info
.load_flags
= LOAD_NORMAL
;
712 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
713 HttpStreamParser
parser(
714 socket_handle
.get(), &request_info
, read_buffer
.get(), BoundNetLog());
716 HttpRequestHeaders request_headers
;
717 HttpResponseInfo response_info
;
718 rv
= parser
.SendRequest("GET / HTTP/1.1\r\n", request_headers
,
719 &response_info
, callback
.callback());
722 rv
= parser
.ReadResponseHeaders(callback
.callback());
723 if (i
== arraysize(reads
) - 1) {
725 EXPECT_TRUE(response_info
.headers
.get());
727 if (protocol
== HTTP
) {
728 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
729 EXPECT_TRUE(response_info
.headers
.get());
731 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED
, rv
);
732 EXPECT_FALSE(response_info
.headers
.get());
739 // Confirm that on 101 response, the headers are parsed but the data that
740 // follows remains in the buffer.
741 TEST(HttpStreamParser
, Websocket101Response
) {
743 MockRead(SYNCHRONOUS
, 1,
744 "HTTP/1.1 101 Switching Protocols\r\n"
745 "Upgrade: websocket\r\n"
746 "Connection: Upgrade\r\n"
748 "a fake websocket frame"),
751 MockWrite writes
[] = {
752 MockWrite(SYNCHRONOUS
, 0, "GET / HTTP/1.1\r\n\r\n"),
755 DeterministicSocketData
data(reads
, arraysize(reads
),
756 writes
, arraysize(writes
));
757 data
.set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
760 scoped_ptr
<DeterministicMockTCPClientSocket
> transport(
761 new DeterministicMockTCPClientSocket(NULL
, &data
));
762 data
.set_delegate(transport
->AsWeakPtr());
764 TestCompletionCallback callback
;
765 int rv
= transport
->Connect(callback
.callback());
768 scoped_ptr
<ClientSocketHandle
> socket_handle(new ClientSocketHandle
);
769 socket_handle
->SetSocket(transport
.Pass());
771 HttpRequestInfo request_info
;
772 request_info
.method
= "GET";
773 request_info
.url
= GURL("http://localhost");
774 request_info
.load_flags
= LOAD_NORMAL
;
776 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
777 HttpStreamParser
parser(
778 socket_handle
.get(), &request_info
, read_buffer
.get(), BoundNetLog());
780 HttpRequestHeaders request_headers
;
781 HttpResponseInfo response_info
;
782 rv
= parser
.SendRequest("GET / HTTP/1.1\r\n", request_headers
,
783 &response_info
, callback
.callback());
786 rv
= parser
.ReadResponseHeaders(callback
.callback());
788 ASSERT_TRUE(response_info
.headers
.get());
789 EXPECT_EQ(101, response_info
.headers
->response_code());
790 EXPECT_TRUE(response_info
.headers
->HasHeaderValue("Connection", "Upgrade"));
791 EXPECT_TRUE(response_info
.headers
->HasHeaderValue("Upgrade", "websocket"));
792 EXPECT_EQ(read_buffer
->capacity(), read_buffer
->offset());
793 EXPECT_EQ("a fake websocket frame",
794 base::StringPiece(read_buffer
->StartOfBuffer(),
795 read_buffer
->capacity()));
798 // Helper class for constructing HttpStreamParser and running GET requests.
799 class SimpleGetRunner
{
801 SimpleGetRunner() : read_buffer_(new GrowableIOBuffer
), sequence_number_(0) {
802 writes_
.push_back(MockWrite(
803 SYNCHRONOUS
, sequence_number_
++, "GET / HTTP/1.1\r\n\r\n"));
806 HttpStreamParser
* parser() { return parser_
.get(); }
807 GrowableIOBuffer
* read_buffer() { return read_buffer_
.get(); }
808 HttpResponseInfo
* response_info() { return &response_info_
; }
810 void AddInitialData(const std::string
& data
) {
811 int offset
= read_buffer_
->offset();
812 int size
= data
.size();
813 read_buffer_
->SetCapacity(offset
+ size
);
814 memcpy(read_buffer_
->StartOfBuffer() + offset
, data
.data(), size
);
815 read_buffer_
->set_offset(offset
+ size
);
818 void AddRead(const std::string
& data
) {
819 reads_
.push_back(MockRead(SYNCHRONOUS
, sequence_number_
++, data
.data()));
822 void SetupParserAndSendRequest() {
823 reads_
.push_back(MockRead(SYNCHRONOUS
, 0, sequence_number_
++)); // EOF
825 socket_handle_
.reset(new ClientSocketHandle
);
826 data_
.reset(new DeterministicSocketData(
827 &reads_
.front(), reads_
.size(), &writes_
.front(), writes_
.size()));
828 data_
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
829 data_
->SetStop(reads_
.size() + writes_
.size());
831 transport_
.reset(new DeterministicMockTCPClientSocket(NULL
, data_
.get()));
832 data_
->set_delegate(transport_
->AsWeakPtr());
834 TestCompletionCallback callback
;
835 int rv
= transport_
->Connect(callback
.callback());
836 rv
= callback
.GetResult(rv
);
839 socket_handle_
->SetSocket(transport_
.Pass());
841 request_info_
.method
= "GET";
842 request_info_
.url
= GURL("http://localhost");
843 request_info_
.load_flags
= LOAD_NORMAL
;
845 parser_
.reset(new HttpStreamParser(
846 socket_handle_
.get(), &request_info_
, read_buffer(), BoundNetLog()));
848 rv
= parser_
->SendRequest("GET / HTTP/1.1\r\n", request_headers_
,
849 &response_info_
, callback
.callback());
854 TestCompletionCallback callback
;
855 EXPECT_EQ(OK
, parser_
->ReadResponseHeaders(callback
.callback()));
858 void ReadBody(int user_buf_len
, int* read_lengths
) {
859 TestCompletionCallback callback
;
860 scoped_refptr
<IOBuffer
> buffer
= new IOBuffer(user_buf_len
);
864 rv
= parser_
->ReadResponseBody(
865 buffer
.get(), user_buf_len
, callback
.callback());
866 EXPECT_EQ(read_lengths
[i
], rv
);
874 HttpRequestHeaders request_headers_
;
875 HttpResponseInfo response_info_
;
876 HttpRequestInfo request_info_
;
877 scoped_refptr
<GrowableIOBuffer
> read_buffer_
;
878 std::vector
<MockRead
> reads_
;
879 std::vector
<MockWrite
> writes_
;
880 scoped_ptr
<ClientSocketHandle
> socket_handle_
;
881 scoped_ptr
<DeterministicSocketData
> data_
;
882 scoped_ptr
<DeterministicMockTCPClientSocket
> transport_
;
883 scoped_ptr
<HttpStreamParser
> parser_
;
884 int sequence_number_
;
887 // Test that HTTP/0.9 response size is correctly calculated.
888 TEST(HttpStreamParser
, ReceivedBytesNoHeaders
) {
889 std::string response
= "hello\r\nworld\r\n";
891 SimpleGetRunner get_runner
;
892 get_runner
.AddRead(response
);
893 get_runner
.SetupParserAndSendRequest();
894 get_runner
.ReadHeaders();
895 EXPECT_EQ(0, get_runner
.parser()->received_bytes());
896 int response_size
= response
.size();
897 int read_lengths
[] = {response_size
, 0};
898 get_runner
.ReadBody(response_size
, read_lengths
);
899 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
902 // Test basic case where there is no keep-alive or extra data from the socket,
903 // and the entire response is received in a single read.
904 TEST(HttpStreamParser
, ReceivedBytesNormal
) {
905 std::string headers
= "HTTP/1.1 200 OK\r\n"
906 "Content-Length: 7\r\n\r\n";
907 std::string body
= "content";
908 std::string response
= headers
+ body
;
910 SimpleGetRunner get_runner
;
911 get_runner
.AddRead(response
);
912 get_runner
.SetupParserAndSendRequest();
913 get_runner
.ReadHeaders();
914 int64 headers_size
= headers
.size();
915 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
916 int body_size
= body
.size();
917 int read_lengths
[] = {body_size
, 0};
918 get_runner
.ReadBody(body_size
, read_lengths
);
919 int64 response_size
= response
.size();
920 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
923 // Test that bytes that represent "next" response are not counted
924 // as current response "received_bytes".
925 TEST(HttpStreamParser
, ReceivedBytesExcludesNextResponse
) {
926 std::string headers
= "HTTP/1.1 200 OK\r\n"
927 "Content-Length: 8\r\n\r\n";
928 std::string body
= "content8";
929 std::string response
= headers
+ body
;
930 std::string next_response
= "HTTP/1.1 200 OK\r\n\r\nFOO";
931 std::string data
= response
+ next_response
;
933 SimpleGetRunner get_runner
;
934 get_runner
.AddRead(data
);
935 get_runner
.SetupParserAndSendRequest();
936 get_runner
.ReadHeaders();
937 EXPECT_EQ(39, get_runner
.parser()->received_bytes());
938 int64 headers_size
= headers
.size();
939 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
940 int body_size
= body
.size();
941 int read_lengths
[] = {body_size
, 0};
942 get_runner
.ReadBody(body_size
, read_lengths
);
943 int64 response_size
= response
.size();
944 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
945 int64 next_response_size
= next_response
.size();
946 EXPECT_EQ(next_response_size
, get_runner
.read_buffer()->offset());
949 // Test that "received_bytes" calculation works fine when last read
950 // contains more data than requested by user.
951 // We send data in two reads:
952 // 1) Headers + beginning of response
953 // 2) remaining part of response + next response start
954 // We setup user read buffer so it fully accepts the beginnig of response
955 // body, but it is larger that remaining part of body.
956 TEST(HttpStreamParser
, ReceivedBytesMultiReadExcludesNextResponse
) {
957 std::string headers
= "HTTP/1.1 200 OK\r\n"
958 "Content-Length: 36\r\n\r\n";
959 int64 user_buf_len
= 32;
960 std::string body_start
= std::string(user_buf_len
, '#');
961 int body_start_size
= body_start
.size();
962 EXPECT_EQ(user_buf_len
, body_start_size
);
963 std::string response_start
= headers
+ body_start
;
964 std::string body_end
= "abcd";
965 std::string next_response
= "HTTP/1.1 200 OK\r\n\r\nFOO";
966 std::string response_end
= body_end
+ next_response
;
968 SimpleGetRunner get_runner
;
969 get_runner
.AddRead(response_start
);
970 get_runner
.AddRead(response_end
);
971 get_runner
.SetupParserAndSendRequest();
972 get_runner
.ReadHeaders();
973 int64 headers_size
= headers
.size();
974 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
975 int body_end_size
= body_end
.size();
976 int read_lengths
[] = {body_start_size
, body_end_size
, 0};
977 get_runner
.ReadBody(body_start_size
, read_lengths
);
978 int64 response_size
= response_start
.size() + body_end_size
;
979 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
980 int64 next_response_size
= next_response
.size();
981 EXPECT_EQ(next_response_size
, get_runner
.read_buffer()->offset());
984 // Test that "received_bytes" calculation works fine when there is no
985 // network activity at all; that is when all data is read from read buffer.
986 // In this case read buffer contains two responses. We expect that only
987 // bytes that correspond to the first one are taken into account.
988 TEST(HttpStreamParser
, ReceivedBytesFromReadBufExcludesNextResponse
) {
989 std::string headers
= "HTTP/1.1 200 OK\r\n"
990 "Content-Length: 7\r\n\r\n";
991 std::string body
= "content";
992 std::string response
= headers
+ body
;
993 std::string next_response
= "HTTP/1.1 200 OK\r\n\r\nFOO";
994 std::string data
= response
+ next_response
;
996 SimpleGetRunner get_runner
;
997 get_runner
.AddInitialData(data
);
998 get_runner
.SetupParserAndSendRequest();
999 get_runner
.ReadHeaders();
1000 int64 headers_size
= headers
.size();
1001 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
1002 int body_size
= body
.size();
1003 int read_lengths
[] = {body_size
, 0};
1004 get_runner
.ReadBody(body_size
, read_lengths
);
1005 int64 response_size
= response
.size();
1006 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
1007 int64 next_response_size
= next_response
.size();
1008 EXPECT_EQ(next_response_size
, get_runner
.read_buffer()->offset());
1011 // Test calculating "received_bytes" when part of request has been already
1012 // loaded and placed to read buffer by previous stream parser.
1013 TEST(HttpStreamParser
, ReceivedBytesUseReadBuf
) {
1014 std::string buffer
= "HTTP/1.1 200 OK\r\n";
1015 std::string remaining_headers
= "Content-Length: 7\r\n\r\n";
1016 int64 headers_size
= buffer
.size() + remaining_headers
.size();
1017 std::string body
= "content";
1018 std::string response
= remaining_headers
+ body
;
1020 SimpleGetRunner get_runner
;
1021 get_runner
.AddInitialData(buffer
);
1022 get_runner
.AddRead(response
);
1023 get_runner
.SetupParserAndSendRequest();
1024 get_runner
.ReadHeaders();
1025 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
1026 int body_size
= body
.size();
1027 int read_lengths
[] = {body_size
, 0};
1028 get_runner
.ReadBody(body_size
, read_lengths
);
1029 EXPECT_EQ(headers_size
+ body_size
, get_runner
.parser()->received_bytes());
1030 EXPECT_EQ(0, get_runner
.read_buffer()->offset());
1033 // Test the case when the resulting read_buf contains both unused bytes and
1034 // bytes ejected by chunked-encoding filter.
1035 TEST(HttpStreamParser
, ReceivedBytesChunkedTransferExcludesNextResponse
) {
1036 std::string response
= "HTTP/1.1 200 OK\r\n"
1037 "Transfer-Encoding: chunked\r\n\r\n"
1042 std::string next_response
= "foo bar\r\n";
1043 std::string data
= response
+ next_response
;
1045 SimpleGetRunner get_runner
;
1046 get_runner
.AddInitialData(data
);
1047 get_runner
.SetupParserAndSendRequest();
1048 get_runner
.ReadHeaders();
1049 int read_lengths
[] = {4, 3, 6, 2, 6, 0};
1050 get_runner
.ReadBody(7, read_lengths
);
1051 int64 response_size
= response
.size();
1052 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
1053 int64 next_response_size
= next_response
.size();
1054 EXPECT_EQ(next_response_size
, get_runner
.read_buffer()->offset());
1057 // Test that data transfered in multiple reads is correctly processed.
1058 // We feed data into 4-bytes reads. Also we set length of read
1059 // buffer to 5-bytes to test all possible buffer misaligments.
1060 TEST(HttpStreamParser
, ReceivedBytesMultipleReads
) {
1061 std::string headers
= "HTTP/1.1 200 OK\r\n"
1062 "Content-Length: 33\r\n\r\n";
1063 std::string body
= "foo bar baz\r\n"
1064 "sputnik mir babushka";
1065 std::string response
= headers
+ body
;
1067 size_t receive_length
= 4;
1068 std::vector
<std::string
> blocks
;
1069 for (size_t i
= 0; i
< response
.size(); i
+= receive_length
) {
1070 size_t length
= std::min(receive_length
, response
.size() - i
);
1071 blocks
.push_back(response
.substr(i
, length
));
1074 SimpleGetRunner get_runner
;
1075 for (std::vector
<std::string
>::size_type i
= 0; i
< blocks
.size(); ++i
)
1076 get_runner
.AddRead(blocks
[i
]);
1077 get_runner
.SetupParserAndSendRequest();
1078 get_runner
.ReadHeaders();
1079 int64 headers_size
= headers
.size();
1080 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
1081 int read_lengths
[] = {1, 4, 4, 4, 4, 4, 4, 4, 4, 0};
1082 get_runner
.ReadBody(receive_length
+ 1, read_lengths
);
1083 int64 response_size
= response
.size();
1084 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
1087 // Test that "continue" HTTP header is counted as "received_bytes".
1088 TEST(HttpStreamParser
, ReceivedBytesIncludesContinueHeader
) {
1089 std::string status100
= "HTTP/1.1 100 OK\r\n\r\n";
1090 std::string headers
= "HTTP/1.1 200 OK\r\n"
1091 "Content-Length: 7\r\n\r\n";
1092 int64 headers_size
= status100
.size() + headers
.size();
1093 std::string body
= "content";
1094 std::string response
= headers
+ body
;
1096 SimpleGetRunner get_runner
;
1097 get_runner
.AddRead(status100
);
1098 get_runner
.AddRead(response
);
1099 get_runner
.SetupParserAndSendRequest();
1100 get_runner
.ReadHeaders();
1101 EXPECT_EQ(100, get_runner
.response_info()->headers
->response_code());
1102 int64 status100_size
= status100
.size();
1103 EXPECT_EQ(status100_size
, get_runner
.parser()->received_bytes());
1104 get_runner
.ReadHeaders();
1105 EXPECT_EQ(200, get_runner
.response_info()->headers
->response_code());
1106 EXPECT_EQ(headers_size
, get_runner
.parser()->received_bytes());
1107 int64 response_size
= headers_size
+ body
.size();
1108 int body_size
= body
.size();
1109 int read_lengths
[] = {body_size
, 0};
1110 get_runner
.ReadBody(body_size
, read_lengths
);
1111 EXPECT_EQ(response_size
, get_runner
.parser()->received_bytes());
1114 // Test that an HttpStreamParser can be read from after it's received headers
1115 // and data structures owned by its owner have been deleted. This happens
1116 // when a ResponseBodyDrainer is used.
1117 TEST(HttpStreamParser
, ReadAfterUnownedObjectsDestroyed
) {
1118 MockWrite writes
[] = {
1119 MockWrite(SYNCHRONOUS
, 0,
1120 "GET /foo.html HTTP/1.1\r\n\r\n"),
1121 MockWrite(SYNCHRONOUS
, 1, "1"),
1124 const int kBodySize
= 1;
1125 MockRead reads
[] = {
1126 MockRead(SYNCHRONOUS
, 5, "HTTP/1.1 200 OK\r\n"),
1127 MockRead(SYNCHRONOUS
, 6, "Content-Length: 1\r\n\r\n"),
1128 MockRead(SYNCHRONOUS
, 6, "Connection: Keep-Alive\r\n\r\n"),
1129 MockRead(SYNCHRONOUS
, 7, "1"),
1130 MockRead(SYNCHRONOUS
, 0, 8), // EOF
1133 StaticSocketDataProvider
data(reads
, arraysize(reads
), writes
,
1135 data
.set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
1137 scoped_ptr
<MockTCPClientSocket
> transport(
1138 new MockTCPClientSocket(AddressList(), NULL
, &data
));
1140 TestCompletionCallback callback
;
1141 ASSERT_EQ(OK
, transport
->Connect(callback
.callback()));
1143 scoped_ptr
<ClientSocketHandle
> socket_handle(new ClientSocketHandle
);
1144 socket_handle
->SetSocket(transport
.Pass());
1146 scoped_ptr
<HttpRequestInfo
> request_info(new HttpRequestInfo());
1147 request_info
->method
= "GET";
1148 request_info
->url
= GURL("http://somewhere/foo.html");
1150 scoped_refptr
<GrowableIOBuffer
> read_buffer(new GrowableIOBuffer
);
1151 HttpStreamParser
parser(socket_handle
.get(), request_info
.get(),
1152 read_buffer
.get(), BoundNetLog());
1154 scoped_ptr
<HttpRequestHeaders
> request_headers(new HttpRequestHeaders());
1155 scoped_ptr
<HttpResponseInfo
> response_info(new HttpResponseInfo());
1156 ASSERT_EQ(OK
, parser
.SendRequest("GET /foo.html HTTP/1.1\r\n",
1157 *request_headers
, response_info
.get(), callback
.callback()));
1158 ASSERT_EQ(OK
, parser
.ReadResponseHeaders(callback
.callback()));
1160 // If the object that owns the HttpStreamParser is deleted, it takes the
1161 // objects passed to the HttpStreamParser with it.
1162 request_info
.reset();
1163 request_headers
.reset();
1164 response_info
.reset();
1166 scoped_refptr
<IOBuffer
> body_buffer(new IOBuffer(kBodySize
));
1167 ASSERT_EQ(kBodySize
, parser
.ReadResponseBody(
1168 body_buffer
.get(), kBodySize
, callback
.callback()));