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