OLD | NEW |
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/chromium/quic_http_stream.h" | 5 #include "net/quic/chromium/quic_http_stream.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 return vary_data.MatchesRequest(client_request_info, | 104 return vary_data.MatchesRequest(client_request_info, |
105 *promise_response_info.headers.get()); | 105 *promise_response_info.headers.get()); |
106 } | 106 } |
107 | 107 |
108 void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) { | 108 void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) { |
109 push_handle_ = nullptr; | 109 push_handle_ = nullptr; |
110 if (stream) { | 110 if (stream) { |
111 stream_ = static_cast<QuicChromiumClientStream*>(stream); | 111 stream_ = static_cast<QuicChromiumClientStream*>(stream); |
112 stream_->SetDelegate(this); | 112 stream_->SetDelegate(this); |
113 } | 113 } |
114 // callback_ should be non-null in the case of asynchronous | 114 |
| 115 // callback_ should only be non-null in the case of asynchronous |
115 // rendezvous; i.e. |Try()| returned QUIC_PENDING. | 116 // rendezvous; i.e. |Try()| returned QUIC_PENDING. |
116 if (!callback_.is_null()) { | 117 if (callback_.is_null()) |
117 if (stream) { | 118 return; |
118 next_state_ = STATE_OPEN; | 119 |
119 stream_net_log_.AddEvent( | 120 if (stream) { |
120 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, | 121 next_state_ = STATE_HANDLE_PROMISE_COMPLETE; |
121 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), | 122 } else { |
122 &request_info_->url)); | |
123 session_->net_log().AddEvent( | |
124 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, | |
125 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), | |
126 &request_info_->url)); | |
127 DoCallback(OK); | |
128 return; | |
129 } | |
130 // rendezvous has failed so proceed as with a non-push request. | 123 // rendezvous has failed so proceed as with a non-push request. |
131 next_state_ = STATE_REQUEST_STREAM; | 124 next_state_ = STATE_REQUEST_STREAM; |
132 OnIOComplete(OK); | |
133 } | 125 } |
| 126 |
| 127 OnIOComplete(OK); |
134 } | 128 } |
135 | 129 |
136 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, | 130 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, |
137 RequestPriority priority, | 131 RequestPriority priority, |
138 const BoundNetLog& stream_net_log, | 132 const BoundNetLog& stream_net_log, |
139 const CompletionCallback& callback) { | 133 const CompletionCallback& callback) { |
140 CHECK(callback_.is_null()); | 134 CHECK(callback_.is_null()); |
141 DCHECK(!stream_); | 135 DCHECK(!stream_); |
142 if (!session_) | 136 if (!session_) |
143 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED | 137 return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED |
(...skipping 29 matching lines...) Expand all Loading... |
173 } | 167 } |
174 | 168 |
175 next_state_ = STATE_REQUEST_STREAM; | 169 next_state_ = STATE_REQUEST_STREAM; |
176 int rv = DoLoop(OK); | 170 int rv = DoLoop(OK); |
177 if (rv == ERR_IO_PENDING) | 171 if (rv == ERR_IO_PENDING) |
178 callback_ = callback; | 172 callback_ = callback; |
179 | 173 |
180 return rv; | 174 return rv; |
181 } | 175 } |
182 | 176 |
183 void QuicHttpStream::OnStreamReady(int rv) { | |
184 DCHECK(rv == OK || !stream_); | |
185 if (rv == OK) { | |
186 stream_->SetDelegate(this); | |
187 if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) { | |
188 stream_->DisableConnectionMigration(); | |
189 } | |
190 if (response_info_) { | |
191 // This happens in the case of a asynchronous push rendezvous | |
192 // that ultimately fails (e.g. vary failure). |response_info_| | |
193 // non-null implies that |DoStreamRequest()| was called via | |
194 // |SendRequest()|. | |
195 next_state_ = STATE_SET_REQUEST_PRIORITY; | |
196 rv = DoLoop(OK); | |
197 } | |
198 } else if (!was_handshake_confirmed_) { | |
199 rv = ERR_QUIC_HANDSHAKE_FAILED; | |
200 } | |
201 if (rv != ERR_IO_PENDING) { | |
202 DoCallback(rv); | |
203 } | |
204 } | |
205 | |
206 bool QuicHttpStream::CancelPromiseIfHasBody() { | 177 bool QuicHttpStream::CancelPromiseIfHasBody() { |
207 if (!request_body_stream_) | 178 if (!request_body_stream_) |
208 return false; | 179 return false; |
209 // Method type or request with body ineligble for push. | 180 |
| 181 // A request with a body is ineligble for push. |
210 this->push_handle_->Cancel(); | 182 this->push_handle_->Cancel(); |
211 this->push_handle_ = nullptr; | 183 this->push_handle_ = nullptr; |
212 next_state_ = STATE_REQUEST_STREAM; | |
213 return true; | 184 return true; |
214 } | 185 } |
215 | 186 |
216 int QuicHttpStream::HandlePromise() { | 187 int QuicHttpStream::DoHandlePromise() { |
217 QuicAsyncStatus push_status = session_->push_promise_index()->Try( | 188 QuicAsyncStatus push_status = session_->push_promise_index()->Try( |
218 request_headers_, this, &this->push_handle_); | 189 request_headers_, this, &this->push_handle_); |
219 | 190 |
220 switch (push_status) { | 191 switch (push_status) { |
221 case QUIC_FAILURE: | 192 case QUIC_FAILURE: |
222 // Push rendezvous failed. | 193 // Push rendezvous failed. |
223 next_state_ = STATE_REQUEST_STREAM; | 194 next_state_ = STATE_REQUEST_STREAM; |
224 break; | 195 break; |
225 case QUIC_SUCCESS: | 196 case QUIC_SUCCESS: |
226 next_state_ = STATE_OPEN; | 197 next_state_ = STATE_HANDLE_PROMISE_COMPLETE; |
227 if (!CancelPromiseIfHasBody()) { | |
228 stream_net_log_.AddEvent( | |
229 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, | |
230 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), | |
231 &request_info_->url)); | |
232 session_->net_log().AddEvent( | |
233 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, | |
234 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), | |
235 &request_info_->url)); | |
236 // Avoid the call to |DoLoop()| below, which would reset | |
237 // next_state_ to STATE_NONE. | |
238 return OK; | |
239 } | |
240 | |
241 break; | 198 break; |
242 case QUIC_PENDING: | 199 case QUIC_PENDING: |
243 if (!CancelPromiseIfHasBody()) { | 200 if (!CancelPromiseIfHasBody()) { |
| 201 next_state_ = STATE_HANDLE_PROMISE_COMPLETE; |
244 // Have a promise but the promised stream doesn't exist yet. | 202 // Have a promise but the promised stream doesn't exist yet. |
245 // Still have to do validation before accepting the promised | 203 // Still have to do validation before accepting the promised |
246 // stream for sure. | 204 // stream for sure. |
247 return ERR_IO_PENDING; | 205 return ERR_IO_PENDING; |
248 } | 206 } |
249 break; | 207 next_state_ = STATE_REQUEST_STREAM; |
250 } | 208 } |
251 return DoLoop(OK); | 209 return OK; |
| 210 } |
| 211 |
| 212 int QuicHttpStream::DoHandlePromiseComplete(int rv) { |
| 213 if (rv != OK) |
| 214 return rv; |
| 215 |
| 216 if (CancelPromiseIfHasBody()) { |
| 217 next_state_ = STATE_REQUEST_STREAM; |
| 218 return OK; |
| 219 } |
| 220 |
| 221 next_state_ = STATE_OPEN; |
| 222 stream_net_log_.AddEvent( |
| 223 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, |
| 224 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), |
| 225 &request_info_->url)); |
| 226 session_->net_log().AddEvent( |
| 227 NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM, |
| 228 base::Bind(&NetLogQuicPushStreamCallback, stream_->id(), |
| 229 &request_info_->url)); |
| 230 return OK; |
252 } | 231 } |
253 | 232 |
254 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, | 233 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, |
255 HttpResponseInfo* response, | 234 HttpResponseInfo* response, |
256 const CompletionCallback& callback) { | 235 const CompletionCallback& callback) { |
257 CHECK(!request_body_stream_); | 236 CHECK(!request_body_stream_); |
258 CHECK(!response_info_); | 237 CHECK(!response_info_); |
259 CHECK(callback_.is_null()); | 238 CHECK(callback_.is_null()); |
260 CHECK(!callback.is_null()); | 239 CHECK(!callback.is_null()); |
261 CHECK(response); | 240 CHECK(response); |
(...skipping 30 matching lines...) Expand all Loading... |
292 // The request body buffer is empty at first. | 271 // The request body buffer is empty at first. |
293 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0); | 272 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0); |
294 } | 273 } |
295 | 274 |
296 // Store the response info. | 275 // Store the response info. |
297 response_info_ = response; | 276 response_info_ = response; |
298 | 277 |
299 int rv; | 278 int rv; |
300 | 279 |
301 if (found_promise_) { | 280 if (found_promise_) { |
302 rv = HandlePromise(); | 281 // TODO(rch): If this request has a body, instead of waiting for the pushed |
| 282 // headers to arrive before canceling the push we could cancel the pushed |
| 283 // stream now and go straight to STATE_REQUEST_STREAM. |
| 284 next_state_ = STATE_HANDLE_PROMISE; |
303 } else { | 285 } else { |
304 next_state_ = STATE_SET_REQUEST_PRIORITY; | 286 next_state_ = STATE_SET_REQUEST_PRIORITY; |
305 rv = DoLoop(OK); | |
306 } | 287 } |
| 288 rv = DoLoop(OK); |
307 | 289 |
308 if (rv == ERR_IO_PENDING) | 290 if (rv == ERR_IO_PENDING) |
309 callback_ = callback; | 291 callback_ = callback; |
310 | 292 |
311 return rv > 0 ? OK : rv; | 293 return rv > 0 ? OK : rv; |
312 } | 294 } |
313 | 295 |
314 UploadProgress QuicHttpStream::GetUploadProgress() const { | 296 UploadProgress QuicHttpStream::GetUploadProgress() const { |
315 if (!request_body_stream_) | 297 if (!request_body_stream_) |
316 return UploadProgress(); | 298 return UploadProgress(); |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 base::ResetAndReturn(&callback_).Run(rv); | 567 base::ResetAndReturn(&callback_).Run(rv); |
586 } | 568 } |
587 | 569 |
588 int QuicHttpStream::DoLoop(int rv) { | 570 int QuicHttpStream::DoLoop(int rv) { |
589 CHECK(!in_loop_); | 571 CHECK(!in_loop_); |
590 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); | 572 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); |
591 do { | 573 do { |
592 State state = next_state_; | 574 State state = next_state_; |
593 next_state_ = STATE_NONE; | 575 next_state_ = STATE_NONE; |
594 switch (state) { | 576 switch (state) { |
| 577 case STATE_HANDLE_PROMISE: |
| 578 CHECK_EQ(OK, rv); |
| 579 rv = DoHandlePromise(); |
| 580 break; |
| 581 case STATE_HANDLE_PROMISE_COMPLETE: |
| 582 CHECK_EQ(OK, rv); |
| 583 rv = DoHandlePromiseComplete(rv); |
| 584 break; |
595 case STATE_REQUEST_STREAM: | 585 case STATE_REQUEST_STREAM: |
596 rv = DoStreamRequest(); | 586 CHECK_EQ(OK, rv); |
| 587 rv = DoRequestStream(); |
| 588 break; |
| 589 case STATE_REQUEST_STREAM_COMPLETE: |
| 590 rv = DoRequestStreamComplete(rv); |
597 break; | 591 break; |
598 case STATE_SET_REQUEST_PRIORITY: | 592 case STATE_SET_REQUEST_PRIORITY: |
| 593 CHECK_EQ(OK, rv); |
599 rv = DoSetRequestPriority(); | 594 rv = DoSetRequestPriority(); |
600 break; | 595 break; |
601 case STATE_WAIT_FOR_CONFIRMATION: | 596 case STATE_WAIT_FOR_CONFIRMATION: |
602 CHECK_EQ(OK, rv); | 597 CHECK_EQ(OK, rv); |
603 rv = DoWaitForConfirmation(); | 598 rv = DoWaitForConfirmation(); |
604 break; | 599 break; |
605 case STATE_WAIT_FOR_CONFIRMATION_COMPLETE: | 600 case STATE_WAIT_FOR_CONFIRMATION_COMPLETE: |
606 rv = DoWaitForConfirmationComplete(rv); | 601 rv = DoWaitForConfirmationComplete(rv); |
607 break; | 602 break; |
608 case STATE_SEND_HEADERS: | 603 case STATE_SEND_HEADERS: |
(...skipping 23 matching lines...) Expand all Loading... |
632 default: | 627 default: |
633 NOTREACHED() << "next_state_: " << next_state_; | 628 NOTREACHED() << "next_state_: " << next_state_; |
634 break; | 629 break; |
635 } | 630 } |
636 } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN && | 631 } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN && |
637 rv != ERR_IO_PENDING); | 632 rv != ERR_IO_PENDING); |
638 | 633 |
639 return rv; | 634 return rv; |
640 } | 635 } |
641 | 636 |
642 int QuicHttpStream::DoStreamRequest() { | 637 int QuicHttpStream::DoRequestStream() { |
643 int rv = stream_request_.StartRequest( | 638 next_state_ = STATE_REQUEST_STREAM_COMPLETE; |
| 639 return stream_request_.StartRequest( |
644 session_, &stream_, | 640 session_, &stream_, |
645 base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr())); | 641 base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr())); |
646 if (rv == OK) { | 642 } |
647 stream_->SetDelegate(this); | 643 |
648 if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) { | 644 int QuicHttpStream::DoRequestStreamComplete(int rv) { |
649 stream_->DisableConnectionMigration(); | 645 DCHECK(rv == OK || !stream_); |
650 } | 646 if (rv != OK) |
651 if (response_info_) { | 647 return was_handshake_confirmed_ ? rv : ERR_QUIC_HANDSHAKE_FAILED; |
652 next_state_ = STATE_SET_REQUEST_PRIORITY; | 648 |
653 } | 649 stream_->SetDelegate(this); |
654 } else if (rv != ERR_IO_PENDING && !was_handshake_confirmed_) { | 650 if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) { |
655 rv = ERR_QUIC_HANDSHAKE_FAILED; | 651 stream_->DisableConnectionMigration(); |
656 } | 652 } |
657 return rv; | 653 |
| 654 if (response_info_) { |
| 655 // This happens in the case of a asynchronous push rendezvous |
| 656 // that ultimately fails (e.g. vary failure). |response_info_| |
| 657 // non-null implies that |DoRequestStream()| was called via |
| 658 // |SendRequest()|. |
| 659 next_state_ = STATE_SET_REQUEST_PRIORITY; |
| 660 } |
| 661 |
| 662 return OK; |
658 } | 663 } |
659 | 664 |
660 int QuicHttpStream::DoSetRequestPriority() { | 665 int QuicHttpStream::DoSetRequestPriority() { |
661 // Set priority according to request | 666 // Set priority according to request |
662 DCHECK(stream_); | 667 DCHECK(stream_); |
663 DCHECK(response_info_); | 668 DCHECK(response_info_); |
664 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_); | 669 SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_); |
665 stream_->SetPriority(priority); | 670 stream_->SetPriority(priority); |
666 next_state_ = STATE_WAIT_FOR_CONFIRMATION; | 671 next_state_ = STATE_WAIT_FOR_CONFIRMATION; |
667 return OK; | 672 return OK; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 closed_is_first_stream_ = stream_->IsFirstStream(); | 844 closed_is_first_stream_ = stream_->IsFirstStream(); |
840 stream_ = nullptr; | 845 stream_ = nullptr; |
841 | 846 |
842 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress | 847 // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress |
843 // read. | 848 // read. |
844 if (request_body_stream_) | 849 if (request_body_stream_) |
845 request_body_stream_->Reset(); | 850 request_body_stream_->Reset(); |
846 } | 851 } |
847 | 852 |
848 } // namespace net | 853 } // namespace net |
OLD | NEW |