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/spdy/spdy_stream.h" | 5 #include "net/spdy/spdy_stream.h" |
6 | 6 |
7 #include <limits> | |
8 | |
9 #include "base/bind.h" | 7 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
11 #include "base/logging.h" | 9 #include "base/logging.h" |
12 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
13 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
14 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
15 #include "base/values.h" | 13 #include "base/values.h" |
16 #include "net/spdy/spdy_buffer_producer.h" | 14 #include "net/spdy/spdy_buffer_producer.h" |
17 #include "net/spdy/spdy_http_utils.h" | 15 #include "net/spdy/spdy_http_utils.h" |
18 #include "net/spdy/spdy_session.h" | 16 #include "net/spdy/spdy_session.h" |
(...skipping 18 matching lines...) Expand all Loading... |
37 int32 delta, | 35 int32 delta, |
38 int32 window_size, | 36 int32 window_size, |
39 NetLog::LogLevel /* log_level */) { | 37 NetLog::LogLevel /* log_level */) { |
40 base::DictionaryValue* dict = new base::DictionaryValue(); | 38 base::DictionaryValue* dict = new base::DictionaryValue(); |
41 dict->SetInteger("stream_id", stream_id); | 39 dict->SetInteger("stream_id", stream_id); |
42 dict->SetInteger("delta", delta); | 40 dict->SetInteger("delta", delta); |
43 dict->SetInteger("window_size", window_size); | 41 dict->SetInteger("window_size", window_size); |
44 return dict; | 42 return dict; |
45 } | 43 } |
46 | 44 |
47 bool ContainsUpperAscii(const std::string& str) { | 45 bool ContainsUppercaseAscii(const std::string& str) { |
48 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { | 46 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { |
49 if (*i >= 'A' && *i <= 'Z') { | 47 if (*i >= 'A' && *i <= 'Z') { |
50 return true; | 48 return true; |
51 } | 49 } |
52 } | 50 } |
53 return false; | 51 return false; |
54 } | 52 } |
55 | 53 |
56 } // namespace | 54 } // namespace |
57 | 55 |
(...skipping 24 matching lines...) Expand all Loading... |
82 SpdyStream::SpdyStream(SpdyStreamType type, | 80 SpdyStream::SpdyStream(SpdyStreamType type, |
83 SpdySession* session, | 81 SpdySession* session, |
84 const std::string& path, | 82 const std::string& path, |
85 RequestPriority priority, | 83 RequestPriority priority, |
86 int32 initial_send_window_size, | 84 int32 initial_send_window_size, |
87 int32 initial_recv_window_size, | 85 int32 initial_recv_window_size, |
88 const BoundNetLog& net_log) | 86 const BoundNetLog& net_log) |
89 : type_(type), | 87 : type_(type), |
90 weak_ptr_factory_(this), | 88 weak_ptr_factory_(this), |
91 in_do_loop_(false), | 89 in_do_loop_(false), |
92 continue_buffering_data_(true), | 90 continue_buffering_data_(type_ == SPDY_PUSH_STREAM), |
93 stream_id_(0), | 91 stream_id_(0), |
94 path_(path), | 92 path_(path), |
95 priority_(priority), | 93 priority_(priority), |
96 slot_(0), | 94 slot_(0), |
97 send_stalled_by_flow_control_(false), | 95 send_stalled_by_flow_control_(false), |
98 send_window_size_(initial_send_window_size), | 96 send_window_size_(initial_send_window_size), |
99 recv_window_size_(initial_recv_window_size), | 97 recv_window_size_(initial_recv_window_size), |
100 unacked_recv_window_bytes_(0), | 98 unacked_recv_window_bytes_(0), |
101 response_received_(false), | |
102 session_(session), | 99 session_(session), |
103 delegate_(NULL), | 100 delegate_(NULL), |
104 send_status_( | 101 send_status_( |
105 (type_ == SPDY_PUSH_STREAM) ? | 102 (type_ == SPDY_PUSH_STREAM) ? |
106 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND), | 103 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND), |
107 request_time_(base::Time::Now()), | 104 request_time_(base::Time::Now()), |
108 response_(new SpdyHeaderBlock), | 105 response_headers_status_(RESPONSE_HEADERS_ARE_INCOMPLETE), |
109 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE), | 106 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE), |
110 response_status_(OK), | 107 response_status_(OK), |
111 net_log_(net_log), | 108 net_log_(net_log), |
112 send_bytes_(0), | 109 send_bytes_(0), |
113 recv_bytes_(0), | 110 recv_bytes_(0), |
114 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE), | 111 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE), |
115 just_completed_frame_type_(DATA), | 112 just_completed_frame_type_(DATA), |
116 just_completed_frame_size_(0) { | 113 just_completed_frame_size_(0) { |
117 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || | 114 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || |
118 type_ == SPDY_REQUEST_RESPONSE_STREAM || | 115 type_ == SPDY_REQUEST_RESPONSE_STREAM || |
119 type_ == SPDY_PUSH_STREAM); | 116 type_ == SPDY_PUSH_STREAM); |
120 } | 117 } |
121 | 118 |
122 SpdyStream::~SpdyStream() { | 119 SpdyStream::~SpdyStream() { |
123 CHECK(!in_do_loop_); | 120 CHECK(!in_do_loop_); |
124 UpdateHistograms(); | 121 UpdateHistograms(); |
125 } | 122 } |
126 | 123 |
127 void SpdyStream::SetDelegate(Delegate* delegate) { | 124 void SpdyStream::SetDelegate(Delegate* delegate) { |
128 CHECK(!delegate_); | 125 CHECK(!delegate_); |
129 CHECK(delegate); | 126 CHECK(delegate); |
130 delegate_ = delegate; | 127 delegate_ = delegate; |
131 | 128 |
132 if (type_ == SPDY_PUSH_STREAM) { | 129 if (type_ == SPDY_PUSH_STREAM) { |
133 CHECK(response_received()); | 130 DCHECK(continue_buffering_data_); |
134 base::MessageLoop::current()->PostTask( | 131 base::MessageLoop::current()->PostTask( |
135 FROM_HERE, | 132 FROM_HERE, |
136 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr())); | 133 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr())); |
137 } else { | |
138 continue_buffering_data_ = false; | |
139 } | 134 } |
140 } | 135 } |
141 | 136 |
| 137 SpdyStream::Delegate* SpdyStream::GetDelegate() { |
| 138 return delegate_; |
| 139 } |
| 140 |
142 void SpdyStream::PushedStreamReplayData() { | 141 void SpdyStream::PushedStreamReplayData() { |
| 142 DCHECK_EQ(type_, SPDY_PUSH_STREAM); |
143 DCHECK_NE(stream_id_, 0u); | 143 DCHECK_NE(stream_id_, 0u); |
144 | 144 DCHECK(continue_buffering_data_); |
145 if (!delegate_) | |
146 return; | |
147 | 145 |
148 continue_buffering_data_ = false; | 146 continue_buffering_data_ = false; |
149 | 147 |
150 // TODO(akalin): This call may delete this object. Figure out what | 148 // The delegate methods called below may delete |this|, so use |
151 // to do in that case. | 149 // |weak_this| to detect that. |
152 int rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, OK); | 150 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); |
153 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) { | 151 |
154 // We don't have complete headers. Assume we're waiting for another | 152 CHECK(delegate_); |
155 // HEADERS frame. Since we don't have headers, we had better not have | 153 SpdyResponseHeadersStatus status = |
156 // any pending data frames. | 154 delegate_->OnResponseHeadersUpdated(response_headers_); |
157 if (pending_buffers_.size() != 0U) { | 155 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) { |
| 156 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not |
| 157 // have been closed. Since we don't have complete headers, assume |
| 158 // we're waiting for another HEADERS frame, and we had better not |
| 159 // have any pending data frames. |
| 160 CHECK(weak_this); |
| 161 if (!pending_buffers_.empty()) { |
158 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, | 162 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, |
159 "HEADERS incomplete headers, but pending data frames."); | 163 "Data received with incomplete headers."); |
160 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); | 164 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); |
161 } | 165 } |
162 return; | 166 return; |
163 } | 167 } |
164 | 168 |
165 std::vector<SpdyBuffer*> buffers; | 169 // OnResponseHeadersUpdated() may have closed |this|. |
166 pending_buffers_.release(&buffers); | 170 if (!weak_this) |
167 for (size_t i = 0; i < buffers.size(); ++i) { | 171 return; |
168 // It is always possible that a callback to the delegate results in | 172 |
169 // the delegate no longer being available. | 173 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE; |
170 if (!delegate_) | 174 |
| 175 while (!pending_buffers_.empty()) { |
| 176 // Take ownership of the first element of |pending_buffers_|. |
| 177 scoped_ptr<SpdyBuffer> buffer(pending_buffers_.front()); |
| 178 pending_buffers_.weak_erase(pending_buffers_.begin()); |
| 179 |
| 180 bool eof = (buffer == NULL); |
| 181 |
| 182 CHECK(delegate_); |
| 183 delegate_->OnDataReceived(buffer.Pass()); |
| 184 |
| 185 // OnDataReceived() may have closed |this|. |
| 186 if (!weak_this) |
| 187 return; |
| 188 |
| 189 if (eof) { |
| 190 DCHECK(pending_buffers_.empty()); |
| 191 session_->CloseActiveStream(stream_id_, OK); |
| 192 DCHECK(!weak_this); |
| 193 // |pending_buffers_| is invalid at this point. |
171 break; | 194 break; |
172 if (buffers[i]) { | |
173 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>(buffers[i])); | |
174 } else { | |
175 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>()); | |
176 session_->CloseActiveStream(stream_id_, OK); | |
177 // Note: |this| may be deleted after calling CloseActiveStream. | |
178 DCHECK_EQ(buffers.size() - 1, i); | |
179 } | 195 } |
180 } | 196 } |
181 } | 197 } |
182 | 198 |
183 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { | 199 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { |
184 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE); | 200 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE); |
185 CHECK(request_); | 201 CHECK(request_headers_); |
186 CHECK_GT(stream_id_, 0u); | 202 CHECK_GT(stream_id_, 0u); |
187 | 203 |
188 SpdyControlFlags flags = | 204 SpdyControlFlags flags = |
189 (send_status_ == NO_MORE_DATA_TO_SEND) ? | 205 (send_status_ == NO_MORE_DATA_TO_SEND) ? |
190 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE; | 206 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE; |
191 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream( | 207 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream( |
192 stream_id_, priority_, slot_, flags, *request_)); | 208 stream_id_, priority_, slot_, flags, *request_headers_)); |
193 send_time_ = base::TimeTicks::Now(); | 209 send_time_ = base::TimeTicks::Now(); |
194 return frame.Pass(); | 210 return frame.Pass(); |
195 } | 211 } |
196 | 212 |
197 void SpdyStream::DetachDelegate() { | 213 void SpdyStream::DetachDelegate() { |
198 CHECK(!in_do_loop_); | 214 CHECK(!in_do_loop_); |
199 DCHECK(!closed()); | 215 DCHECK(!closed()); |
200 delegate_ = NULL; | 216 delegate_ = NULL; |
201 Cancel(); | 217 Cancel(); |
202 } | 218 } |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 } | 382 } |
367 | 383 |
368 base::Time SpdyStream::GetRequestTime() const { | 384 base::Time SpdyStream::GetRequestTime() const { |
369 return request_time_; | 385 return request_time_; |
370 } | 386 } |
371 | 387 |
372 void SpdyStream::SetRequestTime(base::Time t) { | 388 void SpdyStream::SetRequestTime(base::Time t) { |
373 request_time_ = t; | 389 request_time_ = t; |
374 } | 390 } |
375 | 391 |
376 int SpdyStream::OnResponseHeadersReceived(const SpdyHeaderBlock& response) { | 392 int SpdyStream::OnInitialResponseHeadersReceived( |
377 int rv = OK; | 393 const SpdyHeaderBlock& initial_response_headers, |
378 | 394 base::Time response_time, |
379 metrics_.StartStream(); | 395 base::TimeTicks recv_first_byte_time) { |
380 | 396 // SpdySession guarantees that this is called at most once. |
381 // TODO(akalin): This should be handled as a protocol error. | 397 CHECK(response_headers_.empty()); |
382 DCHECK(response_->empty()); | |
383 *response_ = response; // TODO(ukai): avoid copy. | |
384 | |
385 recv_first_byte_time_ = base::TimeTicks::Now(); | |
386 response_time_ = base::Time::Now(); | |
387 | 398 |
388 // Check to make sure that we don't receive the response headers | 399 // Check to make sure that we don't receive the response headers |
389 // before we're ready for it. | 400 // before we're ready for it. |
390 switch (type_) { | 401 switch (type_) { |
391 case SPDY_BIDIRECTIONAL_STREAM: | 402 case SPDY_BIDIRECTIONAL_STREAM: |
392 // For a bidirectional stream, we're ready for the response | 403 // For a bidirectional stream, we're ready for the response |
393 // headers once we've finished sending the request headers. | 404 // headers once we've finished sending the request headers. |
394 if (io_state_ < STATE_OPEN) | 405 if (io_state_ < STATE_OPEN) |
395 return ERR_SPDY_PROTOCOL_ERROR; | 406 return ERR_SPDY_PROTOCOL_ERROR; |
396 break; | 407 break; |
397 | 408 |
398 case SPDY_REQUEST_RESPONSE_STREAM: | 409 case SPDY_REQUEST_RESPONSE_STREAM: |
399 // For a request/response stream, we're ready for the response | 410 // For a request/response stream, we're ready for the response |
400 // headers once we've finished sending the request headers and | 411 // headers once we've finished sending the request headers and |
401 // the request body (if we have one). | 412 // the request body (if we have one). |
402 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) || | 413 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) || |
403 pending_send_data_.get()) | 414 pending_send_data_.get()) |
404 return ERR_SPDY_PROTOCOL_ERROR; | 415 return ERR_SPDY_PROTOCOL_ERROR; |
405 break; | 416 break; |
406 | 417 |
407 case SPDY_PUSH_STREAM: | 418 case SPDY_PUSH_STREAM: |
408 // For a push stream, we're ready immediately. | 419 // For a push stream, we're ready immediately. |
409 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND); | 420 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND); |
410 DCHECK_EQ(io_state_, STATE_OPEN); | 421 DCHECK_EQ(io_state_, STATE_OPEN); |
411 break; | 422 break; |
412 } | 423 } |
413 | 424 |
| 425 metrics_.StartStream(); |
| 426 |
414 DCHECK_EQ(io_state_, STATE_OPEN); | 427 DCHECK_EQ(io_state_, STATE_OPEN); |
415 | 428 |
416 // TODO(akalin): Merge the code below with the code in OnHeaders(). | 429 response_time_ = response_time; |
417 | 430 recv_first_byte_time_ = recv_first_byte_time; |
418 // Append all the headers into the response header block. | 431 return MergeWithResponseHeaders(initial_response_headers); |
419 for (SpdyHeaderBlock::const_iterator it = response.begin(); | |
420 it != response.end(); ++it) { | |
421 // Disallow uppercase headers. | |
422 if (ContainsUpperAscii(it->first)) { | |
423 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
424 "Upper case characters in header: " + it->first); | |
425 return ERR_SPDY_PROTOCOL_ERROR; | |
426 } | |
427 } | |
428 | |
429 if ((*response_).find("transfer-encoding") != (*response_).end()) { | |
430 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
431 "Received transfer-encoding header"); | |
432 return ERR_SPDY_PROTOCOL_ERROR; | |
433 } | |
434 | |
435 if (delegate_) { | |
436 // May delete this object. | |
437 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv); | |
438 } | |
439 // If delegate_ is not yet attached, we'll call | |
440 // OnResponseHeadersReceived after the delegate gets attached to the | |
441 // stream. | |
442 | |
443 return rv; | |
444 } | 432 } |
445 | 433 |
446 int SpdyStream::OnHeaders(const SpdyHeaderBlock& headers) { | 434 int SpdyStream::OnAdditionalResponseHeadersReceived( |
447 DCHECK(!response_->empty()); | 435 const SpdyHeaderBlock& additional_response_headers) { |
448 | 436 if (type_ == SPDY_REQUEST_RESPONSE_STREAM) { |
449 // Append all the headers into the response header block. | 437 LOG(WARNING) << "Additional headers received for request/response stream"; |
450 for (SpdyHeaderBlock::const_iterator it = headers.begin(); | 438 return OK; |
451 it != headers.end(); ++it) { | 439 } else if (type_ == SPDY_PUSH_STREAM && |
452 // Disallow duplicate headers. This is just to be conservative. | 440 response_headers_status_ == RESPONSE_HEADERS_ARE_COMPLETE) { |
453 if ((*response_).find(it->first) != (*response_).end()) { | 441 LOG(WARNING) << "Additional headers received for push stream"; |
454 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "HEADERS duplicate header"); | 442 return OK; |
455 response_status_ = ERR_SPDY_PROTOCOL_ERROR; | |
456 return ERR_SPDY_PROTOCOL_ERROR; | |
457 } | |
458 | |
459 // Disallow uppercase headers. | |
460 if (ContainsUpperAscii(it->first)) { | |
461 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
462 "Upper case characters in header: " + it->first); | |
463 return ERR_SPDY_PROTOCOL_ERROR; | |
464 } | |
465 | |
466 (*response_)[it->first] = it->second; | |
467 } | 443 } |
468 | 444 return MergeWithResponseHeaders(additional_response_headers); |
469 if ((*response_).find("transfer-encoding") != (*response_).end()) { | |
470 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
471 "Received transfer-encoding header"); | |
472 return ERR_SPDY_PROTOCOL_ERROR; | |
473 } | |
474 | |
475 int rv = OK; | |
476 if (delegate_) { | |
477 // May delete this object. | |
478 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv); | |
479 // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more | |
480 // headers before the response header block is complete. | |
481 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) | |
482 rv = OK; | |
483 } | |
484 return rv; | |
485 } | 445 } |
486 | 446 |
487 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { | 447 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { |
488 DCHECK(session_->IsStreamActive(stream_id_)); | 448 DCHECK(session_->IsStreamActive(stream_id_)); |
489 // If we don't have a response, then the SYN_REPLY did not come through. | |
490 // We cannot pass data up to the caller unless the reply headers have been | |
491 // received. | |
492 if (!response_received()) { | |
493 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response."); | |
494 session_->CloseActiveStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); | |
495 return; | |
496 } | |
497 | 449 |
| 450 // If we're still buffering data for a push stream, we will do the |
| 451 // check for data received with incomplete headers in |
| 452 // PushedStreamReplayData(). |
498 if (!delegate_ || continue_buffering_data_) { | 453 if (!delegate_ || continue_buffering_data_) { |
| 454 DCHECK_EQ(type_, SPDY_PUSH_STREAM); |
499 // It should be valid for this to happen in the server push case. | 455 // It should be valid for this to happen in the server push case. |
500 // We'll return received data when delegate gets attached to the stream. | 456 // We'll return received data when delegate gets attached to the stream. |
501 if (buffer) { | 457 if (buffer) { |
502 pending_buffers_.push_back(buffer.release()); | 458 pending_buffers_.push_back(buffer.release()); |
503 } else { | 459 } else { |
504 pending_buffers_.push_back(NULL); | 460 pending_buffers_.push_back(NULL); |
505 metrics_.StopStream(); | 461 metrics_.StopStream(); |
506 // Note: we leave the stream open in the session until the stream | 462 // Note: we leave the stream open in the session until the stream |
507 // is claimed. | 463 // is claimed. |
508 } | 464 } |
509 return; | 465 return; |
510 } | 466 } |
511 | 467 |
| 468 // If we have response headers but the delegate has indicated that |
| 469 // it's still incomplete, then that's a protocol error. |
| 470 if (response_headers_status_ == RESPONSE_HEADERS_ARE_INCOMPLETE) { |
| 471 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, |
| 472 "Data received with incomplete headers."); |
| 473 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); |
| 474 return; |
| 475 } |
| 476 |
512 CHECK(!closed()); | 477 CHECK(!closed()); |
513 | 478 |
514 if (!buffer) { | 479 if (!buffer) { |
515 metrics_.StopStream(); | 480 metrics_.StopStream(); |
| 481 // Deletes |this|. |
516 session_->CloseActiveStream(stream_id_, OK); | 482 session_->CloseActiveStream(stream_id_, OK); |
517 // Note: |this| may be deleted after calling CloseActiveStream. | |
518 return; | 483 return; |
519 } | 484 } |
520 | 485 |
521 size_t length = buffer->GetRemainingSize(); | 486 size_t length = buffer->GetRemainingSize(); |
522 DCHECK_LE(length, session_->GetDataFrameMaximumPayload()); | 487 DCHECK_LE(length, session_->GetDataFrameMaximumPayload()); |
523 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) { | 488 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) { |
524 DecreaseRecvWindowSize(static_cast<int32>(length)); | 489 DecreaseRecvWindowSize(static_cast<int32>(length)); |
525 buffer->AddConsumeCallback( | 490 buffer->AddConsumeCallback( |
526 base::Bind(&SpdyStream::OnReadBufferConsumed, GetWeakPtr())); | 491 base::Bind(&SpdyStream::OnReadBufferConsumed, GetWeakPtr())); |
527 } | 492 } |
528 | 493 |
529 // Track our bandwidth. | 494 // Track our bandwidth. |
530 metrics_.RecordBytes(length); | 495 metrics_.RecordBytes(length); |
531 recv_bytes_ += length; | 496 recv_bytes_ += length; |
532 recv_last_byte_time_ = base::TimeTicks::Now(); | 497 recv_last_byte_time_ = base::TimeTicks::Now(); |
533 | 498 |
534 if (delegate_->OnDataReceived(buffer.Pass()) != OK) { | 499 // May close |this|. |
535 // |delegate_| rejected the data. | 500 delegate_->OnDataReceived(buffer.Pass()); |
536 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "Delegate rejected the data"); | |
537 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); | |
538 return; | |
539 } | |
540 } | 501 } |
541 | 502 |
542 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, | 503 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, |
543 size_t frame_size) { | 504 size_t frame_size) { |
544 if (frame_size < session_->GetFrameMinimumSize() || | 505 if (frame_size < session_->GetFrameMinimumSize() || |
545 frame_size > session_->GetFrameMaximumSize()) { | 506 frame_size > session_->GetFrameMaximumSize()) { |
546 NOTREACHED(); | 507 NOTREACHED(); |
547 return; | 508 return; |
548 } | 509 } |
549 if (closed()) | 510 if (closed()) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 | 546 |
586 void SpdyStream::Close() { | 547 void SpdyStream::Close() { |
587 CHECK(!in_do_loop_); | 548 CHECK(!in_do_loop_); |
588 if (stream_id_ != 0) { | 549 if (stream_id_ != 0) { |
589 session_->CloseActiveStream(stream_id_, OK); | 550 session_->CloseActiveStream(stream_id_, OK); |
590 } else { | 551 } else { |
591 session_->CloseCreatedStream(GetWeakPtr(), OK); | 552 session_->CloseCreatedStream(GetWeakPtr(), OK); |
592 } | 553 } |
593 } | 554 } |
594 | 555 |
595 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> headers, | 556 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> request_headers, |
596 SpdySendStatus send_status) { | 557 SpdySendStatus send_status) { |
597 CHECK_NE(type_, SPDY_PUSH_STREAM); | 558 CHECK_NE(type_, SPDY_PUSH_STREAM); |
598 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); | 559 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); |
599 CHECK(!request_); | 560 CHECK(!request_headers_); |
600 CHECK(!pending_send_data_.get()); | 561 CHECK(!pending_send_data_.get()); |
601 CHECK_EQ(io_state_, STATE_NONE); | 562 CHECK_EQ(io_state_, STATE_NONE); |
602 request_ = headers.Pass(); | 563 request_headers_ = request_headers.Pass(); |
603 send_status_ = send_status; | 564 send_status_ = send_status; |
604 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; | 565 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; |
605 return DoLoop(OK); | 566 return DoLoop(OK); |
606 } | 567 } |
607 | 568 |
608 void SpdyStream::SendData(IOBuffer* data, | 569 void SpdyStream::SendData(IOBuffer* data, |
609 int length, | 570 int length, |
610 SpdySendStatus send_status) { | 571 SpdySendStatus send_status) { |
611 CHECK_NE(type_, SPDY_PUSH_STREAM); | 572 CHECK_NE(type_, SPDY_PUSH_STREAM); |
612 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); | 573 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); |
(...skipping 25 matching lines...) Expand all Loading... |
638 NetLog::IntegerCallback("stream_id", stream_id_)); | 599 NetLog::IntegerCallback("stream_id", stream_id_)); |
639 send_stalled_by_flow_control_ = false; | 600 send_stalled_by_flow_control_ = false; |
640 QueueNextDataFrame(); | 601 QueueNextDataFrame(); |
641 } | 602 } |
642 } | 603 } |
643 | 604 |
644 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() { | 605 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() { |
645 return weak_ptr_factory_.GetWeakPtr(); | 606 return weak_ptr_factory_.GetWeakPtr(); |
646 } | 607 } |
647 | 608 |
648 bool SpdyStream::HasUrl() const { | |
649 if (type_ == SPDY_PUSH_STREAM) | |
650 return response_received(); | |
651 return request_ != NULL; | |
652 } | |
653 | |
654 GURL SpdyStream::GetUrl() const { | |
655 DCHECK(HasUrl()); | |
656 | |
657 const SpdyHeaderBlock& headers = | |
658 (type_ == SPDY_PUSH_STREAM) ? *response_ : *request_; | |
659 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(), | |
660 type_ == SPDY_PUSH_STREAM); | |
661 } | |
662 | |
663 bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { | 609 bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { |
664 if (stream_id_ == 0) | 610 if (stream_id_ == 0) |
665 return false; | 611 return false; |
666 | 612 |
667 return session_->GetLoadTimingInfo(stream_id_, load_timing_info); | 613 return session_->GetLoadTimingInfo(stream_id_, load_timing_info); |
668 } | 614 } |
669 | 615 |
| 616 GURL SpdyStream::GetUrl() const { |
| 617 if (type_ != SPDY_PUSH_STREAM && !request_headers_) |
| 618 return GURL(); |
| 619 |
| 620 const SpdyHeaderBlock& headers = |
| 621 (type_ == SPDY_PUSH_STREAM) ? response_headers_ : *request_headers_; |
| 622 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(), |
| 623 type_ == SPDY_PUSH_STREAM); |
| 624 } |
| 625 |
| 626 bool SpdyStream::HasUrl() const { |
| 627 return !GetUrl().is_empty(); |
| 628 } |
| 629 |
670 void SpdyStream::OnGetDomainBoundCertComplete(int result) { | 630 void SpdyStream::OnGetDomainBoundCertComplete(int result) { |
671 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); | 631 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); |
672 DoLoop(result); | 632 DoLoop(result); |
673 } | 633 } |
674 | 634 |
675 int SpdyStream::DoLoop(int result) { | 635 int SpdyStream::DoLoop(int result) { |
676 CHECK(!in_do_loop_); | 636 CHECK(!in_do_loop_); |
677 in_do_loop_ = true; | 637 in_do_loop_ = true; |
678 | 638 |
679 do { | 639 do { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE && | 687 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE && |
728 io_state_ != STATE_OPEN); | 688 io_state_ != STATE_OPEN); |
729 | 689 |
730 CHECK(in_do_loop_); | 690 CHECK(in_do_loop_); |
731 in_do_loop_ = false; | 691 in_do_loop_ = false; |
732 | 692 |
733 return result; | 693 return result; |
734 } | 694 } |
735 | 695 |
736 int SpdyStream::DoGetDomainBoundCert() { | 696 int SpdyStream::DoGetDomainBoundCert() { |
737 CHECK(request_); | 697 CHECK(request_headers_); |
738 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 698 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
739 GURL url = GetUrl(); | 699 GURL url = GetUrl(); |
740 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) { | 700 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) { |
741 // Proceed directly to sending the request headers | 701 // Proceed directly to sending the request headers |
742 io_state_ = STATE_SEND_REQUEST_HEADERS; | 702 io_state_ = STATE_SEND_REQUEST_HEADERS; |
743 return OK; | 703 return OK; |
744 } | 704 } |
745 | 705 |
746 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl()); | 706 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl()); |
747 if (slot_ != SpdyCredentialState::kNoEntry) { | 707 if (slot_ != SpdyCredentialState::kNoEntry) { |
(...skipping 19 matching lines...) Expand all Loading... |
767 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 727 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
768 if (result != OK) | 728 if (result != OK) |
769 return result; | 729 return result; |
770 | 730 |
771 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; | 731 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; |
772 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); | 732 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); |
773 return OK; | 733 return OK; |
774 } | 734 } |
775 | 735 |
776 int SpdyStream::DoSendDomainBoundCert() { | 736 int SpdyStream::DoSendDomainBoundCert() { |
777 CHECK(request_); | 737 CHECK(request_headers_); |
778 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 738 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
779 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; | 739 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; |
780 | 740 |
781 std::string origin = GetUrl().GetOrigin().spec(); | 741 std::string origin = GetUrl().GetOrigin().spec(); |
782 DCHECK(origin[origin.length() - 1] == '/'); | 742 DCHECK(origin[origin.length() - 1] == '/'); |
783 origin.erase(origin.length() - 1); // Trim trailing slash. | 743 origin.erase(origin.length() - 1); // Trim trailing slash. |
784 scoped_ptr<SpdyFrame> frame; | 744 scoped_ptr<SpdyFrame> frame; |
785 int rv = session_->CreateCredentialFrame( | 745 int rv = session_->CreateCredentialFrame( |
786 origin, domain_bound_cert_type_, domain_bound_private_key_, | 746 origin, domain_bound_cert_type_, domain_bound_private_key_, |
787 domain_bound_cert_, priority_, &frame); | 747 domain_bound_cert_, priority_, &frame); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
859 | 819 |
860 } // namespace | 820 } // namespace |
861 | 821 |
862 int SpdyStream::DoSendRequestHeadersComplete() { | 822 int SpdyStream::DoSendRequestHeadersComplete() { |
863 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 823 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
864 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM); | 824 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM); |
865 DCHECK_NE(stream_id_, 0u); | 825 DCHECK_NE(stream_id_, 0u); |
866 | 826 |
867 io_state_ = STATE_OPEN; | 827 io_state_ = STATE_OPEN; |
868 | 828 |
869 // Do this before calling into the |delegate_| as that call may | |
870 // delete us. | |
871 int result = GetOpenStateResult(type_, send_status_); | |
872 | |
873 CHECK(delegate_); | 829 CHECK(delegate_); |
| 830 // Must not close |this|; if it does, it will trigger the |in_do_loop_| |
| 831 // check in the destructor. |
874 delegate_->OnRequestHeadersSent(); | 832 delegate_->OnRequestHeadersSent(); |
875 | 833 |
876 return result; | 834 return GetOpenStateResult(type_, send_status_); |
877 } | 835 } |
878 | 836 |
879 int SpdyStream::DoOpen() { | 837 int SpdyStream::DoOpen() { |
880 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 838 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
881 | 839 |
882 if (just_completed_frame_type_ != DATA) { | 840 if (just_completed_frame_type_ != DATA) { |
883 NOTREACHED(); | 841 NOTREACHED(); |
884 return ERR_UNEXPECTED; | 842 return ERR_UNEXPECTED; |
885 } | 843 } |
886 | 844 |
(...skipping 15 matching lines...) Expand all Loading... |
902 send_bytes_ += frame_payload_size; | 860 send_bytes_ += frame_payload_size; |
903 | 861 |
904 pending_send_data_->DidConsume(frame_payload_size); | 862 pending_send_data_->DidConsume(frame_payload_size); |
905 if (pending_send_data_->BytesRemaining() > 0) { | 863 if (pending_send_data_->BytesRemaining() > 0) { |
906 QueueNextDataFrame(); | 864 QueueNextDataFrame(); |
907 return ERR_IO_PENDING; | 865 return ERR_IO_PENDING; |
908 } | 866 } |
909 | 867 |
910 pending_send_data_ = NULL; | 868 pending_send_data_ = NULL; |
911 | 869 |
912 // Do this before calling into the |delegate_| as that call may | |
913 // delete us. | |
914 int result = GetOpenStateResult(type_, send_status_); | |
915 | |
916 CHECK(delegate_); | 870 CHECK(delegate_); |
| 871 // Must not close |this|; if it does, it will trigger the |
| 872 // |in_do_loop_| check in the destructor. |
917 delegate_->OnDataSent(); | 873 delegate_->OnDataSent(); |
918 | 874 |
919 return result; | 875 return GetOpenStateResult(type_, send_status_); |
920 } | 876 } |
921 | 877 |
922 void SpdyStream::UpdateHistograms() { | 878 void SpdyStream::UpdateHistograms() { |
923 // We need at least the receive timers to be filled in, as otherwise | 879 // We need at least the receive timers to be filled in, as otherwise |
924 // metrics can be bogus. | 880 // metrics can be bogus. |
925 if (recv_first_byte_time_.is_null() || recv_last_byte_time_.is_null()) | 881 if (recv_first_byte_time_.is_null() || recv_last_byte_time_.is_null()) |
926 return; | 882 return; |
927 | 883 |
928 base::TimeTicks effective_send_time; | 884 base::TimeTicks effective_send_time; |
929 if (type_ == SPDY_PUSH_STREAM) { | 885 if (type_ == SPDY_PUSH_STREAM) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
983 base::Bind(&SpdyStream::OnWriteBufferConsumed, | 939 base::Bind(&SpdyStream::OnWriteBufferConsumed, |
984 GetWeakPtr(), payload_size)); | 940 GetWeakPtr(), payload_size)); |
985 } | 941 } |
986 | 942 |
987 session_->EnqueueStreamWrite( | 943 session_->EnqueueStreamWrite( |
988 GetWeakPtr(), DATA, | 944 GetWeakPtr(), DATA, |
989 scoped_ptr<SpdyBufferProducer>( | 945 scoped_ptr<SpdyBufferProducer>( |
990 new SimpleBufferProducer(data_buffer.Pass()))); | 946 new SimpleBufferProducer(data_buffer.Pass()))); |
991 } | 947 } |
992 | 948 |
| 949 int SpdyStream::MergeWithResponseHeaders( |
| 950 const SpdyHeaderBlock& new_response_headers) { |
| 951 if (new_response_headers.find("transfer-encoding") != |
| 952 new_response_headers.end()) { |
| 953 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, |
| 954 "Received transfer-encoding header"); |
| 955 return ERR_SPDY_PROTOCOL_ERROR; |
| 956 } |
| 957 |
| 958 for (SpdyHeaderBlock::const_iterator it = new_response_headers.begin(); |
| 959 it != new_response_headers.end(); ++it) { |
| 960 // Disallow uppercase headers. |
| 961 if (ContainsUppercaseAscii(it->first)) { |
| 962 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, |
| 963 "Upper case characters in header: " + it->first); |
| 964 return ERR_SPDY_PROTOCOL_ERROR; |
| 965 } |
| 966 |
| 967 SpdyHeaderBlock::iterator it2 = response_headers_.lower_bound(it->first); |
| 968 // Disallow duplicate headers. This is just to be conservative. |
| 969 if (it2 != response_headers_.end() && it2->first == it->first) { |
| 970 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, |
| 971 "Duplicate header: " + it->first); |
| 972 return ERR_SPDY_PROTOCOL_ERROR; |
| 973 } |
| 974 |
| 975 response_headers_.insert(it2, *it); |
| 976 } |
| 977 |
| 978 // If delegate_ is not yet attached, we'll call |
| 979 // OnResponseHeadersUpdated() after the delegate gets attached to |
| 980 // the stream. |
| 981 if (delegate_) { |
| 982 // The call to OnResponseHeadersUpdated() below may delete |this|, |
| 983 // so use |weak_this| to detect that. |
| 984 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); |
| 985 |
| 986 SpdyResponseHeadersStatus status = |
| 987 delegate_->OnResponseHeadersUpdated(response_headers_); |
| 988 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) { |
| 989 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not |
| 990 // have been closed. |
| 991 CHECK(weak_this); |
| 992 // Incomplete headers are OK only for push streams. |
| 993 if (type_ != SPDY_PUSH_STREAM) |
| 994 return ERR_INCOMPLETE_SPDY_HEADERS; |
| 995 } else if (weak_this) { |
| 996 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE; |
| 997 } |
| 998 } |
| 999 |
| 1000 return OK; |
| 1001 } |
| 1002 |
993 } // namespace net | 1003 } // namespace net |
OLD | NEW |