blob: 793642641388674c262987937c49d6452a6ffc20 [file] [log] [blame]
[email protected]6db833d12012-01-21 00:45:191// 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.
4
5#include "net/http/http_stream_parser.h"
6
sclittlebe1ccf62015-09-02 19:40:367#include <stdint.h>
[email protected]3cb5fc22013-12-12 19:40:568#include <algorithm>
9#include <string>
dchengc7eeda422015-12-26 03:56:4810#include <utility>
[email protected]3cb5fc22013-12-12 19:40:5611#include <vector>
12
[email protected]57999812013-02-24 05:40:5213#include "base/files/file_path.h"
thestigd8df0332014-09-04 06:33:2914#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2315#include "base/files/scoped_temp_dir.h"
[email protected]4750937f2012-06-15 20:44:2116#include "base/memory/ref_counted.h"
olli.raula6df48b2a2015-11-26 07:40:2217#include "base/memory/scoped_ptr.h"
[email protected]0f972882013-09-20 04:34:2018#include "base/run_loop.h"
[email protected]d069c11a2013-04-13 00:01:5519#include "base/strings/string_piece.h"
[email protected]125ef482013-06-11 18:32:4720#include "base/strings/stringprintf.h"
skyostil4891b25b2015-06-11 11:43:4521#include "base/thread_task_runner_handle.h"
mmenkecbc2b712014-10-09 20:29:0722#include "net/base/chunked_upload_data_stream.h"
23#include "net/base/elements_upload_data_stream.h"
[email protected]4750937f2012-06-15 20:44:2124#include "net/base/io_buffer.h"
[email protected]6db833d12012-01-21 00:45:1925#include "net/base/net_errors.h"
[email protected]4750937f2012-06-15 20:44:2126#include "net/base/test_completion_callback.h"
[email protected]b2d26cfd2012-12-11 10:36:0627#include "net/base/upload_bytes_element_reader.h"
[email protected]b2d26cfd2012-12-11 10:36:0628#include "net/base/upload_file_element_reader.h"
[email protected]4750937f2012-06-15 20:44:2129#include "net/http/http_request_headers.h"
30#include "net/http/http_request_info.h"
[email protected]df8e6382013-11-07 00:19:0631#include "net/http/http_response_headers.h"
[email protected]4750937f2012-06-15 20:44:2132#include "net/http/http_response_info.h"
33#include "net/socket/client_socket_handle.h"
34#include "net/socket/socket_test_util.h"
[email protected]6db833d12012-01-21 00:45:1935#include "testing/gtest/include/gtest/gtest.h"
[email protected]f89276a72013-07-12 06:41:5436#include "url/gurl.h"
[email protected]6db833d12012-01-21 00:45:1937
38namespace net {
39
[email protected]390489b2013-12-09 10:49:0140namespace {
41
[email protected]6db833d12012-01-21 00:45:1942const size_t kOutputSize = 1024; // Just large enough for this test.
43// The number of bytes that can fit in a buffer of kOutputSize.
44const size_t kMaxPayloadSize =
45 kOutputSize - HttpStreamParser::kChunkHeaderFooterSize;
46
mmenke3dc8c88b2015-02-19 15:11:2747// Helper method to create a connected ClientSocketHandle using |data|.
48// Modifies |data|.
49scoped_ptr<ClientSocketHandle> CreateConnectedSocketHandle(
mmenkef22be0ee2015-06-05 15:39:0250 SequencedSocketData* data) {
mmenke3dc8c88b2015-02-19 15:11:2751 data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
52
mmenkef22be0ee2015-06-05 15:39:0253 scoped_ptr<MockTCPClientSocket> socket(
54 new MockTCPClientSocket(net::AddressList(), nullptr, data));
mmenke3dc8c88b2015-02-19 15:11:2755
56 TestCompletionCallback callback;
mmenkef22be0ee2015-06-05 15:39:0257 EXPECT_EQ(OK, socket->Connect(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:2758
59 scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
dchengc7eeda422015-12-26 03:56:4860 socket_handle->SetSocket(std::move(socket));
61 return socket_handle;
mmenke3dc8c88b2015-02-19 15:11:2762}
63
[email protected]6db833d12012-01-21 00:45:1964// The empty payload is how the last chunk is encoded.
65TEST(HttpStreamParser, EncodeChunk_EmptyPayload) {
66 char output[kOutputSize];
67
68 const base::StringPiece kPayload = "";
69 const base::StringPiece kExpected = "0\r\n\r\n";
70 const int num_bytes_written =
71 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
72 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
73 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
74}
75
76TEST(HttpStreamParser, EncodeChunk_ShortPayload) {
77 char output[kOutputSize];
78
79 const std::string kPayload("foo\x00\x11\x22", 6);
80 // 11 = payload size + sizeof("6") + CRLF x 2.
81 const std::string kExpected("6\r\nfoo\x00\x11\x22\r\n", 11);
82 const int num_bytes_written =
83 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
84 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
85 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
86}
87
88TEST(HttpStreamParser, EncodeChunk_LargePayload) {
89 char output[kOutputSize];
90
91 const std::string kPayload(1000, '\xff'); // '\xff' x 1000.
92 // 3E8 = 1000 in hex.
93 const std::string kExpected = "3E8\r\n" + kPayload + "\r\n";
94 const int num_bytes_written =
95 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
96 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
97 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
98}
99
100TEST(HttpStreamParser, EncodeChunk_FullPayload) {
101 char output[kOutputSize];
102
103 const std::string kPayload(kMaxPayloadSize, '\xff');
104 // 3F4 = 1012 in hex.
105 const std::string kExpected = "3F4\r\n" + kPayload + "\r\n";
106 const int num_bytes_written =
107 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
108 ASSERT_EQ(kExpected.size(), static_cast<size_t>(num_bytes_written));
109 EXPECT_EQ(kExpected, base::StringPiece(output, num_bytes_written));
110}
111
112TEST(HttpStreamParser, EncodeChunk_TooLargePayload) {
113 char output[kOutputSize];
114
115 // The payload is one byte larger the output buffer size.
116 const std::string kPayload(kMaxPayloadSize + 1, '\xff');
117 const int num_bytes_written =
118 HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
119 ASSERT_EQ(ERR_INVALID_ARGUMENT, num_bytes_written);
120}
121
[email protected]75577ec2012-01-24 23:41:50122TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_NoBody) {
[email protected]7a1fcff2012-01-24 01:07:49123 // Shouldn't be merged if upload data is non-existent.
[email protected]75577ec2012-01-24 23:41:50124 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
125 "some header", NULL));
[email protected]7a1fcff2012-01-24 01:07:49126}
127
[email protected]75577ec2012-01-24 23:41:50128TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_EmptyBody) {
olli.raula6df48b2a2015-11-26 07:40:22129 std::vector<scoped_ptr<UploadElementReader>> element_readers;
130 scoped_ptr<UploadDataStream> body(make_scoped_ptr(
131 new ElementsUploadDataStream(std::move(element_readers), 0)));
[email protected]4db27d82012-12-20 11:50:24132 ASSERT_EQ(OK, body->Init(CompletionCallback()));
[email protected]7a1fcff2012-01-24 01:07:49133 // Shouldn't be merged if upload data is empty.
[email protected]75577ec2012-01-24 23:41:50134 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
135 "some header", body.get()));
[email protected]7a1fcff2012-01-24 01:07:49136}
137
[email protected]75577ec2012-01-24 23:41:50138TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_ChunkedBody) {
[email protected]7a1fcff2012-01-24 01:07:49139 const std::string payload = "123";
mmenkecbc2b712014-10-09 20:29:07140 scoped_ptr<ChunkedUploadDataStream> body(new ChunkedUploadDataStream(0));
141 body->AppendData(payload.data(), payload.size(), true);
142 ASSERT_EQ(OK, body->Init(TestCompletionCallback().callback()));
[email protected]7a1fcff2012-01-24 01:07:49143 // Shouldn't be merged if upload data carries chunked data.
[email protected]75577ec2012-01-24 23:41:50144 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
145 "some header", body.get()));
[email protected]7a1fcff2012-01-24 01:07:49146}
147
[email protected]75577ec2012-01-24 23:41:50148TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_FileBody) {
wkorman30fe3fd2015-11-06 23:43:42149 // 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(), &temp_file_path));
154
[email protected]0f972882013-09-20 04:34:20155 {
olli.raula6df48b2a2015-11-26 07:40:22156 std::vector<scoped_ptr<UploadElementReader>> element_readers;
[email protected]7a1fcff2012-01-24 01:07:49157
olli.raula6df48b2a2015-11-26 07:40:22158 element_readers.push_back(make_scoped_ptr(
skyostil4891b25b2015-06-11 11:43:45159 new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
olli.raula6df48b2a2015-11-26 07:40:22160 temp_file_path, 0, 0, base::Time())));
[email protected]7a1fcff2012-01-24 01:07:49161
[email protected]0f972882013-09-20 04:34:20162 scoped_ptr<UploadDataStream> body(
olli.raula6df48b2a2015-11-26 07:40:22163 new ElementsUploadDataStream(std::move(element_readers), 0));
[email protected]0f972882013-09-20 04:34:20164 TestCompletionCallback callback;
165 ASSERT_EQ(ERR_IO_PENDING, body->Init(callback.callback()));
166 ASSERT_EQ(OK, callback.WaitForResult());
167 // Shouldn't be merged if upload data carries a file, as it's not in-memory.
168 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
169 "some header", body.get()));
170 }
wkorman30fe3fd2015-11-06 23:43:42171
[email protected]0f972882013-09-20 04:34:20172 // UploadFileElementReaders may post clean-up tasks on destruction.
173 base::RunLoop().RunUntilIdle();
[email protected]7a1fcff2012-01-24 01:07:49174}
175
[email protected]75577ec2012-01-24 23:41:50176TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory) {
olli.raula6df48b2a2015-11-26 07:40:22177 std::vector<scoped_ptr<UploadElementReader>> element_readers;
[email protected]7a1fcff2012-01-24 01:07:49178 const std::string payload = "123";
olli.raula6df48b2a2015-11-26 07:40:22179 element_readers.push_back(make_scoped_ptr(
180 new UploadBytesElementReader(payload.data(), payload.size())));
[email protected]7a1fcff2012-01-24 01:07:49181
[email protected]96c77a72013-09-24 09:49:20182 scoped_ptr<UploadDataStream> body(
olli.raula6df48b2a2015-11-26 07:40:22183 new ElementsUploadDataStream(std::move(element_readers), 0));
[email protected]4db27d82012-12-20 11:50:24184 ASSERT_EQ(OK, body->Init(CompletionCallback()));
[email protected]7a1fcff2012-01-24 01:07:49185 // Yes, should be merged if the in-memory body is small here.
[email protected]75577ec2012-01-24 23:41:50186 ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
187 "some header", body.get()));
[email protected]7a1fcff2012-01-24 01:07:49188}
189
[email protected]75577ec2012-01-24 23:41:50190TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_LargeBodyInMemory) {
olli.raula6df48b2a2015-11-26 07:40:22191 std::vector<scoped_ptr<UploadElementReader>> element_readers;
[email protected]7a1fcff2012-01-24 01:07:49192 const std::string payload(10000, 'a'); // 'a' x 10000.
olli.raula6df48b2a2015-11-26 07:40:22193 element_readers.push_back(make_scoped_ptr(
194 new UploadBytesElementReader(payload.data(), payload.size())));
[email protected]7a1fcff2012-01-24 01:07:49195
[email protected]96c77a72013-09-24 09:49:20196 scoped_ptr<UploadDataStream> body(
olli.raula6df48b2a2015-11-26 07:40:22197 new ElementsUploadDataStream(std::move(element_readers), 0));
[email protected]4db27d82012-12-20 11:50:24198 ASSERT_EQ(OK, body->Init(CompletionCallback()));
[email protected]7a1fcff2012-01-24 01:07:49199 // Shouldn't be merged if the in-memory body is large here.
[email protected]75577ec2012-01-24 23:41:50200 ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
201 "some header", body.get()));
[email protected]7a1fcff2012-01-24 01:07:49202}
203
sclittlebe1ccf62015-09-02 19:40:36204TEST(HttpStreamParser, SentBytesNoHeaders) {
205 MockWrite writes[] = {
206 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
207 };
208
209 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
210 scoped_ptr<ClientSocketHandle> socket_handle =
211 CreateConnectedSocketHandle(&data);
212
213 HttpRequestInfo request;
214 request.method = "GET";
215 request.url = GURL("http://localhost");
216
217 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
218 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
219 BoundNetLog());
220
221 HttpResponseInfo response;
222 TestCompletionCallback callback;
223 EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", HttpRequestHeaders(),
224 &response, callback.callback()));
225
226 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
227}
228
229TEST(HttpStreamParser, SentBytesWithHeaders) {
230 MockWrite writes[] = {
231 MockWrite(SYNCHRONOUS, 0,
232 "GET / HTTP/1.1\r\n"
233 "Host: localhost\r\n"
234 "Connection: Keep-Alive\r\n\r\n"),
235 };
236
237 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
238 scoped_ptr<ClientSocketHandle> socket_handle =
239 CreateConnectedSocketHandle(&data);
240
241 HttpRequestInfo request;
242 request.method = "GET";
243 request.url = GURL("http://localhost");
244
245 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
246 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
247 BoundNetLog());
248
249 HttpRequestHeaders headers;
250 headers.SetHeader("Host", "localhost");
251 headers.SetHeader("Connection", "Keep-Alive");
252
253 HttpResponseInfo response;
254 TestCompletionCallback callback;
255 EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response,
256 callback.callback()));
257
258 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
259}
260
261TEST(HttpStreamParser, SentBytesWithHeadersMultiWrite) {
262 MockWrite writes[] = {
263 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
264 MockWrite(SYNCHRONOUS, 1, "Host: localhost\r\n"),
265 MockWrite(SYNCHRONOUS, 2, "Connection: Keep-Alive\r\n\r\n"),
266 };
267
268 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
269 scoped_ptr<ClientSocketHandle> socket_handle =
270 CreateConnectedSocketHandle(&data);
271
272 HttpRequestInfo request;
273 request.method = "GET";
274 request.url = GURL("http://localhost");
275
276 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
277 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
278 BoundNetLog());
279
280 HttpRequestHeaders headers;
281 headers.SetHeader("Host", "localhost");
282 headers.SetHeader("Connection", "Keep-Alive");
283
284 HttpResponseInfo response;
285 TestCompletionCallback callback;
286
287 EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response,
288 callback.callback()));
289
290 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
291}
292
293TEST(HttpStreamParser, SentBytesWithErrorWritingHeaders) {
294 MockWrite writes[] = {
295 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
296 MockWrite(SYNCHRONOUS, 1, "Host: localhost\r\n"),
297 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 2),
298 };
299
300 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
301 scoped_ptr<ClientSocketHandle> socket_handle =
302 CreateConnectedSocketHandle(&data);
303
304 HttpRequestInfo request;
305 request.method = "GET";
306 request.url = GURL("http://localhost");
307
308 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
309 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
310 BoundNetLog());
311
312 HttpRequestHeaders headers;
313 headers.SetHeader("Host", "localhost");
314 headers.SetHeader("Connection", "Keep-Alive");
315
316 HttpResponseInfo response;
317 TestCompletionCallback callback;
318 EXPECT_EQ(ERR_CONNECTION_RESET,
319 parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response,
320 callback.callback()));
321
322 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
323}
324
325TEST(HttpStreamParser, SentBytesPost) {
326 MockWrite writes[] = {
327 MockWrite(SYNCHRONOUS, 0, "POST / HTTP/1.1\r\n"),
328 MockWrite(SYNCHRONOUS, 1, "Content-Length: 12\r\n\r\n"),
329 MockWrite(SYNCHRONOUS, 2, "hello world!"),
330 };
331
332 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
333 scoped_ptr<ClientSocketHandle> socket_handle =
334 CreateConnectedSocketHandle(&data);
335
olli.raula6df48b2a2015-11-26 07:40:22336 std::vector<scoped_ptr<UploadElementReader>> element_readers;
337 element_readers.push_back(
338 make_scoped_ptr(new UploadBytesElementReader("hello world!", 12)));
339 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
sclittlebe1ccf62015-09-02 19:40:36340 ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
341
342 HttpRequestInfo request;
343 request.method = "POST";
344 request.url = GURL("http://localhost");
345 request.upload_data_stream = &upload_data_stream;
346
347 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
348 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
349 BoundNetLog());
350
351 HttpRequestHeaders headers;
352 headers.SetHeader("Content-Length", "12");
353
354 HttpResponseInfo response;
355 TestCompletionCallback callback;
356 EXPECT_EQ(OK, parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response,
357 callback.callback()));
358
359 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
360}
361
362TEST(HttpStreamParser, SentBytesChunkedPostError) {
363 static const char kChunk[] = "Chunk 1";
364
365 MockWrite writes[] = {
366 MockWrite(ASYNC, 0, "POST / HTTP/1.1\r\n"),
367 MockWrite(ASYNC, 1, "Transfer-Encoding: chunked\r\n\r\n"),
368 MockWrite(ASYNC, 2, "7\r\nChunk 1\r\n"),
369 MockWrite(SYNCHRONOUS, ERR_FAILED, 3),
370 };
371
372 SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
373 scoped_ptr<ClientSocketHandle> socket_handle =
374 CreateConnectedSocketHandle(&data);
375
376 ChunkedUploadDataStream upload_data_stream(0);
377 ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
378
379 HttpRequestInfo request;
380 request.method = "POST";
381 request.url = GURL("http://localhost");
382 request.upload_data_stream = &upload_data_stream;
383
384 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
385 HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
386 BoundNetLog());
387
388 HttpRequestHeaders headers;
389 headers.SetHeader("Transfer-Encoding", "chunked");
390
391 HttpResponseInfo response;
392 TestCompletionCallback callback;
393 EXPECT_EQ(ERR_IO_PENDING, parser.SendRequest("POST / HTTP/1.1\r\n", headers,
394 &response, callback.callback()));
395
396 base::RunLoop().RunUntilIdle();
397 upload_data_stream.AppendData(kChunk, arraysize(kChunk) - 1, false);
398
399 base::RunLoop().RunUntilIdle();
400 // This write should fail.
401 upload_data_stream.AppendData(kChunk, arraysize(kChunk) - 1, false);
402 EXPECT_EQ(ERR_FAILED, callback.WaitForResult());
403
404 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
405}
406
[email protected]4750937f2012-06-15 20:44:21407// Test to ensure the HttpStreamParser state machine does not get confused
mmenke3dc8c88b2015-02-19 15:11:27408// when sending a request with a chunked body with only one chunk that becomes
409// available asynchronously.
410TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
411 static const char kChunk[] = "Chunk";
412
413 MockWrite writes[] = {
414 MockWrite(ASYNC, 0,
415 "GET /one.html HTTP/1.1\r\n"
416 "Transfer-Encoding: chunked\r\n\r\n"),
417 MockWrite(ASYNC, 1, "5\r\nChunk\r\n"),
418 MockWrite(ASYNC, 2, "0\r\n\r\n"),
419 };
420
421 // The size of the response body, as reflected in the Content-Length of the
422 // MockRead below.
423 static const int kBodySize = 8;
424
425 MockRead reads[] = {
426 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n"),
427 MockRead(ASYNC, 4, "Content-Length: 8\r\n\r\n"),
428 MockRead(ASYNC, 5, "one.html"),
429 MockRead(SYNCHRONOUS, 0, 6), // EOF
430 };
431
432 ChunkedUploadDataStream upload_stream(0);
433 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
434
mmenkef22be0ee2015-06-05 15:39:02435 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
mmenke3dc8c88b2015-02-19 15:11:27436 scoped_ptr<ClientSocketHandle> socket_handle =
437 CreateConnectedSocketHandle(&data);
438
439 HttpRequestInfo request_info;
440 request_info.method = "GET";
441 request_info.url = GURL("http://localhost");
442 request_info.upload_data_stream = &upload_stream;
443
444 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
445 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
446 BoundNetLog());
447
448 HttpRequestHeaders request_headers;
449 request_headers.SetHeader("Transfer-Encoding", "chunked");
450
451 HttpResponseInfo response_info;
452 TestCompletionCallback callback;
453 // This will attempt to Write() the initial request and headers, which will
454 // complete asynchronously.
455 ASSERT_EQ(ERR_IO_PENDING,
456 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
457 &response_info, callback.callback()));
458
mmenkef22be0ee2015-06-05 15:39:02459 // Complete the initial request write. Callback should not have been invoked.
460 base::RunLoop().RunUntilIdle();
mmenke3dc8c88b2015-02-19 15:11:27461 ASSERT_FALSE(callback.have_result());
462
mmenkef22be0ee2015-06-05 15:39:02463 // Now append the only chunk and wait for the callback.
mmenke3dc8c88b2015-02-19 15:11:27464 upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
mmenke3dc8c88b2015-02-19 15:11:27465 ASSERT_EQ(OK, callback.WaitForResult());
466
467 // Attempt to read the response status and the response headers.
468 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27469 ASSERT_GT(callback.WaitForResult(), 0);
470
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()));
mmenke3dc8c88b2015-02-19 15:11:27476 ASSERT_EQ(kBodySize, callback.WaitForResult());
sclittlebe1ccf62015-09-02 19:40:36477
478 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
479 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
mmenke3dc8c88b2015-02-19 15:11:27480}
481
482// Test to ensure the HttpStreamParser state machine does not get confused
483// when sending a request with a chunked body with only one chunk that is
484// available synchronously.
485TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
486 static const char kChunk[] = "Chunk";
487
488 MockWrite writes[] = {
489 MockWrite(ASYNC, 0,
490 "GET /one.html HTTP/1.1\r\n"
491 "Transfer-Encoding: chunked\r\n\r\n"),
492 MockWrite(ASYNC, 1, "5\r\nChunk\r\n"),
493 MockWrite(ASYNC, 2, "0\r\n\r\n"),
494 };
495
496 // The size of the response body, as reflected in the Content-Length of the
497 // MockRead below.
498 static const int kBodySize = 8;
499
500 MockRead reads[] = {
501 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n"),
502 MockRead(ASYNC, 4, "Content-Length: 8\r\n\r\n"),
503 MockRead(ASYNC, 5, "one.html"),
504 MockRead(SYNCHRONOUS, 0, 6), // EOF
505 };
506
507 ChunkedUploadDataStream upload_stream(0);
508 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
509 // Append the only chunk.
510 upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
511
mmenkef22be0ee2015-06-05 15:39:02512 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
mmenke3dc8c88b2015-02-19 15:11:27513 scoped_ptr<ClientSocketHandle> socket_handle =
514 CreateConnectedSocketHandle(&data);
515
516 HttpRequestInfo request_info;
517 request_info.method = "GET";
518 request_info.url = GURL("http://localhost");
519 request_info.upload_data_stream = &upload_stream;
520
521 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
522 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
523 BoundNetLog());
524
525 HttpRequestHeaders request_headers;
526 request_headers.SetHeader("Transfer-Encoding", "chunked");
527
528 HttpResponseInfo response_info;
529 TestCompletionCallback callback;
530 // This will attempt to Write() the initial request and headers, which will
531 // complete asynchronously.
532 ASSERT_EQ(ERR_IO_PENDING,
533 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
534 &response_info, callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27535 ASSERT_EQ(OK, callback.WaitForResult());
536
537 // Attempt to read the response status and the response headers.
538 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27539 ASSERT_GT(callback.WaitForResult(), 0);
540
541 // Finally, attempt to read the response body.
542 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
543 ASSERT_EQ(ERR_IO_PENDING,
544 parser.ReadResponseBody(body_buffer.get(), kBodySize,
545 callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27546 ASSERT_EQ(kBodySize, callback.WaitForResult());
sclittlebe1ccf62015-09-02 19:40:36547
548 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
549 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
mmenke3dc8c88b2015-02-19 15:11:27550}
551
552// Test to ensure the HttpStreamParser state machine does not get confused
[email protected]4750937f2012-06-15 20:44:21553// when sending a request with a chunked body, where chunks become available
554// asynchronously, over a socket where writes may also complete
555// asynchronously.
556// This is a regression test for http://crbug.com/132243
mmenke3dc8c88b2015-02-19 15:11:27557TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
[email protected]4750937f2012-06-15 20:44:21558 // The chunks that will be written in the request, as reflected in the
559 // MockWrites below.
560 static const char kChunk1[] = "Chunk 1";
561 static const char kChunk2[] = "Chunky 2";
562 static const char kChunk3[] = "Test 3";
563
564 MockWrite writes[] = {
mmenke3dc8c88b2015-02-19 15:11:27565 MockWrite(ASYNC, 0,
566 "GET /one.html HTTP/1.1\r\n"
567 "Transfer-Encoding: chunked\r\n\r\n"),
568 MockWrite(ASYNC, 1, "7\r\nChunk 1\r\n"),
569 MockWrite(ASYNC, 2, "8\r\nChunky 2\r\n"),
570 MockWrite(ASYNC, 3, "6\r\nTest 3\r\n"),
571 MockWrite(ASYNC, 4, "0\r\n\r\n"),
[email protected]4750937f2012-06-15 20:44:21572 };
573
574 // The size of the response body, as reflected in the Content-Length of the
575 // MockRead below.
576 static const int kBodySize = 8;
577
578 MockRead reads[] = {
579 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"),
580 MockRead(ASYNC, 6, "Content-Length: 8\r\n\r\n"),
581 MockRead(ASYNC, 7, "one.html"),
[email protected]d55b30a2012-07-21 00:35:39582 MockRead(SYNCHRONOUS, 0, 8), // EOF
[email protected]4750937f2012-06-15 20:44:21583 };
584
mmenkecbc2b712014-10-09 20:29:07585 ChunkedUploadDataStream upload_stream(0);
586 upload_stream.AppendData(kChunk1, arraysize(kChunk1) - 1, false);
587 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
[email protected]9a963892012-11-01 11:48:13588
mmenkef22be0ee2015-06-05 15:39:02589 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
mmenke3dc8c88b2015-02-19 15:11:27590 scoped_ptr<ClientSocketHandle> socket_handle =
591 CreateConnectedSocketHandle(&data);
[email protected]4750937f2012-06-15 20:44:21592
593 HttpRequestInfo request_info;
594 request_info.method = "GET";
595 request_info.url = GURL("http://localhost");
[email protected]bf3eb002012-11-15 05:50:11596 request_info.upload_data_stream = &upload_stream;
[email protected]4750937f2012-06-15 20:44:21597
598 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
[email protected]90499482013-06-01 00:39:50599 HttpStreamParser parser(
600 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
[email protected]4750937f2012-06-15 20:44:21601
[email protected]4750937f2012-06-15 20:44:21602 HttpRequestHeaders request_headers;
[email protected]4750937f2012-06-15 20:44:21603 request_headers.SetHeader("Transfer-Encoding", "chunked");
[email protected]4750937f2012-06-15 20:44:21604
605 HttpResponseInfo response_info;
mmenke3dc8c88b2015-02-19 15:11:27606 TestCompletionCallback callback;
[email protected]4750937f2012-06-15 20:44:21607 // This will attempt to Write() the initial request and headers, which will
608 // complete asynchronously.
mmenke3dc8c88b2015-02-19 15:11:27609 ASSERT_EQ(ERR_IO_PENDING,
610 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
611 &response_info, callback.callback()));
[email protected]4750937f2012-06-15 20:44:21612 ASSERT_FALSE(callback.have_result());
613
mmenkef22be0ee2015-06-05 15:39:02614 // Sending the request and the first chunk completes.
615 base::RunLoop().RunUntilIdle();
616 ASSERT_FALSE(callback.have_result());
617
618 // Now append another chunk.
mmenkecbc2b712014-10-09 20:29:07619 upload_stream.AppendData(kChunk2, arraysize(kChunk2) - 1, false);
[email protected]4750937f2012-06-15 20:44:21620 ASSERT_FALSE(callback.have_result());
621
mmenkef22be0ee2015-06-05 15:39:02622 // Add the final chunk, while the write for the second is still pending,
623 // which should not confuse the state machine.
mmenkecbc2b712014-10-09 20:29:07624 upload_stream.AppendData(kChunk3, arraysize(kChunk3) - 1, true);
[email protected]4750937f2012-06-15 20:44:21625 ASSERT_FALSE(callback.have_result());
626
mmenkef22be0ee2015-06-05 15:39:02627 // Wait for writes to complete.
mmenke3dc8c88b2015-02-19 15:11:27628 ASSERT_EQ(OK, callback.WaitForResult());
[email protected]4750937f2012-06-15 20:44:21629
630 // Attempt to read the response status and the response headers.
mmenke3dc8c88b2015-02-19 15:11:27631 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27632 ASSERT_GT(callback.WaitForResult(), 0);
[email protected]4750937f2012-06-15 20:44:21633
634 // Finally, attempt to read the response body.
635 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
mmenke3dc8c88b2015-02-19 15:11:27636 ASSERT_EQ(ERR_IO_PENDING,
637 parser.ReadResponseBody(body_buffer.get(), kBodySize,
638 callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27639 ASSERT_EQ(kBodySize, callback.WaitForResult());
sclittlebe1ccf62015-09-02 19:40:36640
641 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
642 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
mmenke3dc8c88b2015-02-19 15:11:27643}
644
645// Test to ensure the HttpStreamParser state machine does not get confused
646// when there's only one "chunk" with 0 bytes, and is received from the
647// UploadStream only after sending the request headers successfully.
648TEST(HttpStreamParser, AsyncEmptyChunkedUpload) {
649 MockWrite writes[] = {
650 MockWrite(ASYNC, 0,
651 "GET /one.html HTTP/1.1\r\n"
652 "Transfer-Encoding: chunked\r\n\r\n"),
653 MockWrite(ASYNC, 1, "0\r\n\r\n"),
654 };
655
656 // The size of the response body, as reflected in the Content-Length of the
657 // MockRead below.
658 const int kBodySize = 8;
659
660 MockRead reads[] = {
661 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"),
662 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"),
663 MockRead(ASYNC, 4, "one.html"),
664 MockRead(SYNCHRONOUS, 0, 5), // EOF
665 };
666
667 ChunkedUploadDataStream upload_stream(0);
668 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
669
mmenkef22be0ee2015-06-05 15:39:02670 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
mmenke3dc8c88b2015-02-19 15:11:27671 scoped_ptr<ClientSocketHandle> socket_handle =
672 CreateConnectedSocketHandle(&data);
673
674 HttpRequestInfo request_info;
675 request_info.method = "GET";
676 request_info.url = GURL("http://localhost");
677 request_info.upload_data_stream = &upload_stream;
678
679 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
680 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
681 BoundNetLog());
682
683 HttpRequestHeaders request_headers;
684 request_headers.SetHeader("Transfer-Encoding", "chunked");
685
686 HttpResponseInfo response_info;
687 TestCompletionCallback callback;
688 // This will attempt to Write() the initial request and headers, which will
689 // complete asynchronously.
690 ASSERT_EQ(ERR_IO_PENDING,
691 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
692 &response_info, callback.callback()));
693
mmenke3dc8c88b2015-02-19 15:11:27694 // Now append the terminal 0-byte "chunk".
695 upload_stream.AppendData(nullptr, 0, true);
696 ASSERT_FALSE(callback.have_result());
697
mmenke3dc8c88b2015-02-19 15:11:27698 ASSERT_EQ(OK, callback.WaitForResult());
699
700 // Attempt to read the response status and the response headers.
701 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27702 ASSERT_GT(callback.WaitForResult(), 0);
703
704 // Finally, attempt to read the response body.
705 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
706 ASSERT_EQ(ERR_IO_PENDING,
707 parser.ReadResponseBody(body_buffer.get(), kBodySize,
708 callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27709 ASSERT_EQ(kBodySize, callback.WaitForResult());
sclittlebe1ccf62015-09-02 19:40:36710
711 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
712 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
mmenke3dc8c88b2015-02-19 15:11:27713}
714
715// Test to ensure the HttpStreamParser state machine does not get confused
716// when there's only one "chunk" with 0 bytes, which was already appended before
717// the request was started.
718TEST(HttpStreamParser, SyncEmptyChunkedUpload) {
719 MockWrite writes[] = {
720 MockWrite(ASYNC, 0,
721 "GET /one.html HTTP/1.1\r\n"
722 "Transfer-Encoding: chunked\r\n\r\n"),
723 MockWrite(ASYNC, 1, "0\r\n\r\n"),
724 };
725
726 // The size of the response body, as reflected in the Content-Length of the
727 // MockRead below.
728 const int kBodySize = 8;
729
730 MockRead reads[] = {
731 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"),
732 MockRead(ASYNC, 3, "Content-Length: 8\r\n\r\n"),
733 MockRead(ASYNC, 4, "one.html"),
734 MockRead(SYNCHRONOUS, 0, 5), // EOF
735 };
736
737 ChunkedUploadDataStream upload_stream(0);
738 ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
739 // Append final empty chunk.
740 upload_stream.AppendData(nullptr, 0, true);
741
mmenkef22be0ee2015-06-05 15:39:02742 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
mmenke3dc8c88b2015-02-19 15:11:27743 scoped_ptr<ClientSocketHandle> socket_handle =
744 CreateConnectedSocketHandle(&data);
745
746 HttpRequestInfo request_info;
747 request_info.method = "GET";
748 request_info.url = GURL("http://localhost");
749 request_info.upload_data_stream = &upload_stream;
750
751 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
752 HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
753 BoundNetLog());
754
755 HttpRequestHeaders request_headers;
756 request_headers.SetHeader("Transfer-Encoding", "chunked");
757
758 HttpResponseInfo response_info;
759 TestCompletionCallback callback;
760 // This will attempt to Write() the initial request and headers, which will
761 // complete asynchronously.
762 ASSERT_EQ(ERR_IO_PENDING,
763 parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
764 &response_info, callback.callback()));
765
766 // Complete writing the request headers and body.
mmenke3dc8c88b2015-02-19 15:11:27767 ASSERT_EQ(OK, callback.WaitForResult());
768
769 // Attempt to read the response status and the response headers.
770 ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27771 ASSERT_GT(callback.WaitForResult(), 0);
772
773 // Finally, attempt to read the response body.
774 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
775 ASSERT_EQ(ERR_IO_PENDING,
776 parser.ReadResponseBody(body_buffer.get(), kBodySize,
777 callback.callback()));
mmenke3dc8c88b2015-02-19 15:11:27778 ASSERT_EQ(kBodySize, callback.WaitForResult());
sclittlebe1ccf62015-09-02 19:40:36779
780 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
781 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
[email protected]4750937f2012-06-15 20:44:21782}
783
[email protected]9c18dbc2013-05-29 19:06:53784TEST(HttpStreamParser, TruncatedHeaders) {
785 MockRead truncated_status_reads[] = {
786 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"),
787 MockRead(SYNCHRONOUS, 0, 2), // EOF
788 };
789
790 MockRead truncated_after_status_reads[] = {
791 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"),
792 MockRead(SYNCHRONOUS, 0, 2), // EOF
793 };
794
795 MockRead truncated_in_header_reads[] = {
796 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHead"),
797 MockRead(SYNCHRONOUS, 0, 2), // EOF
798 };
799
800 MockRead truncated_after_header_reads[] = {
801 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n"),
802 MockRead(SYNCHRONOUS, 0, 2), // EOF
803 };
804
805 MockRead truncated_after_final_newline_reads[] = {
806 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r"),
807 MockRead(SYNCHRONOUS, 0, 2), // EOF
808 };
809
810 MockRead not_truncated_reads[] = {
811 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r\n"),
812 MockRead(SYNCHRONOUS, 0, 2), // EOF
813 };
814
815 MockRead* reads[] = {
816 truncated_status_reads,
817 truncated_after_status_reads,
818 truncated_in_header_reads,
819 truncated_after_header_reads,
820 truncated_after_final_newline_reads,
821 not_truncated_reads,
822 };
823
824 MockWrite writes[] = {
825 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
826 };
827
zmo9528c9f42015-08-04 22:12:08828 enum {
829 HTTP = 0,
830 HTTPS,
831 NUM_PROTOCOLS,
832 };
[email protected]9c18dbc2013-05-29 19:06:53833
zmo9528c9f42015-08-04 22:12:08834 for (size_t protocol = 0; protocol < NUM_PROTOCOLS; protocol++) {
835 SCOPED_TRACE(protocol);
[email protected]9c18dbc2013-05-29 19:06:53836
zmo9528c9f42015-08-04 22:12:08837 for (size_t i = 0; i < arraysize(reads); i++) {
838 SCOPED_TRACE(i);
839 SequencedSocketData data(reads[i], 2, writes, arraysize(writes));
840 scoped_ptr<ClientSocketHandle> socket_handle(
841 CreateConnectedSocketHandle(&data));
[email protected]9c18dbc2013-05-29 19:06:53842
zmo9528c9f42015-08-04 22:12:08843 HttpRequestInfo request_info;
844 request_info.method = "GET";
845 if (protocol == HTTP) {
846 request_info.url = GURL("http://localhost");
847 } else {
848 request_info.url = GURL("https://localhost");
849 }
850 request_info.load_flags = LOAD_NORMAL;
[email protected]9c18dbc2013-05-29 19:06:53851
zmo9528c9f42015-08-04 22:12:08852 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
853 HttpStreamParser parser(
854 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
855
856 HttpRequestHeaders request_headers;
857 HttpResponseInfo response_info;
858 TestCompletionCallback callback;
859 ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
860 &response_info, callback.callback()));
861
862 int rv = parser.ReadResponseHeaders(callback.callback());
sclittlebe1ccf62015-09-02 19:40:36863 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
864 parser.sent_bytes());
zmo9528c9f42015-08-04 22:12:08865 if (i == arraysize(reads) - 1) {
866 EXPECT_EQ(OK, rv);
867 EXPECT_TRUE(response_info.headers.get());
sclittlebe1ccf62015-09-02 19:40:36868 EXPECT_EQ(CountReadBytes(reads[i], 2), parser.received_bytes());
zmo9528c9f42015-08-04 22:12:08869 } else {
870 if (protocol == HTTP) {
871 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
872 EXPECT_TRUE(response_info.headers.get());
sclittlebe1ccf62015-09-02 19:40:36873 EXPECT_EQ(CountReadBytes(reads[i], 2), parser.received_bytes());
zmo9528c9f42015-08-04 22:12:08874 } else {
875 EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, rv);
876 EXPECT_FALSE(response_info.headers.get());
sclittlebe1ccf62015-09-02 19:40:36877 EXPECT_EQ(0, parser.received_bytes());
zmo9528c9f42015-08-04 22:12:08878 }
879 }
[email protected]9c18dbc2013-05-29 19:06:53880 }
881 }
882}
883
[email protected]df8e6382013-11-07 00:19:06884// Confirm that on 101 response, the headers are parsed but the data that
885// follows remains in the buffer.
886TEST(HttpStreamParser, Websocket101Response) {
887 MockRead reads[] = {
888 MockRead(SYNCHRONOUS, 1,
889 "HTTP/1.1 101 Switching Protocols\r\n"
890 "Upgrade: websocket\r\n"
891 "Connection: Upgrade\r\n"
892 "\r\n"
893 "a fake websocket frame"),
894 };
895
896 MockWrite writes[] = {
897 MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
898 };
899
mmenkef22be0ee2015-06-05 15:39:02900 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
901 scoped_ptr<ClientSocketHandle> socket_handle =
902 CreateConnectedSocketHandle(&data);
[email protected]df8e6382013-11-07 00:19:06903
904 HttpRequestInfo request_info;
905 request_info.method = "GET";
906 request_info.url = GURL("http://localhost");
907 request_info.load_flags = LOAD_NORMAL;
908
909 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
910 HttpStreamParser parser(
911 socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
912
913 HttpRequestHeaders request_headers;
914 HttpResponseInfo response_info;
mmenkef22be0ee2015-06-05 15:39:02915 TestCompletionCallback callback;
916 ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
917 &response_info, callback.callback()));
[email protected]df8e6382013-11-07 00:19:06918
mmenkef22be0ee2015-06-05 15:39:02919 EXPECT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
[email protected]df8e6382013-11-07 00:19:06920 ASSERT_TRUE(response_info.headers.get());
921 EXPECT_EQ(101, response_info.headers->response_code());
922 EXPECT_TRUE(response_info.headers->HasHeaderValue("Connection", "Upgrade"));
923 EXPECT_TRUE(response_info.headers->HasHeaderValue("Upgrade", "websocket"));
924 EXPECT_EQ(read_buffer->capacity(), read_buffer->offset());
925 EXPECT_EQ("a fake websocket frame",
926 base::StringPiece(read_buffer->StartOfBuffer(),
927 read_buffer->capacity()));
sclittlebe1ccf62015-09-02 19:40:36928
929 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
930 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)) -
931 static_cast<int64_t>(strlen("a fake websocket frame")),
932 parser.received_bytes());
[email protected]df8e6382013-11-07 00:19:06933}
934
[email protected]390489b2013-12-09 10:49:01935// Helper class for constructing HttpStreamParser and running GET requests.
936class SimpleGetRunner {
937 public:
938 SimpleGetRunner() : read_buffer_(new GrowableIOBuffer), sequence_number_(0) {
939 writes_.push_back(MockWrite(
940 SYNCHRONOUS, sequence_number_++, "GET / HTTP/1.1\r\n\r\n"));
941 }
942
943 HttpStreamParser* parser() { return parser_.get(); }
944 GrowableIOBuffer* read_buffer() { return read_buffer_.get(); }
945 HttpResponseInfo* response_info() { return &response_info_; }
946
947 void AddInitialData(const std::string& data) {
948 int offset = read_buffer_->offset();
949 int size = data.size();
950 read_buffer_->SetCapacity(offset + size);
951 memcpy(read_buffer_->StartOfBuffer() + offset, data.data(), size);
952 read_buffer_->set_offset(offset + size);
953 }
954
955 void AddRead(const std::string& data) {
956 reads_.push_back(MockRead(SYNCHRONOUS, sequence_number_++, data.data()));
957 }
958
959 void SetupParserAndSendRequest() {
960 reads_.push_back(MockRead(SYNCHRONOUS, 0, sequence_number_++)); // EOF
961
mmenkef22be0ee2015-06-05 15:39:02962 data_.reset(new SequencedSocketData(&reads_.front(), reads_.size(),
963 &writes_.front(), writes_.size()));
964 socket_handle_ = CreateConnectedSocketHandle(data_.get());
[email protected]390489b2013-12-09 10:49:01965
966 request_info_.method = "GET";
967 request_info_.url = GURL("http://localhost");
968 request_info_.load_flags = LOAD_NORMAL;
969
970 parser_.reset(new HttpStreamParser(
971 socket_handle_.get(), &request_info_, read_buffer(), BoundNetLog()));
972
mmenkef22be0ee2015-06-05 15:39:02973 TestCompletionCallback callback;
974 ASSERT_EQ(OK, parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_,
975 &response_info_, callback.callback()));
[email protected]390489b2013-12-09 10:49:01976 }
977
978 void ReadHeaders() {
979 TestCompletionCallback callback;
980 EXPECT_EQ(OK, parser_->ReadResponseHeaders(callback.callback()));
981 }
982
983 void ReadBody(int user_buf_len, int* read_lengths) {
984 TestCompletionCallback callback;
985 scoped_refptr<IOBuffer> buffer = new IOBuffer(user_buf_len);
986 int rv;
987 int i = 0;
988 while (true) {
dcheng48459ac22014-08-26 00:46:41989 rv = parser_->ReadResponseBody(
990 buffer.get(), user_buf_len, callback.callback());
[email protected]390489b2013-12-09 10:49:01991 EXPECT_EQ(read_lengths[i], rv);
992 i++;
993 if (rv <= 0)
994 return;
995 }
996 }
997
998 private:
999 HttpRequestHeaders request_headers_;
1000 HttpResponseInfo response_info_;
1001 HttpRequestInfo request_info_;
1002 scoped_refptr<GrowableIOBuffer> read_buffer_;
1003 std::vector<MockRead> reads_;
1004 std::vector<MockWrite> writes_;
1005 scoped_ptr<ClientSocketHandle> socket_handle_;
mmenkef22be0ee2015-06-05 15:39:021006 scoped_ptr<SequencedSocketData> data_;
[email protected]390489b2013-12-09 10:49:011007 scoped_ptr<HttpStreamParser> parser_;
1008 int sequence_number_;
1009};
1010
1011// Test that HTTP/0.9 response size is correctly calculated.
1012TEST(HttpStreamParser, ReceivedBytesNoHeaders) {
1013 std::string response = "hello\r\nworld\r\n";
1014
1015 SimpleGetRunner get_runner;
1016 get_runner.AddRead(response);
1017 get_runner.SetupParserAndSendRequest();
1018 get_runner.ReadHeaders();
1019 EXPECT_EQ(0, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561020 int response_size = response.size();
[email protected]390489b2013-12-09 10:49:011021 int read_lengths[] = {response_size, 0};
1022 get_runner.ReadBody(response_size, read_lengths);
1023 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
1024}
1025
1026// Test basic case where there is no keep-alive or extra data from the socket,
1027// and the entire response is received in a single read.
1028TEST(HttpStreamParser, ReceivedBytesNormal) {
1029 std::string headers = "HTTP/1.1 200 OK\r\n"
1030 "Content-Length: 7\r\n\r\n";
1031 std::string body = "content";
1032 std::string response = headers + body;
1033
1034 SimpleGetRunner get_runner;
1035 get_runner.AddRead(response);
1036 get_runner.SetupParserAndSendRequest();
1037 get_runner.ReadHeaders();
Avi Drissman13fc8932015-12-20 04:40:461038 int64_t headers_size = headers.size();
[email protected]390489b2013-12-09 10:49:011039 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561040 int body_size = body.size();
[email protected]390489b2013-12-09 10:49:011041 int read_lengths[] = {body_size, 0};
1042 get_runner.ReadBody(body_size, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461043 int64_t response_size = response.size();
[email protected]390489b2013-12-09 10:49:011044 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
1045}
1046
1047// Test that bytes that represent "next" response are not counted
1048// as current response "received_bytes".
1049TEST(HttpStreamParser, ReceivedBytesExcludesNextResponse) {
1050 std::string headers = "HTTP/1.1 200 OK\r\n"
1051 "Content-Length: 8\r\n\r\n";
1052 std::string body = "content8";
1053 std::string response = headers + body;
1054 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
1055 std::string data = response + next_response;
1056
1057 SimpleGetRunner get_runner;
1058 get_runner.AddRead(data);
1059 get_runner.SetupParserAndSendRequest();
1060 get_runner.ReadHeaders();
1061 EXPECT_EQ(39, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461062 int64_t headers_size = headers.size();
[email protected]390489b2013-12-09 10:49:011063 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561064 int body_size = body.size();
[email protected]390489b2013-12-09 10:49:011065 int read_lengths[] = {body_size, 0};
1066 get_runner.ReadBody(body_size, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461067 int64_t response_size = response.size();
[email protected]390489b2013-12-09 10:49:011068 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461069 int64_t next_response_size = next_response.size();
[email protected]390489b2013-12-09 10:49:011070 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
1071}
1072
1073// Test that "received_bytes" calculation works fine when last read
1074// contains more data than requested by user.
1075// We send data in two reads:
1076// 1) Headers + beginning of response
1077// 2) remaining part of response + next response start
1078// We setup user read buffer so it fully accepts the beginnig of response
1079// body, but it is larger that remaining part of body.
1080TEST(HttpStreamParser, ReceivedBytesMultiReadExcludesNextResponse) {
1081 std::string headers = "HTTP/1.1 200 OK\r\n"
1082 "Content-Length: 36\r\n\r\n";
Avi Drissman13fc8932015-12-20 04:40:461083 int64_t user_buf_len = 32;
[email protected]390489b2013-12-09 10:49:011084 std::string body_start = std::string(user_buf_len, '#');
[email protected]3cb5fc22013-12-12 19:40:561085 int body_start_size = body_start.size();
[email protected]390489b2013-12-09 10:49:011086 EXPECT_EQ(user_buf_len, body_start_size);
1087 std::string response_start = headers + body_start;
1088 std::string body_end = "abcd";
1089 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
1090 std::string response_end = body_end + next_response;
1091
1092 SimpleGetRunner get_runner;
1093 get_runner.AddRead(response_start);
1094 get_runner.AddRead(response_end);
1095 get_runner.SetupParserAndSendRequest();
1096 get_runner.ReadHeaders();
Avi Drissman13fc8932015-12-20 04:40:461097 int64_t headers_size = headers.size();
[email protected]390489b2013-12-09 10:49:011098 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561099 int body_end_size = body_end.size();
[email protected]390489b2013-12-09 10:49:011100 int read_lengths[] = {body_start_size, body_end_size, 0};
1101 get_runner.ReadBody(body_start_size, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461102 int64_t response_size = response_start.size() + body_end_size;
[email protected]390489b2013-12-09 10:49:011103 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461104 int64_t next_response_size = next_response.size();
[email protected]390489b2013-12-09 10:49:011105 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
1106}
1107
1108// Test that "received_bytes" calculation works fine when there is no
1109// network activity at all; that is when all data is read from read buffer.
1110// In this case read buffer contains two responses. We expect that only
1111// bytes that correspond to the first one are taken into account.
1112TEST(HttpStreamParser, ReceivedBytesFromReadBufExcludesNextResponse) {
1113 std::string headers = "HTTP/1.1 200 OK\r\n"
1114 "Content-Length: 7\r\n\r\n";
1115 std::string body = "content";
1116 std::string response = headers + body;
1117 std::string next_response = "HTTP/1.1 200 OK\r\n\r\nFOO";
1118 std::string data = response + next_response;
1119
1120 SimpleGetRunner get_runner;
1121 get_runner.AddInitialData(data);
1122 get_runner.SetupParserAndSendRequest();
1123 get_runner.ReadHeaders();
Avi Drissman13fc8932015-12-20 04:40:461124 int64_t headers_size = headers.size();
[email protected]390489b2013-12-09 10:49:011125 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561126 int body_size = body.size();
[email protected]390489b2013-12-09 10:49:011127 int read_lengths[] = {body_size, 0};
1128 get_runner.ReadBody(body_size, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461129 int64_t response_size = response.size();
[email protected]390489b2013-12-09 10:49:011130 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461131 int64_t next_response_size = next_response.size();
[email protected]390489b2013-12-09 10:49:011132 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
1133}
1134
1135// Test calculating "received_bytes" when part of request has been already
1136// loaded and placed to read buffer by previous stream parser.
1137TEST(HttpStreamParser, ReceivedBytesUseReadBuf) {
1138 std::string buffer = "HTTP/1.1 200 OK\r\n";
1139 std::string remaining_headers = "Content-Length: 7\r\n\r\n";
Avi Drissman13fc8932015-12-20 04:40:461140 int64_t headers_size = buffer.size() + remaining_headers.size();
[email protected]390489b2013-12-09 10:49:011141 std::string body = "content";
1142 std::string response = remaining_headers + body;
1143
1144 SimpleGetRunner get_runner;
1145 get_runner.AddInitialData(buffer);
1146 get_runner.AddRead(response);
1147 get_runner.SetupParserAndSendRequest();
1148 get_runner.ReadHeaders();
1149 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
[email protected]3cb5fc22013-12-12 19:40:561150 int body_size = body.size();
[email protected]390489b2013-12-09 10:49:011151 int read_lengths[] = {body_size, 0};
1152 get_runner.ReadBody(body_size, read_lengths);
1153 EXPECT_EQ(headers_size + body_size, get_runner.parser()->received_bytes());
1154 EXPECT_EQ(0, get_runner.read_buffer()->offset());
1155}
1156
1157// Test the case when the resulting read_buf contains both unused bytes and
1158// bytes ejected by chunked-encoding filter.
1159TEST(HttpStreamParser, ReceivedBytesChunkedTransferExcludesNextResponse) {
1160 std::string response = "HTTP/1.1 200 OK\r\n"
1161 "Transfer-Encoding: chunked\r\n\r\n"
1162 "7\r\nChunk 1\r\n"
1163 "8\r\nChunky 2\r\n"
1164 "6\r\nTest 3\r\n"
1165 "0\r\n\r\n";
1166 std::string next_response = "foo bar\r\n";
1167 std::string data = response + next_response;
1168
1169 SimpleGetRunner get_runner;
1170 get_runner.AddInitialData(data);
1171 get_runner.SetupParserAndSendRequest();
1172 get_runner.ReadHeaders();
1173 int read_lengths[] = {4, 3, 6, 2, 6, 0};
1174 get_runner.ReadBody(7, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461175 int64_t response_size = response.size();
[email protected]390489b2013-12-09 10:49:011176 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461177 int64_t next_response_size = next_response.size();
[email protected]390489b2013-12-09 10:49:011178 EXPECT_EQ(next_response_size, get_runner.read_buffer()->offset());
1179}
1180
1181// Test that data transfered in multiple reads is correctly processed.
1182// We feed data into 4-bytes reads. Also we set length of read
1183// buffer to 5-bytes to test all possible buffer misaligments.
1184TEST(HttpStreamParser, ReceivedBytesMultipleReads) {
1185 std::string headers = "HTTP/1.1 200 OK\r\n"
1186 "Content-Length: 33\r\n\r\n";
1187 std::string body = "foo bar baz\r\n"
1188 "sputnik mir babushka";
1189 std::string response = headers + body;
1190
1191 size_t receive_length = 4;
1192 std::vector<std::string> blocks;
1193 for (size_t i = 0; i < response.size(); i += receive_length) {
1194 size_t length = std::min(receive_length, response.size() - i);
1195 blocks.push_back(response.substr(i, length));
1196 }
1197
1198 SimpleGetRunner get_runner;
[email protected]3cb5fc22013-12-12 19:40:561199 for (std::vector<std::string>::size_type i = 0; i < blocks.size(); ++i)
[email protected]390489b2013-12-09 10:49:011200 get_runner.AddRead(blocks[i]);
1201 get_runner.SetupParserAndSendRequest();
1202 get_runner.ReadHeaders();
Avi Drissman13fc8932015-12-20 04:40:461203 int64_t headers_size = headers.size();
[email protected]390489b2013-12-09 10:49:011204 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
1205 int read_lengths[] = {1, 4, 4, 4, 4, 4, 4, 4, 4, 0};
1206 get_runner.ReadBody(receive_length + 1, read_lengths);
Avi Drissman13fc8932015-12-20 04:40:461207 int64_t response_size = response.size();
[email protected]390489b2013-12-09 10:49:011208 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
1209}
1210
1211// Test that "continue" HTTP header is counted as "received_bytes".
1212TEST(HttpStreamParser, ReceivedBytesIncludesContinueHeader) {
1213 std::string status100 = "HTTP/1.1 100 OK\r\n\r\n";
1214 std::string headers = "HTTP/1.1 200 OK\r\n"
1215 "Content-Length: 7\r\n\r\n";
Avi Drissman13fc8932015-12-20 04:40:461216 int64_t headers_size = status100.size() + headers.size();
[email protected]390489b2013-12-09 10:49:011217 std::string body = "content";
1218 std::string response = headers + body;
1219
1220 SimpleGetRunner get_runner;
1221 get_runner.AddRead(status100);
1222 get_runner.AddRead(response);
1223 get_runner.SetupParserAndSendRequest();
1224 get_runner.ReadHeaders();
1225 EXPECT_EQ(100, get_runner.response_info()->headers->response_code());
Avi Drissman13fc8932015-12-20 04:40:461226 int64_t status100_size = status100.size();
[email protected]390489b2013-12-09 10:49:011227 EXPECT_EQ(status100_size, get_runner.parser()->received_bytes());
1228 get_runner.ReadHeaders();
1229 EXPECT_EQ(200, get_runner.response_info()->headers->response_code());
1230 EXPECT_EQ(headers_size, get_runner.parser()->received_bytes());
Avi Drissman13fc8932015-12-20 04:40:461231 int64_t response_size = headers_size + body.size();
[email protected]3cb5fc22013-12-12 19:40:561232 int body_size = body.size();
[email protected]390489b2013-12-09 10:49:011233 int read_lengths[] = {body_size, 0};
1234 get_runner.ReadBody(body_size, read_lengths);
1235 EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
1236}
1237
[email protected]ecab6e052014-05-16 14:58:121238// Test that an HttpStreamParser can be read from after it's received headers
1239// and data structures owned by its owner have been deleted. This happens
1240// when a ResponseBodyDrainer is used.
1241TEST(HttpStreamParser, ReadAfterUnownedObjectsDestroyed) {
1242 MockWrite writes[] = {
1243 MockWrite(SYNCHRONOUS, 0,
1244 "GET /foo.html HTTP/1.1\r\n\r\n"),
[email protected]ecab6e052014-05-16 14:58:121245 };
1246
1247 const int kBodySize = 1;
1248 MockRead reads[] = {
mmenkef22be0ee2015-06-05 15:39:021249 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
sclittlebe1ccf62015-09-02 19:40:361250 MockRead(SYNCHRONOUS, 2, "Content-Length: 1\r\n"),
mmenkef22be0ee2015-06-05 15:39:021251 MockRead(SYNCHRONOUS, 3, "Connection: Keep-Alive\r\n\r\n"),
1252 MockRead(SYNCHRONOUS, 4, "1"),
1253 MockRead(SYNCHRONOUS, 0, 5), // EOF
[email protected]ecab6e052014-05-16 14:58:121254 };
1255
mmenkef22be0ee2015-06-05 15:39:021256 SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
1257 scoped_ptr<ClientSocketHandle> socket_handle =
1258 CreateConnectedSocketHandle(&data);
[email protected]ecab6e052014-05-16 14:58:121259
1260 scoped_ptr<HttpRequestInfo> request_info(new HttpRequestInfo());
1261 request_info->method = "GET";
1262 request_info->url = GURL("http://somewhere/foo.html");
1263
1264 scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
1265 HttpStreamParser parser(socket_handle.get(), request_info.get(),
1266 read_buffer.get(), BoundNetLog());
1267
1268 scoped_ptr<HttpRequestHeaders> request_headers(new HttpRequestHeaders());
1269 scoped_ptr<HttpResponseInfo> response_info(new HttpResponseInfo());
mmenkef22be0ee2015-06-05 15:39:021270 TestCompletionCallback callback;
[email protected]ecab6e052014-05-16 14:58:121271 ASSERT_EQ(OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n",
1272 *request_headers, response_info.get(), callback.callback()));
1273 ASSERT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
1274
1275 // If the object that owns the HttpStreamParser is deleted, it takes the
1276 // objects passed to the HttpStreamParser with it.
1277 request_info.reset();
1278 request_headers.reset();
1279 response_info.reset();
1280
1281 scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
1282 ASSERT_EQ(kBodySize, parser.ReadResponseBody(
1283 body_buffer.get(), kBodySize, callback.callback()));
sclittlebe1ccf62015-09-02 19:40:361284
1285 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
1286 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), parser.received_bytes());
[email protected]ecab6e052014-05-16 14:58:121287}
1288
[email protected]390489b2013-12-09 10:49:011289} // namespace
[email protected]df8e6382013-11-07 00:19:061290
[email protected]6db833d12012-01-21 00:45:191291} // namespace net