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

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 2. Created 4 years, 9 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
« no previous file with comments | « net/quic/quic_http_stream.h ('k') | net/quic/quic_http_stream_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 // The client callback can do anything, including destroying this class, 518 // The client callback can do anything, including destroying this class,
384 // so any pending callback must be issued after everything else is done. 519 // so any pending callback must be issued after everything else is done.
385 base::ResetAndReturn(&callback_).Run(rv); 520 base::ResetAndReturn(&callback_).Run(rv);
386 } 521 }
387 522
388 int QuicHttpStream::DoLoop(int rv) { 523 int QuicHttpStream::DoLoop(int rv) {
389 do { 524 do {
390 State state = next_state_; 525 State state = next_state_;
391 next_state_ = STATE_NONE; 526 next_state_ = STATE_NONE;
392 switch (state) { 527 switch (state) {
528 case STATE_REQUEST_STREAM:
529 rv = DoStreamRequest();
530 break;
531 case STATE_SET_REQUEST_PRIORITY:
532 rv = DoSetRequestPriority();
533 break;
393 case STATE_SEND_HEADERS: 534 case STATE_SEND_HEADERS:
394 CHECK_EQ(OK, rv); 535 CHECK_EQ(OK, rv);
395 rv = DoSendHeaders(); 536 rv = DoSendHeaders();
396 break; 537 break;
397 case STATE_SEND_HEADERS_COMPLETE: 538 case STATE_SEND_HEADERS_COMPLETE:
398 rv = DoSendHeadersComplete(rv); 539 rv = DoSendHeadersComplete(rv);
399 break; 540 break;
400 case STATE_READ_REQUEST_BODY: 541 case STATE_READ_REQUEST_BODY:
401 CHECK_EQ(OK, rv); 542 CHECK_EQ(OK, rv);
402 rv = DoReadRequestBody(); 543 rv = DoReadRequestBody();
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 } 719 }
579 return rv; 720 return rv;
580 } 721 }
581 722
582 void QuicHttpStream::ResetStream() { 723 void QuicHttpStream::ResetStream() {
583 // TODO(rtenneti): Temporary until crbug.com/585591 is solved. 724 // TODO(rtenneti): Temporary until crbug.com/585591 is solved.
584 if (read_in_progress_) { 725 if (read_in_progress_) {
585 // |stream_| is going away when Read is called. Should never happen?? 726 // |stream_| is going away when Read is called. Should never happen??
586 CHECK(false); 727 CHECK(false);
587 } 728 }
729 if (push_handle_) {
730 push_handle_->Cancel();
731 push_handle_ = nullptr;
732 }
588 if (!stream_) 733 if (!stream_)
589 return; 734 return;
590 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 735 closed_stream_received_bytes_ = stream_->stream_bytes_read();
591 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 736 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
592 stream_ = nullptr; 737 stream_ = nullptr;
593 738
594 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress 739 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
595 // read. 740 // read.
596 if (request_body_stream_) 741 if (request_body_stream_)
597 request_body_stream_->Reset(); 742 request_body_stream_->Reset();
598 } 743 }
599 744
600 } // namespace net 745 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_http_stream.h ('k') | net/quic/quic_http_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698