| 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 |