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