• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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