xref: /aosp_15_r20/external/cronet/net/http/http_basic_stream.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_basic_stream.h"
6 
7 #include <set>
8 #include <string_view>
9 #include <utility>
10 
11 #include "base/functional/bind.h"
12 #include "net/http/http_network_session.h"
13 #include "net/http/http_raw_request_headers.h"
14 #include "net/http/http_request_info.h"
15 #include "net/http/http_response_body_drainer.h"
16 #include "net/http/http_stream_parser.h"
17 #include "net/socket/client_socket_handle.h"
18 #include "net/ssl/ssl_cert_request_info.h"
19 #include "net/ssl/ssl_info.h"
20 
21 namespace net {
22 
HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection,bool is_for_get_to_http_proxy)23 HttpBasicStream::HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection,
24                                  bool is_for_get_to_http_proxy)
25     : state_(std::move(connection), is_for_get_to_http_proxy) {}
26 
27 HttpBasicStream::~HttpBasicStream() = default;
28 
RegisterRequest(const HttpRequestInfo * request_info)29 void HttpBasicStream::RegisterRequest(const HttpRequestInfo* request_info) {
30   DCHECK(request_info);
31   DCHECK(request_info->traffic_annotation.is_valid());
32   request_info_ = request_info;
33 }
34 
InitializeStream(bool can_send_early,RequestPriority priority,const NetLogWithSource & net_log,CompletionOnceCallback callback)35 int HttpBasicStream::InitializeStream(bool can_send_early,
36                                       RequestPriority priority,
37                                       const NetLogWithSource& net_log,
38                                       CompletionOnceCallback callback) {
39   DCHECK(request_info_);
40   state_.Initialize(request_info_, priority, net_log);
41   int ret = OK;
42   if (!can_send_early) {
43     // parser() cannot outlive |this|, so we can use base::Unretained().
44     ret = parser()->ConfirmHandshake(
45         base::BindOnce(&HttpBasicStream::OnHandshakeConfirmed,
46                        base::Unretained(this), std::move(callback)));
47   }
48   // RequestInfo is no longer needed after this point.
49   request_info_ = nullptr;
50   return ret;
51 }
52 
SendRequest(const HttpRequestHeaders & headers,HttpResponseInfo * response,CompletionOnceCallback callback)53 int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers,
54                                  HttpResponseInfo* response,
55                                  CompletionOnceCallback callback) {
56   DCHECK(parser());
57   if (request_headers_callback_) {
58     HttpRawRequestHeaders raw_headers;
59     raw_headers.set_request_line(state_.GenerateRequestLine());
60     for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();)
61       raw_headers.Add(it.name(), it.value());
62     request_headers_callback_.Run(std::move(raw_headers));
63   }
64   return parser()->SendRequest(
65       state_.GenerateRequestLine(), headers,
66       NetworkTrafficAnnotationTag(state_.traffic_annotation()), response,
67       std::move(callback));
68 }
69 
ReadResponseHeaders(CompletionOnceCallback callback)70 int HttpBasicStream::ReadResponseHeaders(CompletionOnceCallback callback) {
71   return parser()->ReadResponseHeaders(std::move(callback));
72 }
73 
ReadResponseBody(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)74 int HttpBasicStream::ReadResponseBody(IOBuffer* buf,
75                                       int buf_len,
76                                       CompletionOnceCallback callback) {
77   return parser()->ReadResponseBody(buf, buf_len, std::move(callback));
78 }
79 
Close(bool not_reusable)80 void HttpBasicStream::Close(bool not_reusable) {
81   // parser() is null if |this| is created by an orphaned HttpStreamFactory::Job
82   // in which case InitializeStream() will not have been called. This also
83   // protects against null dereference in the case where
84   // state_.ReleaseConnection() has been called.
85   //
86   // TODO(mmenke):  Can these cases be handled a bit more cleanly?
87   // WebSocketHandshakeStream will need to be updated as well.
88   if (!parser())
89     return;
90   StreamSocket* socket = state_.connection()->socket();
91   if (not_reusable && socket)
92     socket->Disconnect();
93   parser()->OnConnectionClose();
94   state_.connection()->Reset();
95 }
96 
RenewStreamForAuth()97 std::unique_ptr<HttpStream> HttpBasicStream::RenewStreamForAuth() {
98   DCHECK(IsResponseBodyComplete());
99   DCHECK(!parser()->IsMoreDataBuffered());
100   // The HttpStreamParser object still has a pointer to the connection. Just to
101   // be extra-sure it doesn't touch the connection again, delete it here rather
102   // than leaving it until the destructor is called.
103   state_.DeleteParser();
104   return std::make_unique<HttpBasicStream>(state_.ReleaseConnection(),
105                                            state_.is_for_get_to_http_proxy());
106 }
107 
IsResponseBodyComplete() const108 bool HttpBasicStream::IsResponseBodyComplete() const {
109   return parser()->IsResponseBodyComplete();
110 }
111 
IsConnectionReused() const112 bool HttpBasicStream::IsConnectionReused() const {
113   return state_.IsConnectionReused();
114 }
115 
SetConnectionReused()116 void HttpBasicStream::SetConnectionReused() {
117   state_.connection()->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
118 }
119 
CanReuseConnection() const120 bool HttpBasicStream::CanReuseConnection() const {
121   return parser() && state_.connection()->socket() &&
122          parser()->CanReuseConnection();
123 }
124 
GetTotalReceivedBytes() const125 int64_t HttpBasicStream::GetTotalReceivedBytes() const {
126   if (parser())
127     return parser()->received_bytes();
128   return 0;
129 }
130 
GetTotalSentBytes() const131 int64_t HttpBasicStream::GetTotalSentBytes() const {
132   if (parser())
133     return parser()->sent_bytes();
134   return 0;
135 }
136 
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const137 bool HttpBasicStream::GetLoadTimingInfo(
138     LoadTimingInfo* load_timing_info) const {
139   if (!state_.connection()->GetLoadTimingInfo(IsConnectionReused(),
140                                               load_timing_info) ||
141       !parser()) {
142     return false;
143   }
144 
145   // If the request waited for handshake confirmation, shift |ssl_end| to
146   // include that time.
147   if (!load_timing_info->connect_timing.ssl_end.is_null() &&
148       !confirm_handshake_end_.is_null()) {
149     load_timing_info->connect_timing.ssl_end = confirm_handshake_end_;
150     load_timing_info->connect_timing.connect_end = confirm_handshake_end_;
151   }
152 
153   load_timing_info->receive_headers_start =
154       parser()->first_response_start_time();
155   load_timing_info->receive_non_informational_headers_start =
156       parser()->non_informational_response_start_time();
157   load_timing_info->first_early_hints_time = parser()->first_early_hints_time();
158   return true;
159 }
160 
GetAlternativeService(AlternativeService * alternative_service) const161 bool HttpBasicStream::GetAlternativeService(
162     AlternativeService* alternative_service) const {
163   return false;
164 }
165 
GetSSLInfo(SSLInfo * ssl_info)166 void HttpBasicStream::GetSSLInfo(SSLInfo* ssl_info) {
167   if (!state_.connection()->socket() ||
168       !state_.connection()->socket()->GetSSLInfo(ssl_info)) {
169     ssl_info->Reset();
170   }
171 }
172 
GetRemoteEndpoint(IPEndPoint * endpoint)173 int HttpBasicStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
174   if (!state_.connection() || !state_.connection()->socket())
175     return ERR_SOCKET_NOT_CONNECTED;
176 
177   return state_.connection()->socket()->GetPeerAddress(endpoint);
178 }
179 
Drain(HttpNetworkSession * session)180 void HttpBasicStream::Drain(HttpNetworkSession* session) {
181   session->StartResponseDrainer(
182       std::make_unique<HttpResponseBodyDrainer>(this));
183   // |drainer| will delete itself.
184 }
185 
PopulateNetErrorDetails(NetErrorDetails * details)186 void HttpBasicStream::PopulateNetErrorDetails(NetErrorDetails* details) {
187   // TODO(mmenke):  Consumers don't actually care about HTTP version, but seems
188   // like the right version should be reported, if headers were received.
189   details->connection_info = HttpConnectionInfo::kHTTP1_1;
190   return;
191 }
192 
SetPriority(RequestPriority priority)193 void HttpBasicStream::SetPriority(RequestPriority priority) {
194   // TODO(akalin): Plumb this through to |connection_|.
195 }
196 
SetRequestHeadersCallback(RequestHeadersCallback callback)197 void HttpBasicStream::SetRequestHeadersCallback(
198     RequestHeadersCallback callback) {
199   request_headers_callback_ = std::move(callback);
200 }
201 
GetDnsAliases() const202 const std::set<std::string>& HttpBasicStream::GetDnsAliases() const {
203   return state_.GetDnsAliases();
204 }
205 
GetAcceptChViaAlps() const206 std::string_view HttpBasicStream::GetAcceptChViaAlps() const {
207   return {};
208 }
209 
OnHandshakeConfirmed(CompletionOnceCallback callback,int rv)210 void HttpBasicStream::OnHandshakeConfirmed(CompletionOnceCallback callback,
211                                            int rv) {
212   if (rv == OK) {
213     // Note this time is only recorded if ConfirmHandshake() completed
214     // asynchronously. If it was synchronous, GetLoadTimingInfo() assumes the
215     // handshake was already confirmed or there was nothing to confirm.
216     confirm_handshake_end_ = base::TimeTicks::Now();
217   }
218   std::move(callback).Run(rv);
219 }
220 
221 }  // namespace net
222