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