• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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