1 // Copyright 2012 The Chromium Authors
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
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10
11 #include "base/compiler_specific.h"
12 #include "base/functional/bind.h"
13 #include "base/logging.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/numerics/clamped_math.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/base/upload_data_stream.h"
22 #include "net/http/http_chunked_decoder.h"
23 #include "net/http/http_connection_info.h"
24 #include "net/http/http_log_util.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/http/http_status_code.h"
30 #include "net/http/http_util.h"
31 #include "net/log/net_log_event_type.h"
32 #include "net/socket/ssl_client_socket.h"
33 #include "net/socket/stream_socket.h"
34 #include "net/ssl/ssl_cert_request_info.h"
35 #include "net/ssl/ssl_info.h"
36 #include "url/url_canon.h"
37
38 namespace net {
39
40 namespace {
41
42 const uint64_t kMaxMergedHeaderAndBodySize = 1400;
43 const size_t kRequestBodyBufferSize = 1 << 14; // 16KB
44
GetResponseHeaderLines(const HttpResponseHeaders & headers)45 std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) {
46 std::string raw_headers = headers.raw_headers();
47 const char* null_separated_headers = raw_headers.c_str();
48 const char* header_line = null_separated_headers;
49 std::string cr_separated_headers;
50 while (header_line[0] != 0) {
51 cr_separated_headers += header_line;
52 cr_separated_headers += "\n";
53 header_line += strlen(header_line) + 1;
54 }
55 return cr_separated_headers;
56 }
57
NetLogSendRequestBodyParams(uint64_t length,bool is_chunked,bool did_merge)58 base::Value::Dict NetLogSendRequestBodyParams(uint64_t length,
59 bool is_chunked,
60 bool did_merge) {
61 base::Value::Dict dict;
62 dict.Set("length", static_cast<int>(length));
63 dict.Set("is_chunked", is_chunked);
64 dict.Set("did_merge", did_merge);
65 return dict;
66 }
67
NetLogSendRequestBody(const NetLogWithSource & net_log,uint64_t length,bool is_chunked,bool did_merge)68 void NetLogSendRequestBody(const NetLogWithSource& net_log,
69 uint64_t length,
70 bool is_chunked,
71 bool did_merge) {
72 net_log.AddEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_BODY, [&] {
73 return NetLogSendRequestBodyParams(length, is_chunked, did_merge);
74 });
75 }
76
77 // Returns true if |error_code| is an error for which we give the server a
78 // chance to send a body containing error information, if the error was received
79 // while trying to upload a request body.
ShouldTryReadingOnUploadError(int error_code)80 bool ShouldTryReadingOnUploadError(int error_code) {
81 return (error_code == ERR_CONNECTION_RESET);
82 }
83
84 } // namespace
85
86 // Similar to DrainableIOBuffer(), but this version comes with its own
87 // storage. The motivation is to avoid repeated allocations of
88 // DrainableIOBuffer.
89 //
90 // Example:
91 //
92 // scoped_refptr<SeekableIOBuffer> buf =
93 // base::MakeRefCounted<SeekableIOBuffer>(1024);
94 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0.
95 // // data() points to the beginning of the buffer.
96 //
97 // // Read() takes an IOBuffer.
98 // int bytes_read = some_reader->Read(buf, buf->capacity());
99 // buf->DidAppend(bytes_read);
100 // // size() == BytesRemaining() == bytes_read. data() is unaffected.
101 //
102 // while (buf->BytesRemaining() > 0) {
103 // // Write() takes an IOBuffer. If it takes const char*, we could
104 /// // simply use the regular IOBuffer like buf->data() + offset.
105 // int bytes_written = Write(buf, buf->BytesRemaining());
106 // buf->DidConsume(bytes_written);
107 // }
108 // // BytesRemaining() == 0. BytesConsumed() == size().
109 // // data() points to the end of the consumed bytes (exclusive).
110 //
111 // // If you want to reuse the buffer, be sure to clear the buffer.
112 // buf->Clear();
113 // // size() == BytesRemaining() == BytesConsumed() == 0.
114 // // data() points to the beginning of the buffer.
115 //
116 class HttpStreamParser::SeekableIOBuffer : public IOBufferWithSize {
117 public:
SeekableIOBuffer(int capacity)118 explicit SeekableIOBuffer(int capacity)
119 : IOBufferWithSize(capacity), real_data_(data_), capacity_(capacity) {}
120
121 // DidConsume() changes the |data_| pointer so that |data_| always points
122 // to the first unconsumed byte.
DidConsume(int bytes)123 void DidConsume(int bytes) {
124 SetOffset(used_ + bytes);
125 }
126
127 // Returns the number of unconsumed bytes.
BytesRemaining() const128 int BytesRemaining() const {
129 return size_ - used_;
130 }
131
132 // Seeks to an arbitrary point in the buffer. The notion of bytes consumed
133 // and remaining are updated appropriately.
SetOffset(int bytes)134 void SetOffset(int bytes) {
135 DCHECK_GE(bytes, 0);
136 DCHECK_LE(bytes, size_);
137 used_ = bytes;
138 data_ = real_data_ + used_;
139 }
140
141 // Called after data is added to the buffer. Adds |bytes| added to
142 // |size_|. data() is unaffected.
DidAppend(int bytes)143 void DidAppend(int bytes) {
144 DCHECK_GE(bytes, 0);
145 DCHECK_GE(size_ + bytes, 0);
146 DCHECK_LE(size_ + bytes, capacity_);
147 size_ += bytes;
148 }
149
150 // Changes the logical size to 0, and the offset to 0.
Clear()151 void Clear() {
152 size_ = 0;
153 SetOffset(0);
154 }
155
156 // Returns the logical size of the buffer (i.e the number of bytes of data
157 // in the buffer).
size() const158 int size() const { return size_; }
159
160 // Returns the capacity of the buffer. The capacity is the size used when
161 // the object is created.
capacity() const162 int capacity() const { return capacity_; }
163
164 private:
~SeekableIOBuffer()165 ~SeekableIOBuffer() override {
166 // data_ will be deleted in IOBuffer::~IOBuffer().
167 data_ = real_data_;
168 }
169
170 // DanglingUntriaged because it is assigned a DanglingUntriaged pointer.
171 raw_ptr<char, AcrossTasksDanglingUntriaged | AllowPtrArithmetic> real_data_;
172 const int capacity_;
173 int size_ = 0;
174 int used_ = 0;
175 };
176
177 // 2 CRLFs + max of 8 hex chars.
178 const size_t HttpStreamParser::kChunkHeaderFooterSize = 12;
179
HttpStreamParser(StreamSocket * stream_socket,bool connection_is_reused,const HttpRequestInfo * request,GrowableIOBuffer * read_buffer,const NetLogWithSource & net_log)180 HttpStreamParser::HttpStreamParser(StreamSocket* stream_socket,
181 bool connection_is_reused,
182 const HttpRequestInfo* request,
183 GrowableIOBuffer* read_buffer,
184 const NetLogWithSource& net_log)
185 : request_(request),
186 read_buf_(read_buffer),
187 response_header_start_offset_(std::string::npos),
188 stream_socket_(stream_socket),
189 connection_is_reused_(connection_is_reused),
190 net_log_(net_log) {
191 io_callback_ = base::BindRepeating(&HttpStreamParser::OnIOComplete,
192 weak_ptr_factory_.GetWeakPtr());
193 }
194
195 HttpStreamParser::~HttpStreamParser() = default;
196
SendRequest(const std::string & request_line,const HttpRequestHeaders & headers,const NetworkTrafficAnnotationTag & traffic_annotation,HttpResponseInfo * response,CompletionOnceCallback callback)197 int HttpStreamParser::SendRequest(
198 const std::string& request_line,
199 const HttpRequestHeaders& headers,
200 const NetworkTrafficAnnotationTag& traffic_annotation,
201 HttpResponseInfo* response,
202 CompletionOnceCallback callback) {
203 DCHECK_EQ(STATE_NONE, io_state_);
204 DCHECK(callback_.is_null());
205 DCHECK(!callback.is_null());
206 DCHECK(response);
207
208 NetLogRequestHeaders(net_log_,
209 NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
210 request_line, &headers);
211
212 DVLOG(1) << __func__ << "() request_line = \"" << request_line << "\""
213 << " headers = \"" << headers.ToString() << "\"";
214 traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation);
215 response_ = response;
216
217 // Put the peer's IP address and port into the response.
218 IPEndPoint ip_endpoint;
219 int result = stream_socket_->GetPeerAddress(&ip_endpoint);
220 if (result != OK)
221 return result;
222 response_->remote_endpoint = ip_endpoint;
223
224 std::string request = request_line + headers.ToString();
225 request_headers_length_ = request.size();
226
227 if (request_->upload_data_stream != nullptr) {
228 request_body_send_buf_ =
229 base::MakeRefCounted<SeekableIOBuffer>(kRequestBodyBufferSize);
230 if (request_->upload_data_stream->is_chunked()) {
231 // Read buffer is adjusted to guarantee that |request_body_send_buf_| is
232 // large enough to hold the encoded chunk.
233 request_body_read_buf_ = base::MakeRefCounted<SeekableIOBuffer>(
234 kRequestBodyBufferSize - kChunkHeaderFooterSize);
235 } else {
236 // No need to encode request body, just send the raw data.
237 request_body_read_buf_ = request_body_send_buf_;
238 }
239 }
240
241 io_state_ = STATE_SEND_HEADERS;
242
243 // If we have a small request body, then we'll merge with the headers into a
244 // single write.
245 bool did_merge = false;
246 if (ShouldMergeRequestHeadersAndBody(request, request_->upload_data_stream)) {
247 int merged_size = static_cast<int>(
248 request_headers_length_ + request_->upload_data_stream->size());
249 auto merged_request_headers_and_body =
250 base::MakeRefCounted<IOBufferWithSize>(merged_size);
251 // We'll repurpose |request_headers_| to store the merged headers and
252 // body.
253 request_headers_ = base::MakeRefCounted<DrainableIOBuffer>(
254 merged_request_headers_and_body, merged_size);
255
256 memcpy(request_headers_->data(), request.data(), request_headers_length_);
257 request_headers_->DidConsume(request_headers_length_);
258
259 uint64_t todo = request_->upload_data_stream->size();
260 while (todo) {
261 int consumed = request_->upload_data_stream->Read(
262 request_headers_.get(), static_cast<int>(todo),
263 CompletionOnceCallback());
264 // Read() must succeed synchronously if not chunked and in memory.
265 DCHECK_GT(consumed, 0);
266 request_headers_->DidConsume(consumed);
267 todo -= consumed;
268 }
269 DCHECK(request_->upload_data_stream->IsEOF());
270 // Reset the offset, so the buffer can be read from the beginning.
271 request_headers_->SetOffset(0);
272 did_merge = true;
273
274 NetLogSendRequestBody(net_log_, request_->upload_data_stream->size(),
275 false, /* not chunked */
276 true /* merged */);
277 }
278
279 if (!did_merge) {
280 // If we didn't merge the body with the headers, then |request_headers_|
281 // contains just the HTTP headers.
282 size_t request_size = request.size();
283 scoped_refptr<StringIOBuffer> headers_io_buf =
284 base::MakeRefCounted<StringIOBuffer>(std::move(request));
285 request_headers_ = base::MakeRefCounted<DrainableIOBuffer>(
286 std::move(headers_io_buf), request_size);
287 }
288
289 result = DoLoop(OK);
290 if (result == ERR_IO_PENDING)
291 callback_ = std::move(callback);
292
293 return result > 0 ? OK : result;
294 }
295
ConfirmHandshake(CompletionOnceCallback callback)296 int HttpStreamParser::ConfirmHandshake(CompletionOnceCallback callback) {
297 int ret = stream_socket_->ConfirmHandshake(
298 base::BindOnce(&HttpStreamParser::RunConfirmHandshakeCallback,
299 weak_ptr_factory_.GetWeakPtr()));
300 if (ret == ERR_IO_PENDING)
301 confirm_handshake_callback_ = std::move(callback);
302 return ret;
303 }
304
ReadResponseHeaders(CompletionOnceCallback callback)305 int HttpStreamParser::ReadResponseHeaders(CompletionOnceCallback callback) {
306 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE);
307 DCHECK(callback_.is_null());
308 DCHECK(!callback.is_null());
309 DCHECK_EQ(0, read_buf_unused_offset_);
310 DCHECK(SendRequestBuffersEmpty());
311
312 // This function can be called with io_state_ == STATE_DONE if the
313 // connection is closed after seeing just a 1xx response code.
314 if (io_state_ == STATE_DONE)
315 return ERR_CONNECTION_CLOSED;
316
317 int result = OK;
318 io_state_ = STATE_READ_HEADERS;
319
320 if (read_buf_->offset() > 0) {
321 // Simulate the state where the data was just read from the socket.
322 result = read_buf_->offset();
323 read_buf_->set_offset(0);
324 }
325 if (result > 0)
326 io_state_ = STATE_READ_HEADERS_COMPLETE;
327
328 result = DoLoop(result);
329 if (result == ERR_IO_PENDING)
330 callback_ = std::move(callback);
331
332 return result > 0 ? OK : result;
333 }
334
ReadResponseBody(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)335 int HttpStreamParser::ReadResponseBody(IOBuffer* buf,
336 int buf_len,
337 CompletionOnceCallback callback) {
338 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE);
339 DCHECK(callback_.is_null());
340 DCHECK(!callback.is_null());
341 DCHECK_LE(buf_len, kMaxBufSize);
342 DCHECK(SendRequestBuffersEmpty());
343 // Added to investigate crbug.com/499663.
344 CHECK(buf);
345
346 if (io_state_ == STATE_DONE)
347 return OK;
348
349 user_read_buf_ = buf;
350 user_read_buf_len_ = buf_len;
351 io_state_ = STATE_READ_BODY;
352
353 // Invalidate HttpRequestInfo pointer. This is to allow the stream to be
354 // shared across multiple consumers.
355 // It is safe to reset it at this point since request_->upload_data_stream
356 // is also not needed anymore.
357 request_ = nullptr;
358
359 int result = DoLoop(OK);
360 if (result == ERR_IO_PENDING)
361 callback_ = std::move(callback);
362
363 return result;
364 }
365
OnIOComplete(int result)366 void HttpStreamParser::OnIOComplete(int result) {
367 result = DoLoop(result);
368
369 // The client callback can do anything, including destroying this class,
370 // so any pending callback must be issued after everything else is done.
371 if (result != ERR_IO_PENDING && !callback_.is_null()) {
372 std::move(callback_).Run(result);
373 }
374 }
375
DoLoop(int result)376 int HttpStreamParser::DoLoop(int result) {
377 do {
378 DCHECK_NE(ERR_IO_PENDING, result);
379 DCHECK_NE(STATE_DONE, io_state_);
380 DCHECK_NE(STATE_NONE, io_state_);
381 State state = io_state_;
382 io_state_ = STATE_NONE;
383 switch (state) {
384 case STATE_SEND_HEADERS:
385 DCHECK_EQ(OK, result);
386 result = DoSendHeaders();
387 DCHECK_NE(STATE_NONE, io_state_);
388 break;
389 case STATE_SEND_HEADERS_COMPLETE:
390 result = DoSendHeadersComplete(result);
391 DCHECK_NE(STATE_NONE, io_state_);
392 break;
393 case STATE_SEND_BODY:
394 DCHECK_EQ(OK, result);
395 result = DoSendBody();
396 DCHECK_NE(STATE_NONE, io_state_);
397 break;
398 case STATE_SEND_BODY_COMPLETE:
399 result = DoSendBodyComplete(result);
400 DCHECK_NE(STATE_NONE, io_state_);
401 break;
402 case STATE_SEND_REQUEST_READ_BODY_COMPLETE:
403 result = DoSendRequestReadBodyComplete(result);
404 DCHECK_NE(STATE_NONE, io_state_);
405 break;
406 case STATE_SEND_REQUEST_COMPLETE:
407 result = DoSendRequestComplete(result);
408 break;
409 case STATE_READ_HEADERS:
410 net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS);
411 DCHECK_GE(result, 0);
412 result = DoReadHeaders();
413 break;
414 case STATE_READ_HEADERS_COMPLETE:
415 result = DoReadHeadersComplete(result);
416 net_log_.EndEventWithNetErrorCode(
417 NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS, result);
418 break;
419 case STATE_READ_BODY:
420 DCHECK_GE(result, 0);
421 result = DoReadBody();
422 break;
423 case STATE_READ_BODY_COMPLETE:
424 result = DoReadBodyComplete(result);
425 break;
426 default:
427 NOTREACHED();
428 break;
429 }
430 } while (result != ERR_IO_PENDING &&
431 (io_state_ != STATE_DONE && io_state_ != STATE_NONE));
432
433 return result;
434 }
435
DoSendHeaders()436 int HttpStreamParser::DoSendHeaders() {
437 int bytes_remaining = request_headers_->BytesRemaining();
438 DCHECK_GT(bytes_remaining, 0);
439
440 // Record our best estimate of the 'request time' as the time when we send
441 // out the first bytes of the request headers.
442 if (bytes_remaining == request_headers_->size())
443 response_->request_time = base::Time::Now();
444
445 io_state_ = STATE_SEND_HEADERS_COMPLETE;
446 return stream_socket_->Write(
447 request_headers_.get(), bytes_remaining, io_callback_,
448 NetworkTrafficAnnotationTag(traffic_annotation_));
449 }
450
DoSendHeadersComplete(int result)451 int HttpStreamParser::DoSendHeadersComplete(int result) {
452 if (result < 0) {
453 // In the unlikely case that the headers and body were merged, all the
454 // the headers were sent, but not all of the body way, and |result| is
455 // an error that this should try reading after, stash the error for now and
456 // act like the request was successfully sent.
457 io_state_ = STATE_SEND_REQUEST_COMPLETE;
458 if (request_headers_->BytesConsumed() >= request_headers_length_ &&
459 ShouldTryReadingOnUploadError(result)) {
460 upload_error_ = result;
461 return OK;
462 }
463 return result;
464 }
465
466 sent_bytes_ += result;
467 request_headers_->DidConsume(result);
468 if (request_headers_->BytesRemaining() > 0) {
469 io_state_ = STATE_SEND_HEADERS;
470 return OK;
471 }
472
473 if (request_->upload_data_stream != nullptr &&
474 (request_->upload_data_stream->is_chunked() ||
475 // !IsEOF() indicates that the body wasn't merged.
476 (request_->upload_data_stream->size() > 0 &&
477 !request_->upload_data_stream->IsEOF()))) {
478 NetLogSendRequestBody(net_log_, request_->upload_data_stream->size(),
479 request_->upload_data_stream->is_chunked(),
480 false /* not merged */);
481 io_state_ = STATE_SEND_BODY;
482 return OK;
483 }
484
485 // Finished sending the request.
486 io_state_ = STATE_SEND_REQUEST_COMPLETE;
487 return OK;
488 }
489
DoSendBody()490 int HttpStreamParser::DoSendBody() {
491 if (request_body_send_buf_->BytesRemaining() > 0) {
492 io_state_ = STATE_SEND_BODY_COMPLETE;
493 return stream_socket_->Write(
494 request_body_send_buf_.get(), request_body_send_buf_->BytesRemaining(),
495 io_callback_, NetworkTrafficAnnotationTag(traffic_annotation_));
496 }
497
498 if (request_->upload_data_stream->is_chunked() && sent_last_chunk_) {
499 // Finished sending the request.
500 io_state_ = STATE_SEND_REQUEST_COMPLETE;
501 return OK;
502 }
503
504 request_body_read_buf_->Clear();
505 io_state_ = STATE_SEND_REQUEST_READ_BODY_COMPLETE;
506 return request_->upload_data_stream->Read(
507 request_body_read_buf_.get(), request_body_read_buf_->capacity(),
508 base::BindOnce(&HttpStreamParser::OnIOComplete,
509 weak_ptr_factory_.GetWeakPtr()));
510 }
511
DoSendBodyComplete(int result)512 int HttpStreamParser::DoSendBodyComplete(int result) {
513 if (result < 0) {
514 // If |result| is an error that this should try reading after, stash the
515 // error for now and act like the request was successfully sent.
516 io_state_ = STATE_SEND_REQUEST_COMPLETE;
517 if (ShouldTryReadingOnUploadError(result)) {
518 upload_error_ = result;
519 return OK;
520 }
521 return result;
522 }
523
524 sent_bytes_ += result;
525 request_body_send_buf_->DidConsume(result);
526
527 io_state_ = STATE_SEND_BODY;
528 return OK;
529 }
530
DoSendRequestReadBodyComplete(int result)531 int HttpStreamParser::DoSendRequestReadBodyComplete(int result) {
532 // |result| is the result of read from the request body from the last call to
533 // DoSendBody().
534 if (result < 0) {
535 io_state_ = STATE_SEND_REQUEST_COMPLETE;
536 return result;
537 }
538
539 // Chunked data needs to be encoded.
540 if (request_->upload_data_stream->is_chunked()) {
541 if (result == 0) { // Reached the end.
542 DCHECK(request_->upload_data_stream->IsEOF());
543 sent_last_chunk_ = true;
544 }
545 // Encode the buffer as 1 chunk.
546 const base::StringPiece payload(request_body_read_buf_->data(), result);
547 request_body_send_buf_->Clear();
548 result = EncodeChunk(payload,
549 request_body_send_buf_->data(),
550 request_body_send_buf_->capacity());
551 }
552
553 if (result == 0) { // Reached the end.
554 // Reaching EOF means we can finish sending request body unless the data is
555 // chunked. (i.e. No need to send the terminal chunk.)
556 DCHECK(request_->upload_data_stream->IsEOF());
557 DCHECK(!request_->upload_data_stream->is_chunked());
558 // Finished sending the request.
559 io_state_ = STATE_SEND_REQUEST_COMPLETE;
560 } else if (result > 0) {
561 request_body_send_buf_->DidAppend(result);
562 result = 0;
563 io_state_ = STATE_SEND_BODY;
564 }
565 return result;
566 }
567
DoSendRequestComplete(int result)568 int HttpStreamParser::DoSendRequestComplete(int result) {
569 DCHECK_NE(result, ERR_IO_PENDING);
570 request_headers_ = nullptr;
571 request_body_send_buf_ = nullptr;
572 request_body_read_buf_ = nullptr;
573
574 return result;
575 }
576
DoReadHeaders()577 int HttpStreamParser::DoReadHeaders() {
578 io_state_ = STATE_READ_HEADERS_COMPLETE;
579
580 // Grow the read buffer if necessary.
581 if (read_buf_->RemainingCapacity() == 0)
582 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
583
584 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
585 // See if the user is passing in an IOBuffer with a NULL |data_|.
586 CHECK(read_buf_->data());
587
588 return stream_socket_->Read(read_buf_.get(), read_buf_->RemainingCapacity(),
589 io_callback_);
590 }
591
DoReadHeadersComplete(int result)592 int HttpStreamParser::DoReadHeadersComplete(int result) {
593 // DoReadHeadersComplete is called with the result of Socket::Read, which is a
594 // (byte_count | error), and returns (error | OK).
595
596 result = HandleReadHeaderResult(result);
597
598 // TODO(mmenke): The code below is ugly and hacky. A much better and more
599 // flexible long term solution would be to separate out the read and write
600 // loops, though this would involve significant changes, both here and
601 // elsewhere (WebSockets, for instance).
602
603 // If still reading the headers, or there was no error uploading the request
604 // body, just return the result.
605 if (io_state_ == STATE_READ_HEADERS || upload_error_ == OK)
606 return result;
607
608 // If the result is ERR_IO_PENDING, |io_state_| should be STATE_READ_HEADERS.
609 DCHECK_NE(ERR_IO_PENDING, result);
610
611 // On errors, use the original error received when sending the request.
612 // The main cases where these are different is when there's a header-related
613 // error code, or when there's an ERR_CONNECTION_CLOSED, which can result in
614 // special handling of partial responses and HTTP/0.9 responses.
615 if (result < 0) {
616 // Nothing else to do. In the HTTP/0.9 or only partial headers received
617 // cases, can normally go to other states after an error reading headers.
618 io_state_ = STATE_DONE;
619 // Don't let caller see the headers.
620 response_->headers = nullptr;
621 return upload_error_;
622 }
623
624 // Skip over 1xx responses as usual, and allow 4xx/5xx error responses to
625 // override the error received while uploading the body.
626 int response_code_class = response_->headers->response_code() / 100;
627 if (response_code_class == 1 || response_code_class == 4 ||
628 response_code_class == 5) {
629 return result;
630 }
631
632 // All other status codes are not allowed after an error during upload, to
633 // make sure the consumer has some indication there was an error.
634
635 // Nothing else to do.
636 io_state_ = STATE_DONE;
637 // Don't let caller see the headers.
638 response_->headers = nullptr;
639 return upload_error_;
640 }
641
DoReadBody()642 int HttpStreamParser::DoReadBody() {
643 io_state_ = STATE_READ_BODY_COMPLETE;
644
645 // Added to investigate crbug.com/499663.
646 CHECK(user_read_buf_.get());
647
648 // There may be some data left over from reading the response headers.
649 if (read_buf_->offset()) {
650 int available = read_buf_->offset() - read_buf_unused_offset_;
651 if (available) {
652 CHECK_GT(available, 0);
653 int bytes_from_buffer = std::min(available, user_read_buf_len_);
654 memcpy(user_read_buf_->data(),
655 read_buf_->StartOfBuffer() + read_buf_unused_offset_,
656 bytes_from_buffer);
657 read_buf_unused_offset_ += bytes_from_buffer;
658 if (bytes_from_buffer == available) {
659 read_buf_->SetCapacity(0);
660 read_buf_unused_offset_ = 0;
661 }
662 return bytes_from_buffer;
663 } else {
664 read_buf_->SetCapacity(0);
665 read_buf_unused_offset_ = 0;
666 }
667 }
668
669 // Check to see if we're done reading.
670 if (IsResponseBodyComplete())
671 return 0;
672
673 DCHECK_EQ(0, read_buf_->offset());
674 return stream_socket_->Read(user_read_buf_.get(), user_read_buf_len_,
675 io_callback_);
676 }
677
DoReadBodyComplete(int result)678 int HttpStreamParser::DoReadBodyComplete(int result) {
679 // When the connection is closed, there are numerous ways to interpret it.
680 //
681 // - If a Content-Length header is present and the body contains exactly that
682 // number of bytes at connection close, the response is successful.
683 //
684 // - If a Content-Length header is present and the body contains fewer bytes
685 // than promised by the header at connection close, it may indicate that
686 // the connection was closed prematurely, or it may indicate that the
687 // server sent an invalid Content-Length header. Unfortunately, the invalid
688 // Content-Length header case does occur in practice and other browsers are
689 // tolerant of it. We choose to treat it as an error for now, but the
690 // download system treats it as a non-error, and URLRequestHttpJob also
691 // treats it as OK if the Content-Length is the post-decoded body content
692 // length.
693 //
694 // - If chunked encoding is used and the terminating chunk has been processed
695 // when the connection is closed, the response is successful.
696 //
697 // - If chunked encoding is used and the terminating chunk has not been
698 // processed when the connection is closed, it may indicate that the
699 // connection was closed prematurely or it may indicate that the server
700 // sent an invalid chunked encoding. We choose to treat it as
701 // an invalid chunked encoding.
702 //
703 // - If a Content-Length is not present and chunked encoding is not used,
704 // connection close is the only way to signal that the response is
705 // complete. Unfortunately, this also means that there is no way to detect
706 // early close of a connection. No error is returned.
707 if (result == 0 && !IsResponseBodyComplete() && CanFindEndOfResponse()) {
708 if (chunked_decoder_.get())
709 result = ERR_INCOMPLETE_CHUNKED_ENCODING;
710 else
711 result = ERR_CONTENT_LENGTH_MISMATCH;
712 }
713
714 if (result > 0)
715 received_bytes_ += result;
716
717 // Filter incoming data if appropriate. FilterBuf may return an error.
718 if (result > 0 && chunked_decoder_.get()) {
719 result = chunked_decoder_->FilterBuf(user_read_buf_->data(), result);
720 if (result == 0 && !chunked_decoder_->reached_eof()) {
721 // Don't signal completion of the Read call yet or else it'll look like
722 // we received end-of-file. Wait for more data.
723 io_state_ = STATE_READ_BODY;
724 return OK;
725 }
726 }
727
728 if (result > 0)
729 response_body_read_ += result;
730
731 if (result <= 0 || IsResponseBodyComplete()) {
732 io_state_ = STATE_DONE;
733
734 // Save the overflow data, which can be in two places. There may be
735 // some left over in |user_read_buf_|, plus there may be more
736 // in |read_buf_|. But the part left over in |user_read_buf_| must have
737 // come from the |read_buf_|, so there's room to put it back at the
738 // start first.
739 int additional_save_amount = read_buf_->offset() - read_buf_unused_offset_;
740 int save_amount = 0;
741 if (chunked_decoder_.get()) {
742 save_amount = chunked_decoder_->bytes_after_eof();
743 } else if (response_body_length_ >= 0) {
744 int64_t extra_data_read = response_body_read_ - response_body_length_;
745 if (extra_data_read > 0) {
746 save_amount = static_cast<int>(extra_data_read);
747 if (result > 0)
748 result -= save_amount;
749 }
750 }
751
752 CHECK_LE(save_amount + additional_save_amount, kMaxBufSize);
753 if (read_buf_->capacity() < save_amount + additional_save_amount) {
754 read_buf_->SetCapacity(save_amount + additional_save_amount);
755 }
756
757 if (save_amount) {
758 received_bytes_ -= save_amount;
759 memcpy(read_buf_->StartOfBuffer(), user_read_buf_->data() + result,
760 save_amount);
761 }
762 read_buf_->set_offset(save_amount);
763 if (additional_save_amount) {
764 memmove(read_buf_->data(),
765 read_buf_->StartOfBuffer() + read_buf_unused_offset_,
766 additional_save_amount);
767 read_buf_->set_offset(save_amount + additional_save_amount);
768 }
769 read_buf_unused_offset_ = 0;
770 } else {
771 // Now waiting for more of the body to be read.
772 user_read_buf_ = nullptr;
773 user_read_buf_len_ = 0;
774 }
775
776 return result;
777 }
778
HandleReadHeaderResult(int result)779 int HttpStreamParser::HandleReadHeaderResult(int result) {
780 DCHECK_EQ(0, read_buf_unused_offset_);
781
782 if (result == 0)
783 result = ERR_CONNECTION_CLOSED;
784
785 if (result == ERR_CONNECTION_CLOSED) {
786 // The connection closed without getting any more data.
787 if (read_buf_->offset() == 0) {
788 io_state_ = STATE_DONE;
789 // If the connection has not been reused, it may have been a 0-length
790 // HTTP/0.9 responses, but it was most likely an error, so just return
791 // ERR_EMPTY_RESPONSE instead. If the connection was reused, just pass
792 // on the original connection close error, as rather than being an
793 // empty HTTP/0.9 response it's much more likely the server closed the
794 // socket before it received the request.
795 if (!connection_is_reused_)
796 return ERR_EMPTY_RESPONSE;
797 return result;
798 }
799
800 // Accepting truncated headers over HTTPS is a potential security
801 // vulnerability, so just return an error in that case.
802 //
803 // If response_header_start_offset_ is std::string::npos, this may be a < 8
804 // byte HTTP/0.9 response. However, accepting such a response over HTTPS
805 // would allow a MITM to truncate an HTTP/1.x status line to look like a
806 // short HTTP/0.9 response if the peer put a record boundary at the first 8
807 // bytes. To ensure that all response headers received over HTTPS are
808 // pristine, treat such responses as errors.
809 //
810 // TODO(mmenke): Returning ERR_RESPONSE_HEADERS_TRUNCATED when a response
811 // looks like an HTTP/0.9 response is weird. Should either come up with
812 // another error code, or, better, disable HTTP/0.9 over HTTPS (and give
813 // that a new error code).
814 if (request_->url.SchemeIsCryptographic()) {
815 io_state_ = STATE_DONE;
816 return ERR_RESPONSE_HEADERS_TRUNCATED;
817 }
818
819 // Parse things as well as we can and let the caller decide what to do.
820 int end_offset;
821 if (response_header_start_offset_ != std::string::npos) {
822 // The response looks to be a truncated set of HTTP headers.
823 io_state_ = STATE_READ_BODY_COMPLETE;
824 end_offset = read_buf_->offset();
825 } else {
826 // The response is apparently using HTTP/0.9. Treat the entire response
827 // as the body.
828 end_offset = 0;
829 }
830 int rv = ParseResponseHeaders(end_offset);
831 if (rv < 0)
832 return rv;
833 return result;
834 }
835
836 if (result < 0) {
837 io_state_ = STATE_DONE;
838 return result;
839 }
840
841 // Record our best estimate of the 'response time' as the time when we read
842 // the first bytes of the response headers.
843 if (read_buf_->offset() == 0) {
844 response_->response_time = base::Time::Now();
845 // Also keep the time as base::TimeTicks for `first_response_start_time_`
846 // and `non_informational_response_start_time_`.
847 current_response_start_time_ = base::TimeTicks::Now();
848 }
849
850 // For |first_response_start_time_|, use the time that we received the first
851 // byte of *any* response- including 1XX, as per the resource timing spec for
852 // responseStart (see note at
853 // https://www.w3.org/TR/resource-timing-2/#dom-performanceresourcetiming-responsestart).
854 if (first_response_start_time_.is_null())
855 first_response_start_time_ = current_response_start_time_;
856
857 read_buf_->set_offset(read_buf_->offset() + result);
858 DCHECK_LE(read_buf_->offset(), read_buf_->capacity());
859 DCHECK_GT(result, 0);
860
861 int end_of_header_offset = FindAndParseResponseHeaders(result);
862
863 // Note: -1 is special, it indicates we haven't found the end of headers.
864 // Anything less than -1 is a net::Error, so we bail out.
865 if (end_of_header_offset < -1)
866 return end_of_header_offset;
867
868 if (end_of_header_offset == -1) {
869 io_state_ = STATE_READ_HEADERS;
870 // Prevent growing the headers buffer indefinitely.
871 if (read_buf_->offset() >= kMaxHeaderBufSize) {
872 io_state_ = STATE_DONE;
873 return ERR_RESPONSE_HEADERS_TOO_BIG;
874 }
875 } else {
876 CalculateResponseBodySize();
877
878 // If the body is zero length, the caller may not call ReadResponseBody,
879 // which is where any extra data is copied to read_buf_, so we move the
880 // data here.
881 if (response_body_length_ == 0) {
882 int extra_bytes = read_buf_->offset() - end_of_header_offset;
883 if (extra_bytes) {
884 CHECK_GT(extra_bytes, 0);
885 memmove(read_buf_->StartOfBuffer(),
886 read_buf_->StartOfBuffer() + end_of_header_offset,
887 extra_bytes);
888 }
889 read_buf_->SetCapacity(extra_bytes);
890 if (response_->headers->response_code() / 100 == 1) {
891 // After processing a 1xx response, the caller will ask for the next
892 // header, so reset state to support that. We don't completely ignore a
893 // 1xx response because it cannot be returned in reply to a CONNECT
894 // request so we return OK here, which lets the caller inspect the
895 // response and reject it in the event that we're setting up a CONNECT
896 // tunnel.
897 response_header_start_offset_ = std::string::npos;
898 response_body_length_ = -1;
899 // Record the timing of the 103 Early Hints response for the experiment
900 // (https://crbug.com/1093693).
901 if (response_->headers->response_code() == net::HTTP_EARLY_HINTS &&
902 first_early_hints_time_.is_null()) {
903 first_early_hints_time_ = current_response_start_time_;
904 }
905 // Now waiting for the second set of headers to be read.
906 } else {
907 // Only set keep-alive based on final set of headers.
908 response_is_keep_alive_ = response_->headers->IsKeepAlive();
909
910 io_state_ = STATE_DONE;
911 }
912 return OK;
913 }
914
915 // Record the response start time if this response is not informational
916 // (non-1xx).
917 if (response_->headers->response_code() / 100 != 1) {
918 DCHECK(non_informational_response_start_time_.is_null());
919 non_informational_response_start_time_ = current_response_start_time_;
920 }
921
922 // Only set keep-alive based on final set of headers.
923 response_is_keep_alive_ = response_->headers->IsKeepAlive();
924
925 // Note where the headers stop.
926 read_buf_unused_offset_ = end_of_header_offset;
927 // Now waiting for the body to be read.
928 }
929 return OK;
930 }
931
RunConfirmHandshakeCallback(int rv)932 void HttpStreamParser::RunConfirmHandshakeCallback(int rv) {
933 std::move(confirm_handshake_callback_).Run(rv);
934 }
935
FindAndParseResponseHeaders(int new_bytes)936 int HttpStreamParser::FindAndParseResponseHeaders(int new_bytes) {
937 DCHECK_GT(new_bytes, 0);
938 DCHECK_EQ(0, read_buf_unused_offset_);
939 size_t end_offset = std::string::npos;
940
941 // Look for the start of the status line, if it hasn't been found yet.
942 if (response_header_start_offset_ == std::string::npos) {
943 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine(
944 read_buf_->StartOfBuffer(), read_buf_->offset());
945 }
946
947 if (response_header_start_offset_ != std::string::npos) {
948 // LocateEndOfHeaders looks for two line breaks in a row (With or without
949 // carriage returns). So the end of the headers includes at most the last 3
950 // bytes of the buffer from the past read. This optimization avoids O(n^2)
951 // performance in the case each read only returns a couple bytes. It's not
952 // too important in production, but for fuzzers with memory instrumentation,
953 // it's needed to avoid timing out.
954 size_t lower_bound =
955 (base::ClampedNumeric<size_t>(read_buf_->offset()) - new_bytes - 3)
956 .RawValue();
957 size_t search_start = std::max(response_header_start_offset_, lower_bound);
958 end_offset = HttpUtil::LocateEndOfHeaders(
959 read_buf_->StartOfBuffer(), read_buf_->offset(), search_start);
960 } else if (read_buf_->offset() >= 8) {
961 // Enough data to decide that this is an HTTP/0.9 response.
962 // 8 bytes = (4 bytes of junk) + "http".length()
963 end_offset = 0;
964 }
965
966 if (end_offset == std::string::npos)
967 return -1;
968
969 int rv = ParseResponseHeaders(end_offset);
970 if (rv < 0)
971 return rv;
972 return end_offset;
973 }
974
ParseResponseHeaders(int end_offset)975 int HttpStreamParser::ParseResponseHeaders(int end_offset) {
976 scoped_refptr<HttpResponseHeaders> headers;
977 DCHECK_EQ(0, read_buf_unused_offset_);
978
979 if (response_header_start_offset_ != std::string::npos) {
980 received_bytes_ += end_offset;
981 headers = HttpResponseHeaders::TryToCreate(
982 base::StringPiece(read_buf_->StartOfBuffer(), end_offset));
983 if (!headers)
984 return net::ERR_INVALID_HTTP_RESPONSE;
985 has_seen_status_line_ = true;
986 } else {
987 // Enough data was read -- there is no status line, so this is HTTP/0.9, or
988 // the server is broken / doesn't speak HTTP.
989
990 if (has_seen_status_line_) {
991 // If we saw a status line previously, the server can speak HTTP/1.x so it
992 // is not reasonable to interpret the response as an HTTP/0.9 response.
993 return ERR_INVALID_HTTP_RESPONSE;
994 }
995
996 base::StringPiece scheme = request_->url.scheme_piece();
997 if (url::DefaultPortForScheme(scheme.data(), scheme.length()) !=
998 request_->url.EffectiveIntPort()) {
999 // If the port is not the default for the scheme, assume it's not a real
1000 // HTTP/0.9 response, and fail the request.
1001
1002 // Allow Shoutcast responses over HTTP, as it's somewhat common and relies
1003 // on HTTP/0.9 on weird ports to work.
1004 // See
1005 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/qS63pYso4P0
1006 if (read_buf_->offset() < 3 || scheme != "http" ||
1007 !base::EqualsCaseInsensitiveASCII(
1008 base::StringPiece(read_buf_->StartOfBuffer(), 3), "icy")) {
1009 return ERR_INVALID_HTTP_RESPONSE;
1010 }
1011 }
1012
1013 headers = base::MakeRefCounted<HttpResponseHeaders>(
1014 std::string("HTTP/0.9 200 OK"));
1015 }
1016
1017 // Check for multiple Content-Length headers when the response is not
1018 // chunked-encoded. If they exist, and have distinct values, it's a potential
1019 // response smuggling attack.
1020 if (!headers->IsChunkEncoded()) {
1021 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
1022 "Content-Length"))
1023 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH;
1024 }
1025
1026 // Check for multiple Content-Disposition or Location headers. If they exist,
1027 // it's also a potential response smuggling attack.
1028 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
1029 "Content-Disposition"))
1030 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION;
1031 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers, "Location"))
1032 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION;
1033
1034 response_->headers = headers;
1035 if (headers->GetHttpVersion() == HttpVersion(0, 9)) {
1036 response_->connection_info = HttpConnectionInfo::kHTTP0_9;
1037 } else if (headers->GetHttpVersion() == HttpVersion(1, 0)) {
1038 response_->connection_info = HttpConnectionInfo::kHTTP1_0;
1039 } else if (headers->GetHttpVersion() == HttpVersion(1, 1)) {
1040 response_->connection_info = HttpConnectionInfo::kHTTP1_1;
1041 }
1042 DVLOG(1) << __func__ << "() content_length = \""
1043 << response_->headers->GetContentLength() << "\n\""
1044 << " headers = \"" << GetResponseHeaderLines(*response_->headers)
1045 << "\"";
1046 return OK;
1047 }
1048
CalculateResponseBodySize()1049 void HttpStreamParser::CalculateResponseBodySize() {
1050 // Figure how to determine EOF:
1051
1052 // For certain responses, we know the content length is always 0. From
1053 // RFC 7230 Section 3.3 Message Body:
1054 //
1055 // The presence of a message body in a response depends on both the
1056 // request method to which it is responding and the response status code
1057 // (Section 3.1.2). Responses to the HEAD request method (Section 4.3.2
1058 // of [RFC7231]) never include a message body because the associated
1059 // response header fields (e.g., Transfer-Encoding, Content-Length,
1060 // etc.), if present, indicate only what their values would have been if
1061 // the request method had been GET (Section 4.3.1 of [RFC7231]). 2xx
1062 // (Successful) responses to a CONNECT request method (Section 4.3.6 of
1063 // [RFC7231]) switch to tunnel mode instead of having a message body.
1064 // All 1xx (Informational), 204 (No Content), and 304 (Not Modified)
1065 // responses do not include a message body. All other responses do
1066 // include a message body, although the body might be of zero length.
1067 //
1068 // From RFC 7231 Section 6.3.6 205 Reset Content:
1069 //
1070 // Since the 205 status code implies that no additional content will be
1071 // provided, a server MUST NOT generate a payload in a 205 response.
1072 if (response_->headers->response_code() / 100 == 1) {
1073 response_body_length_ = 0;
1074 } else {
1075 switch (response_->headers->response_code()) {
1076 case net::HTTP_NO_CONTENT: // No Content
1077 case net::HTTP_RESET_CONTENT: // Reset Content
1078 case net::HTTP_NOT_MODIFIED: // Not Modified
1079 response_body_length_ = 0;
1080 break;
1081 }
1082 }
1083 if (request_->method == "HEAD")
1084 response_body_length_ = 0;
1085
1086 if (response_body_length_ == -1) {
1087 // "Transfer-Encoding: chunked" trumps "Content-Length: N"
1088 if (response_->headers->IsChunkEncoded()) {
1089 chunked_decoder_ = std::make_unique<HttpChunkedDecoder>();
1090 } else {
1091 response_body_length_ = response_->headers->GetContentLength();
1092 // If response_body_length_ is still -1, then we have to wait
1093 // for the server to close the connection.
1094 }
1095 }
1096 }
1097
IsResponseBodyComplete() const1098 bool HttpStreamParser::IsResponseBodyComplete() const {
1099 if (chunked_decoder_.get())
1100 return chunked_decoder_->reached_eof();
1101 if (response_body_length_ != -1)
1102 return response_body_read_ >= response_body_length_;
1103
1104 return false; // Must read to EOF.
1105 }
1106
CanFindEndOfResponse() const1107 bool HttpStreamParser::CanFindEndOfResponse() const {
1108 return chunked_decoder_.get() || response_body_length_ >= 0;
1109 }
1110
IsMoreDataBuffered() const1111 bool HttpStreamParser::IsMoreDataBuffered() const {
1112 return read_buf_->offset() > read_buf_unused_offset_;
1113 }
1114
CanReuseConnection() const1115 bool HttpStreamParser::CanReuseConnection() const {
1116 if (!CanFindEndOfResponse())
1117 return false;
1118
1119 if (!response_is_keep_alive_)
1120 return false;
1121
1122 // Check if extra data was received after reading the entire response body. If
1123 // extra data was received, reusing the socket is not a great idea. This does
1124 // have the down side of papering over certain server bugs, but seems to be
1125 // the best option here.
1126 //
1127 // TODO(mmenke): Consider logging this - hard to decipher socket reuse
1128 // behavior makes NetLogs harder to read.
1129 if (IsResponseBodyComplete() && IsMoreDataBuffered())
1130 return false;
1131
1132 return stream_socket_->IsConnected();
1133 }
1134
OnConnectionClose()1135 void HttpStreamParser::OnConnectionClose() {
1136 // This is to ensure `stream_socket_` doesn't get dangling on connection
1137 // close.
1138 stream_socket_ = nullptr;
1139 }
1140
GetSSLCertRequestInfo(SSLCertRequestInfo * cert_request_info)1141 void HttpStreamParser::GetSSLCertRequestInfo(
1142 SSLCertRequestInfo* cert_request_info) {
1143 cert_request_info->Reset();
1144 if (request_->url.SchemeIsCryptographic())
1145 stream_socket_->GetSSLCertRequestInfo(cert_request_info);
1146 }
1147
EncodeChunk(base::StringPiece payload,char * output,size_t output_size)1148 int HttpStreamParser::EncodeChunk(base::StringPiece payload,
1149 char* output,
1150 size_t output_size) {
1151 if (output_size < payload.size() + kChunkHeaderFooterSize)
1152 return ERR_INVALID_ARGUMENT;
1153
1154 char* cursor = output;
1155 // Add the header.
1156 const int num_chars = base::snprintf(output, output_size,
1157 "%X\r\n",
1158 static_cast<int>(payload.size()));
1159 cursor += num_chars;
1160 // Add the payload if any.
1161 if (payload.size() > 0) {
1162 memcpy(cursor, payload.data(), payload.size());
1163 cursor += payload.size();
1164 }
1165 // Add the trailing CRLF.
1166 memcpy(cursor, "\r\n", 2);
1167 cursor += 2;
1168
1169 return cursor - output;
1170 }
1171
1172 // static
ShouldMergeRequestHeadersAndBody(const std::string & request_headers,const UploadDataStream * request_body)1173 bool HttpStreamParser::ShouldMergeRequestHeadersAndBody(
1174 const std::string& request_headers,
1175 const UploadDataStream* request_body) {
1176 if (request_body != nullptr &&
1177 // IsInMemory() ensures that the request body is not chunked.
1178 request_body->IsInMemory() && request_body->size() > 0) {
1179 uint64_t merged_size = request_headers.size() + request_body->size();
1180 if (merged_size <= kMaxMergedHeaderAndBodySize)
1181 return true;
1182 }
1183 return false;
1184 }
1185
SendRequestBuffersEmpty()1186 bool HttpStreamParser::SendRequestBuffersEmpty() {
1187 return request_headers_ == nullptr && request_body_send_buf_ == nullptr &&
1188 request_body_read_buf_ == nullptr;
1189 }
1190
1191 } // namespace net
1192