Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(808)

Side by Side Diff: net/quic/quic_http_stream.cc

Issue 1692253004: QUIC - chromium server push support. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review feedback round 1 Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/quic_http_stream.h" 5 #include "net/quic/quic_http_stream.h"
6 6
7 #include "base/callback_helpers.h" 7 #include "base/callback_helpers.h"
8 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_split.h"
9 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
10 #include "net/base/io_buffer.h" 11 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h" 12 #include "net/base/net_errors.h"
12 #include "net/http/http_response_headers.h" 13 #include "net/http/http_response_headers.h"
13 #include "net/http/http_util.h" 14 #include "net/http/http_util.h"
14 #include "net/quic/quic_chromium_client_session.h" 15 #include "net/quic/quic_chromium_client_session.h"
15 #include "net/quic/quic_chromium_client_stream.h" 16 #include "net/quic/quic_chromium_client_stream.h"
17 #include "net/quic/quic_client_promised_info.h"
16 #include "net/quic/quic_http_utils.h" 18 #include "net/quic/quic_http_utils.h"
17 #include "net/quic/quic_utils.h" 19 #include "net/quic/quic_utils.h"
18 #include "net/quic/spdy_utils.h" 20 #include "net/quic/spdy_utils.h"
19 #include "net/socket/next_proto.h" 21 #include "net/socket/next_proto.h"
20 #include "net/spdy/spdy_frame_builder.h" 22 #include "net/spdy/spdy_frame_builder.h"
21 #include "net/spdy/spdy_framer.h" 23 #include "net/spdy/spdy_framer.h"
22 #include "net/spdy/spdy_http_utils.h" 24 #include "net/spdy/spdy_http_utils.h"
23 #include "net/ssl/ssl_info.h" 25 #include "net/ssl/ssl_info.h"
24 26
25 namespace net { 27 namespace net {
(...skipping 10 matching lines...) Expand all
36 priority_(MINIMUM_PRIORITY), 38 priority_(MINIMUM_PRIORITY),
37 response_info_(nullptr), 39 response_info_(nullptr),
38 response_status_(OK), 40 response_status_(OK),
39 response_headers_received_(false), 41 response_headers_received_(false),
40 headers_bytes_received_(0), 42 headers_bytes_received_(0),
41 headers_bytes_sent_(0), 43 headers_bytes_sent_(0),
42 closed_stream_received_bytes_(0), 44 closed_stream_received_bytes_(0),
43 closed_stream_sent_bytes_(0), 45 closed_stream_sent_bytes_(0),
44 user_buffer_len_(0), 46 user_buffer_len_(0),
45 quic_connection_error_(QUIC_NO_ERROR), 47 quic_connection_error_(QUIC_NO_ERROR),
48 found_promise_(false),
49 push_handle_(nullptr),
46 weak_factory_(this) { 50 weak_factory_(this) {
47 DCHECK(session_); 51 DCHECK(session_);
48 session_->AddObserver(this); 52 session_->AddObserver(this);
49 } 53 }
50 54
51 QuicHttpStream::~QuicHttpStream() { 55 QuicHttpStream::~QuicHttpStream() {
52 Close(false); 56 Close(false);
53 if (session_) 57 if (session_)
54 session_->RemoveObserver(this); 58 session_->RemoveObserver(this);
55 } 59 }
56 60
61 bool QuicHttpStream::CheckVary(const SpdyHeaderBlock& client_request,
62 const SpdyHeaderBlock& promise_request,
63 const SpdyHeaderBlock& promise_response) {
64 HttpResponseInfo promise_response_info;
65
66 HttpRequestInfo promise_request_info;
67 ConvertHeaderBlockToHttpRequestHeaders(promise_request,
68 &promise_request_info.extra_headers);
69 HttpRequestInfo client_request_info;
70 ConvertHeaderBlockToHttpRequestHeaders(client_request,
71 &client_request_info.extra_headers);
72
73 if (!SpdyHeadersToHttpResponse(promise_response, HTTP2,
74 &promise_response_info)) {
75 DLOG(WARNING) << "Invalid headers";
76 return false;
77 }
78
79 HttpVaryData vary_data;
80 if (!vary_data.Init(promise_request_info,
81 *promise_response_info.headers.get())) {
82 // Promise didn't contain valid vary info, so URL match was sufficient.
83 return true;
84 }
85 // Now compare the client request for matching.
86 return vary_data.MatchesRequest(client_request_info,
87 *promise_response_info.headers.get());
88 }
89
90 void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) {
91 push_handle_ = nullptr;
92 if (stream) {
93 stream_ = static_cast<QuicChromiumClientStream*>(stream);
94 stream_->SetDelegate(this);
95 }
96 // callback_ should be non-null in the case of asynchronous
97 // rendezvous; i.e. |Try()| returned QUIC_PENDING.
98 if (!callback_.is_null()) {
99 if (stream) {
100 next_state_ = STATE_OPEN;
101 DoCallback(OK);
102 return;
103 }
104 // rendezvous has failed so proceed as with a non-push request.
105 next_state_ = STATE_REQUEST_STREAM;
106 OnIOComplete(OK);
107 }
108 }
109
57 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, 110 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
58 RequestPriority priority, 111 RequestPriority priority,
59 const BoundNetLog& stream_net_log, 112 const BoundNetLog& stream_net_log,
60 const CompletionCallback& callback) { 113 const CompletionCallback& callback) {
61 DCHECK(!stream_); 114 DCHECK(!stream_);
62 if (!session_) 115 if (!session_)
63 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED 116 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
64 : ERR_QUIC_HANDSHAKE_FAILED; 117 : ERR_QUIC_HANDSHAKE_FAILED;
65 118
66 stream_net_log.AddEvent( 119 stream_net_log.AddEvent(
67 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION, 120 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
68 session_->net_log().source().ToEventParametersCallback()); 121 session_->net_log().source().ToEventParametersCallback());
69 122
70 stream_net_log_ = stream_net_log; 123 stream_net_log_ = stream_net_log;
71 request_info_ = request_info; 124 request_info_ = request_info;
72 request_time_ = base::Time::Now(); 125 request_time_ = base::Time::Now();
73 priority_ = priority; 126 priority_ = priority;
74 127
75 bool success = session_->GetSSLInfo(&ssl_info_); 128 bool success = session_->GetSSLInfo(&ssl_info_);
76 DCHECK(success); 129 DCHECK(success);
77 DCHECK(ssl_info_.cert.get()); 130 DCHECK(ssl_info_.cert.get());
78 131
132 if (session_->push_promise_index()->GetPromised(request_info->url.spec())) {
133 // A PUSH_PROMISE frame for this URL has arrived, next steps of
134 // the rendezvous will happen in |SendRequest()| when the browser
135 // request headers (required for push validation) are available.
136 found_promise_ = true;
137 return OK;
138 }
139
140 next_state_ = STATE_REQUEST_STREAM;
141 int rv = DoLoop(OK);
142 if (rv == ERR_IO_PENDING)
143 callback_ = callback;
144
145 return rv;
146 }
147
148 int QuicHttpStream::DoStreamRequest() {
79 int rv = stream_request_.StartRequest( 149 int rv = stream_request_.StartRequest(
80 session_, &stream_, 150 session_, &stream_,
81 base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr())); 151 base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr()));
82 if (rv == ERR_IO_PENDING) { 152 if (rv == OK) {
83 callback_ = callback;
84 } else if (rv == OK) {
85 stream_->SetDelegate(this); 153 stream_->SetDelegate(this);
86 } else if (!was_handshake_confirmed_) { 154 if (response_info_) {
155 next_state_ = STATE_SET_REQUEST_PRIORITY;
156 }
157 } else if (rv != ERR_IO_PENDING && !was_handshake_confirmed_) {
87 rv = ERR_QUIC_HANDSHAKE_FAILED; 158 rv = ERR_QUIC_HANDSHAKE_FAILED;
88 } 159 }
160 return rv;
161 }
89 162
90 return rv; 163 int QuicHttpStream::DoSetRequestPriority() {
164 // Set priority according to request and, and advance to
165 // STATE_SEND_HEADERS.
166 DCHECK(stream_);
167 DCHECK(response_info_);
168 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
169 stream_->SetPriority(priority);
170 next_state_ = STATE_SEND_HEADERS;
171 return OK;
91 } 172 }
92 173
93 void QuicHttpStream::OnStreamReady(int rv) { 174 void QuicHttpStream::OnStreamReady(int rv) {
94 DCHECK(rv == OK || !stream_); 175 DCHECK(rv == OK || !stream_);
95 if (rv == OK) { 176 if (rv == OK) {
96 stream_->SetDelegate(this); 177 stream_->SetDelegate(this);
178 if (response_info_) {
179 // This happens in the case of a asynchronous push rendezvous
180 // that ultimately fails (e.g. vary failure). |response_info_|
181 // non-null implies that |DoStreamRequest()| was called via
182 // |SendRequest()|.
183 next_state_ = STATE_SET_REQUEST_PRIORITY;
184 rv = DoLoop(OK);
185 }
97 } else if (!was_handshake_confirmed_) { 186 } else if (!was_handshake_confirmed_) {
98 rv = ERR_QUIC_HANDSHAKE_FAILED; 187 rv = ERR_QUIC_HANDSHAKE_FAILED;
99 } 188 }
189 if (rv != ERR_IO_PENDING) {
190 DoCallback(rv);
191 }
192 }
100 193
101 base::ResetAndReturn(&callback_).Run(rv); 194 bool QuicHttpStream::CancelPromiseIfHasBody() {
195 if (!request_body_stream_)
196 return false;
197 // Method type or request with body ineligble for push.
198 this->push_handle_->Cancel();
199 this->push_handle_ = nullptr;
200 next_state_ = STATE_REQUEST_STREAM;
201 return true;
202 }
203
204 int QuicHttpStream::HandlePromise() {
205 QuicAsyncStatus push_status = session_->push_promise_index()->Try(
206 request_headers_, this, &this->push_handle_);
207
208 switch (push_status) {
209 case QUIC_FAILURE:
210 // Push rendezvous failed.
211 next_state_ = STATE_REQUEST_STREAM;
212 break;
213 case QUIC_SUCCESS:
214 next_state_ = STATE_OPEN;
215 if (!CancelPromiseIfHasBody()) {
216 // Avoid the call to |DoLoop()| below, which would reset
217 // next_state_ to STATE_NONE.
218 return OK;
219 }
220 break;
221 case QUIC_PENDING:
222 if (!CancelPromiseIfHasBody()) {
223 // Have a promise but the promised stream doesn't exist yet.
224 // Still have to do validation before accepting the promised
225 // stream for sure.
226 return ERR_IO_PENDING;
227 }
228 break;
229 }
230 return DoLoop(OK);
102 } 231 }
103 232
104 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, 233 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
105 HttpResponseInfo* response, 234 HttpResponseInfo* response,
106 const CompletionCallback& callback) { 235 const CompletionCallback& callback) {
107 CHECK(!request_body_stream_); 236 CHECK(!request_body_stream_);
108 CHECK(!response_info_); 237 CHECK(!response_info_);
109 CHECK(!callback.is_null()); 238 CHECK(!callback.is_null());
110 CHECK(response); 239 CHECK(response);
111 240
112 // TODO(rch): remove this once we figure out why channel ID is not being 241 // TODO(rch): remove this once we figure out why channel ID is not being
113 // sent when it should be. 242 // sent when it should be.
114 HostPortPair origin = HostPortPair::FromURL(request_info_->url); 243 HostPortPair origin = HostPortPair::FromURL(request_info_->url);
115 if (origin.Equals(HostPortPair("accounts.google.com", 443)) && 244 if (origin.Equals(HostPortPair("accounts.google.com", 443)) &&
116 request_headers.HasHeader(HttpRequestHeaders::kCookie)) { 245 request_headers.HasHeader(HttpRequestHeaders::kCookie)) {
117 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId", 246 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId",
118 ssl_info_.channel_id_sent); 247 ssl_info_.channel_id_sent);
119 } 248 }
120 if (!stream_) { 249 if ((!found_promise_ && !stream_) || !session_) {
121 return ERR_CONNECTION_CLOSED; 250 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
251 : ERR_QUIC_HANDSHAKE_FAILED;
122 } 252 }
123 253
124 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
125 stream_->SetPriority(priority);
126 // Store the serialized request headers. 254 // Store the serialized request headers.
127 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, HTTP2, 255 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, HTTP2,
128 /*direct=*/true, &request_headers_); 256 /*direct=*/true, &request_headers_);
129 257
130 // Store the request body. 258 // Store the request body.
131 request_body_stream_ = request_info_->upload_data_stream; 259 request_body_stream_ = request_info_->upload_data_stream;
132 if (request_body_stream_) { 260 if (request_body_stream_) {
133 // TODO(rch): Can we be more precise about when to allocate 261 // TODO(rch): Can we be more precise about when to allocate
134 // raw_request_body_buf_. Removed the following check. DoReadRequestBody() 262 // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
135 // was being called even if we didn't yet allocate raw_request_body_buf_. 263 // was being called even if we didn't yet allocate raw_request_body_buf_.
136 // && (request_body_stream_->size() || 264 // && (request_body_stream_->size() ||
137 // request_body_stream_->is_chunked())) 265 // request_body_stream_->is_chunked()))
138 // Use 10 packets as the body buffer size to give enough space to 266 // Use 10 packets as the body buffer size to give enough space to
139 // help ensure we don't often send out partial packets. 267 // help ensure we don't often send out partial packets.
140 raw_request_body_buf_ = 268 raw_request_body_buf_ =
141 new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize)); 269 new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize));
142 // The request body buffer is empty at first. 270 // The request body buffer is empty at first.
143 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0); 271 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
144 } 272 }
145 273
146 // Store the response info. 274 // Store the response info.
147 response_info_ = response; 275 response_info_ = response;
148 276
149 next_state_ = STATE_SEND_HEADERS; 277 int rv;
150 int rv = DoLoop(OK); 278
279 if (found_promise_) {
280 rv = HandlePromise();
281 } else {
282 next_state_ = STATE_SET_REQUEST_PRIORITY;
283 rv = DoLoop(OK);
284 }
285
151 if (rv == ERR_IO_PENDING) 286 if (rv == ERR_IO_PENDING)
152 callback_ = callback; 287 callback_ = callback;
153 288
154 return rv > 0 ? OK : rv; 289 return rv > 0 ? OK : rv;
155 } 290 }
156 291
157 UploadProgress QuicHttpStream::GetUploadProgress() const { 292 UploadProgress QuicHttpStream::GetUploadProgress() const {
158 if (!request_body_stream_) 293 if (!request_body_stream_)
159 return UploadProgress(); 294 return UploadProgress();
160 295
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 // The client callback can do anything, including destroying this class, 519 // The client callback can do anything, including destroying this class,
385 // so any pending callback must be issued after everything else is done. 520 // so any pending callback must be issued after everything else is done.
386 base::ResetAndReturn(&callback_).Run(rv); 521 base::ResetAndReturn(&callback_).Run(rv);
387 } 522 }
388 523
389 int QuicHttpStream::DoLoop(int rv) { 524 int QuicHttpStream::DoLoop(int rv) {
390 do { 525 do {
391 State state = next_state_; 526 State state = next_state_;
392 next_state_ = STATE_NONE; 527 next_state_ = STATE_NONE;
393 switch (state) { 528 switch (state) {
529 case STATE_REQUEST_STREAM:
530 rv = DoStreamRequest();
531 break;
532 case STATE_SET_REQUEST_PRIORITY:
533 rv = DoSetRequestPriority();
534 break;
394 case STATE_SEND_HEADERS: 535 case STATE_SEND_HEADERS:
395 CHECK_EQ(OK, rv); 536 CHECK_EQ(OK, rv);
396 rv = DoSendHeaders(); 537 rv = DoSendHeaders();
397 break; 538 break;
398 case STATE_SEND_HEADERS_COMPLETE: 539 case STATE_SEND_HEADERS_COMPLETE:
399 rv = DoSendHeadersComplete(rv); 540 rv = DoSendHeadersComplete(rv);
400 break; 541 break;
401 case STATE_READ_REQUEST_BODY: 542 case STATE_READ_REQUEST_BODY:
402 CHECK_EQ(OK, rv); 543 CHECK_EQ(OK, rv);
403 rv = DoReadRequestBody(); 544 rv = DoReadRequestBody();
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 } 720 }
580 return rv; 721 return rv;
581 } 722 }
582 723
583 void QuicHttpStream::ResetStream() { 724 void QuicHttpStream::ResetStream() {
584 // TODO(rtenneti): Temporary until crbug.com/585591 is solved. 725 // TODO(rtenneti): Temporary until crbug.com/585591 is solved.
585 if (read_in_progress_) { 726 if (read_in_progress_) {
586 // |stream_| is going away when Read is called. Should never happen?? 727 // |stream_| is going away when Read is called. Should never happen??
587 CHECK(false); 728 CHECK(false);
588 } 729 }
730 if (push_handle_) {
731 push_handle_->Cancel();
732 push_handle_ = nullptr;
733 }
589 if (!stream_) 734 if (!stream_)
590 return; 735 return;
591 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 736 closed_stream_received_bytes_ = stream_->stream_bytes_read();
592 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 737 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
593 stream_ = nullptr; 738 stream_ = nullptr;
594 739
595 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress 740 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
596 // read. 741 // read.
597 if (request_body_stream_) 742 if (request_body_stream_)
598 request_body_stream_->Reset(); 743 request_body_stream_->Reset();
599 } 744 }
600 745
601 } // namespace net 746 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698