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

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: Initial for-review version 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 void QuicHttpStream::ConvertHeaderBlockToHttpRequestHeaders(
62 const SpdyHeaderBlock& spdy_headers,
63 HttpRequestHeaders* http_headers) {
64 for (auto it : spdy_headers) {
65 StringPiece key = it.first;
66 if (key[0] == ':') {
67 key.remove_prefix(1);
68 }
69 std::vector<StringPiece> values = base::SplitStringPiece(
70 it.second, "\0", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
71 for (auto value : values) {
72 http_headers->SetHeader(key, value);
73 }
74 }
75 }
76
77 bool QuicHttpStream::CheckVary(const SpdyHeaderBlock& client_request,
78 const SpdyHeaderBlock& promise_request,
79 const SpdyHeaderBlock& promise_response) {
80 HttpResponseInfo promise_response_info;
81
82 HttpRequestInfo promise_request_info;
83 ConvertHeaderBlockToHttpRequestHeaders(promise_request,
84 &promise_request_info.extra_headers);
85 HttpRequestInfo client_request_info;
86 ConvertHeaderBlockToHttpRequestHeaders(client_request,
87 &client_request_info.extra_headers);
88
89 if (!SpdyHeadersToHttpResponse(promise_response, HTTP2,
90 &promise_response_info)) {
91 DLOG(WARNING) << "Invalid headers";
92 return false;
93 }
94
95 HttpVaryData vary_data;
96 if (vary_data.Init(promise_request_info,
97 *promise_response_info.headers.get())) {
98 // Now compare the client request for matching.
99 return vary_data.MatchesRequest(client_request_info,
100 *promise_response_info.headers.get());
101 } else {
102 // Promise didn't contain valid vary info, so URL match was sufficient.
103 return true;
Ryan Hamilton 2016/02/24 00:34:00 nit: early return if (!vary_data.Init(...)) { /
Buck 2016/02/26 23:54:16 Done.
104 }
105 }
106
107 void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) {
108 push_handle_ = nullptr;
109 if (stream) {
110 stream_ = static_cast<QuicChromiumClientStream*>(stream);
111 stream_->SetDelegate(this);
112 }
113 if (!callback_.is_null()) {
Ryan Hamilton 2016/02/24 00:34:00 Can you comment about under what circumstances wil
Buck 2016/02/26 23:54:16 Done.
114 // Try returned QUIC_PENDING
115 if (stream) {
116 next_state_ = STATE_OPEN;
117 DoCallback(OK);
Ryan Hamilton 2016/02/24 00:34:00 Instead of DoCallback, can you simply do OnIOCompl
Buck 2016/02/26 23:54:16 No, because OnIoComplete() calls DoLoop() which to
118 return;
119 }
120 // rendezvous has failed so proceed as with a non-push request.
121 next_state_ = STATE_STREAM_REQUEST;
122 OnIOComplete(OK);
123 }
124 }
125
57 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, 126 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
58 RequestPriority priority, 127 RequestPriority priority,
59 const BoundNetLog& stream_net_log, 128 const BoundNetLog& stream_net_log,
60 const CompletionCallback& callback) { 129 const CompletionCallback& callback) {
61 DCHECK(!stream_); 130 DCHECK(!stream_);
62 if (!session_) 131 if (!session_)
63 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED 132 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
64 : ERR_QUIC_HANDSHAKE_FAILED; 133 : ERR_QUIC_HANDSHAKE_FAILED;
65 134
66 stream_net_log.AddEvent( 135 stream_net_log.AddEvent(
67 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION, 136 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
68 session_->net_log().source().ToEventParametersCallback()); 137 session_->net_log().source().ToEventParametersCallback());
69 138
70 stream_net_log_ = stream_net_log; 139 stream_net_log_ = stream_net_log;
71 request_info_ = request_info; 140 request_info_ = request_info;
72 request_time_ = base::Time::Now(); 141 request_time_ = base::Time::Now();
73 priority_ = priority; 142 priority_ = priority;
74 143
75 bool success = session_->GetSSLInfo(&ssl_info_); 144 bool success = session_->GetSSLInfo(&ssl_info_);
76 DCHECK(success); 145 DCHECK(success);
77 DCHECK(ssl_info_.cert.get()); 146 DCHECK(ssl_info_.cert.get());
78 147
148 if (session_->push_promise_index()->GetPromised(request_info->url.spec())) {
149 found_promise_ = true;
150 return OK;
Ryan Hamilton 2016/02/24 00:34:00 Can you add a comment here which explains that the
Buck 2016/02/26 23:54:16 Done.
151 }
152
153 next_state_ = STATE_STREAM_REQUEST;
154 int rv = DoLoop(OK);
155 if (rv == ERR_IO_PENDING)
156 callback_ = callback;
157
158 return rv;
159 }
160
161 int QuicHttpStream::DoStreamRequest() {
79 int rv = stream_request_.StartRequest( 162 int rv = stream_request_.StartRequest(
80 session_, &stream_, 163 session_, &stream_,
81 base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr())); 164 base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr()));
82 if (rv == ERR_IO_PENDING) { 165 if (rv == OK) {
83 callback_ = callback;
84 } else if (rv == OK) {
85 stream_->SetDelegate(this); 166 stream_->SetDelegate(this);
86 } else if (!was_handshake_confirmed_) { 167 if (response_info_) {
168 EnterStateSendHeaders();
Ryan Hamilton 2016/02/24 00:34:00 I think it would be more common to rename EnterSta
169 }
170 } else if (rv != ERR_IO_PENDING && !was_handshake_confirmed_) {
87 rv = ERR_QUIC_HANDSHAKE_FAILED; 171 rv = ERR_QUIC_HANDSHAKE_FAILED;
88 } 172 }
173 return rv;
174 }
89 175
90 return rv; 176 void QuicHttpStream::EnterStateSendHeaders() {
177 // Only advance to STATE_SEND_HEADERS if the stream is ready and
178 // SendRequest has been called (i.e. if response_info_ is a
179 // non-null value, so priority_ etc. are also set).
Ryan Hamilton 2016/02/24 00:34:00 This comment implies some conditional logic which
Buck 2016/02/26 23:54:16 I updated the comment. [ The conditional logic *
180 DCHECK(stream_);
181 DCHECK(response_info_);
182 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
183 stream_->SetPriority(priority);
184 next_state_ = STATE_SEND_HEADERS;
91 } 185 }
92 186
93 void QuicHttpStream::OnStreamReady(int rv) { 187 void QuicHttpStream::OnStreamReady(int rv) {
94 DCHECK(rv == OK || !stream_); 188 DCHECK(rv == OK || !stream_);
95 if (rv == OK) { 189 if (rv == OK) {
96 stream_->SetDelegate(this); 190 stream_->SetDelegate(this);
191 if (response_info_) {
192 EnterStateSendHeaders();
193 rv = DoLoop(OK);
194 }
Ryan Hamilton 2016/02/24 00:34:00 My brain is working slowly. What circumstances lea
Buck 2016/02/26 23:54:16 Added a comment to explain.
97 } else if (!was_handshake_confirmed_) { 195 } else if (!was_handshake_confirmed_) {
98 rv = ERR_QUIC_HANDSHAKE_FAILED; 196 rv = ERR_QUIC_HANDSHAKE_FAILED;
99 } 197 }
198 if (rv != ERR_IO_PENDING) {
199 DoCallback(rv);
200 }
201 }
100 202
101 base::ResetAndReturn(&callback_).Run(rv); 203 int QuicHttpStream::HandlePromise() {
204 QuicAsyncStatus push_status = session_->push_promise_index()->Try(
205 request_headers_, this, &this->push_handle_);
206 if (push_status == QUIC_FAILURE) {
Ryan Hamilton 2016/02/24 00:34:00 nit: consider a switch statement here.
Buck 2016/02/26 23:54:16 Done.
207 // Push rendezvous failed.
208 next_state_ = STATE_STREAM_REQUEST;
209 } else if (request_body_stream_) {
210 // Method type or request with body ineligble for push.
211 this->push_handle_->Cancel();
212 this->push_handle_ = nullptr;
213 next_state_ = STATE_STREAM_REQUEST;
214 } else if (push_status == QUIC_SUCCESS) {
215 next_state_ = STATE_OPEN;
216 } else {
217 DCHECK(push_status == QUIC_PENDING);
218 // Have a promise but the promised stream doesn't exist yet.
219 // Still have to do validation before accepting the promised
220 // stream for sure.
221 return ERR_IO_PENDING;
222 }
223 if (next_state_ != STATE_OPEN) {
Ryan Hamilton 2016/02/24 00:34:00 How 'bout avoiding this conditional by doing a ret
Buck 2016/02/26 23:54:16 Done.
224 return DoLoop(OK);
225 }
226 return OK;
102 } 227 }
103 228
104 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, 229 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
105 HttpResponseInfo* response, 230 HttpResponseInfo* response,
106 const CompletionCallback& callback) { 231 const CompletionCallback& callback) {
107 CHECK(!request_body_stream_); 232 CHECK(!request_body_stream_);
108 CHECK(!response_info_); 233 CHECK(!response_info_);
109 CHECK(!callback.is_null()); 234 CHECK(!callback.is_null());
110 CHECK(response); 235 CHECK(response);
111 236
112 // TODO(rch): remove this once we figure out why channel ID is not being 237 // TODO(rch): remove this once we figure out why channel ID is not being
113 // sent when it should be. 238 // sent when it should be.
114 HostPortPair origin = HostPortPair::FromURL(request_info_->url); 239 HostPortPair origin = HostPortPair::FromURL(request_info_->url);
115 if (origin.Equals(HostPortPair("accounts.google.com", 443)) && 240 if (origin.Equals(HostPortPair("accounts.google.com", 443)) &&
116 request_headers.HasHeader(HttpRequestHeaders::kCookie)) { 241 request_headers.HasHeader(HttpRequestHeaders::kCookie)) {
117 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId", 242 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId",
118 ssl_info_.channel_id_sent); 243 ssl_info_.channel_id_sent);
119 } 244 }
120 if (!stream_) { 245 if (!found_promise_) {
121 return ERR_CONNECTION_CLOSED; 246 if (!stream_)
247 return ERR_CONNECTION_CLOSED;
Ryan Hamilton 2016/02/24 00:34:00 I wonder if this should have the same logic as bel
Buck 2016/02/26 23:54:16 Done.
248 } else if (!session_) {
249 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
250 : ERR_QUIC_HANDSHAKE_FAILED;
122 } 251 }
123 252
124 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
125 stream_->SetPriority(priority);
126 // Store the serialized request headers. 253 // Store the serialized request headers.
127 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, HTTP2, 254 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, HTTP2,
128 /*direct=*/true, &request_headers_); 255 /*direct=*/true, &request_headers_);
129 256
130 // Store the request body. 257 // Store the request body.
131 request_body_stream_ = request_info_->upload_data_stream; 258 request_body_stream_ = request_info_->upload_data_stream;
132 if (request_body_stream_) { 259 if (request_body_stream_) {
133 // TODO(rch): Can we be more precise about when to allocate 260 // TODO(rch): Can we be more precise about when to allocate
134 // raw_request_body_buf_. Removed the following check. DoReadRequestBody() 261 // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
135 // was being called even if we didn't yet allocate raw_request_body_buf_. 262 // was being called even if we didn't yet allocate raw_request_body_buf_.
136 // && (request_body_stream_->size() || 263 // && (request_body_stream_->size() ||
137 // request_body_stream_->is_chunked())) 264 // request_body_stream_->is_chunked()))
138 // Use 10 packets as the body buffer size to give enough space to 265 // Use 10 packets as the body buffer size to give enough space to
139 // help ensure we don't often send out partial packets. 266 // help ensure we don't often send out partial packets.
140 raw_request_body_buf_ = 267 raw_request_body_buf_ =
141 new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize)); 268 new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize));
142 // The request body buffer is empty at first. 269 // The request body buffer is empty at first.
143 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0); 270 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
144 } 271 }
145 272
146 // Store the response info. 273 // Store the response info.
147 response_info_ = response; 274 response_info_ = response;
148 275
149 next_state_ = STATE_SEND_HEADERS; 276 int rv;
150 int rv = DoLoop(OK); 277
278 if (found_promise_) {
279 rv = HandlePromise();
280 } else {
281 EnterStateSendHeaders();
282 rv = DoLoop(OK);
283 }
284
151 if (rv == ERR_IO_PENDING) 285 if (rv == ERR_IO_PENDING)
152 callback_ = callback; 286 callback_ = callback;
153 287
154 return rv > 0 ? OK : rv; 288 return rv > 0 ? OK : rv;
155 } 289 }
156 290
157 UploadProgress QuicHttpStream::GetUploadProgress() const { 291 UploadProgress QuicHttpStream::GetUploadProgress() const {
158 if (!request_body_stream_) 292 if (!request_body_stream_)
159 return UploadProgress(); 293 return UploadProgress();
160 294
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 // The client callback can do anything, including destroying this class, 517 // The client callback can do anything, including destroying this class,
384 // so any pending callback must be issued after everything else is done. 518 // so any pending callback must be issued after everything else is done.
385 base::ResetAndReturn(&callback_).Run(rv); 519 base::ResetAndReturn(&callback_).Run(rv);
386 } 520 }
387 521
388 int QuicHttpStream::DoLoop(int rv) { 522 int QuicHttpStream::DoLoop(int rv) {
389 do { 523 do {
390 State state = next_state_; 524 State state = next_state_;
391 next_state_ = STATE_NONE; 525 next_state_ = STATE_NONE;
392 switch (state) { 526 switch (state) {
527 case STATE_STREAM_REQUEST:
528 rv = DoStreamRequest();
529 break;
393 case STATE_SEND_HEADERS: 530 case STATE_SEND_HEADERS:
394 CHECK_EQ(OK, rv); 531 CHECK_EQ(OK, rv);
395 rv = DoSendHeaders(); 532 rv = DoSendHeaders();
396 break; 533 break;
397 case STATE_SEND_HEADERS_COMPLETE: 534 case STATE_SEND_HEADERS_COMPLETE:
398 rv = DoSendHeadersComplete(rv); 535 rv = DoSendHeadersComplete(rv);
399 break; 536 break;
400 case STATE_READ_REQUEST_BODY: 537 case STATE_READ_REQUEST_BODY:
401 CHECK_EQ(OK, rv); 538 CHECK_EQ(OK, rv);
402 rv = DoReadRequestBody(); 539 rv = DoReadRequestBody();
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 } 715 }
579 return rv; 716 return rv;
580 } 717 }
581 718
582 void QuicHttpStream::ResetStream() { 719 void QuicHttpStream::ResetStream() {
583 // TODO(rtenneti): Temporary until crbug.com/585591 is solved. 720 // TODO(rtenneti): Temporary until crbug.com/585591 is solved.
584 if (read_in_progress_) { 721 if (read_in_progress_) {
585 // |stream_| is going away when Read is called. Should never happen?? 722 // |stream_| is going away when Read is called. Should never happen??
586 CHECK(false); 723 CHECK(false);
587 } 724 }
725 if (push_handle_) {
726 push_handle_->Cancel();
727 push_handle_ = nullptr;
728 }
588 if (!stream_) 729 if (!stream_)
589 return; 730 return;
590 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 731 closed_stream_received_bytes_ = stream_->stream_bytes_read();
591 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 732 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
592 stream_ = nullptr; 733 stream_ = nullptr;
593 734
594 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress 735 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
595 // read. 736 // read.
596 if (request_body_stream_) 737 if (request_body_stream_)
597 request_body_stream_->Reset(); 738 request_body_stream_->Reset();
598 } 739 }
599 740
600 } // namespace net 741 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698