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