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