Chromium Code Reviews| 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> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 int32 delta, | 37 int32 delta, |
| 38 int32 window_size, | 38 int32 window_size, |
| 39 NetLog::LogLevel /* log_level */) { | 39 NetLog::LogLevel /* log_level */) { |
| 40 base::DictionaryValue* dict = new base::DictionaryValue(); | 40 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 41 dict->SetInteger("stream_id", stream_id); | 41 dict->SetInteger("stream_id", stream_id); |
| 42 dict->SetInteger("delta", delta); | 42 dict->SetInteger("delta", delta); |
| 43 dict->SetInteger("window_size", window_size); | 43 dict->SetInteger("window_size", window_size); |
| 44 return dict; | 44 return dict; |
| 45 } | 45 } |
| 46 | 46 |
| 47 bool ContainsUpperAscii(const std::string& str) { | 47 bool ContainsUppercaseAscii(const std::string& str) { |
| 48 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { | 48 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { |
| 49 if (*i >= 'A' && *i <= 'Z') { | 49 if (*i >= 'A' && *i <= 'Z') { |
| 50 return true; | 50 return true; |
| 51 } | 51 } |
| 52 } | 52 } |
| 53 return false; | 53 return false; |
| 54 } | 54 } |
| 55 | 55 |
| 56 } // namespace | 56 } // namespace |
| 57 | 57 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 82 SpdyStream::SpdyStream(SpdyStreamType type, | 82 SpdyStream::SpdyStream(SpdyStreamType type, |
| 83 SpdySession* session, | 83 SpdySession* session, |
| 84 const std::string& path, | 84 const std::string& path, |
| 85 RequestPriority priority, | 85 RequestPriority priority, |
| 86 int32 initial_send_window_size, | 86 int32 initial_send_window_size, |
| 87 int32 initial_recv_window_size, | 87 int32 initial_recv_window_size, |
| 88 const BoundNetLog& net_log) | 88 const BoundNetLog& net_log) |
| 89 : type_(type), | 89 : type_(type), |
| 90 weak_ptr_factory_(this), | 90 weak_ptr_factory_(this), |
| 91 in_do_loop_(false), | 91 in_do_loop_(false), |
| 92 continue_buffering_data_(true), | 92 continue_buffering_data_(type_ == SPDY_PUSH_STREAM), |
| 93 stream_id_(0), | 93 stream_id_(0), |
| 94 path_(path), | 94 path_(path), |
| 95 priority_(priority), | 95 priority_(priority), |
| 96 slot_(0), | 96 slot_(0), |
| 97 send_stalled_by_flow_control_(false), | 97 send_stalled_by_flow_control_(false), |
| 98 send_window_size_(initial_send_window_size), | 98 send_window_size_(initial_send_window_size), |
| 99 recv_window_size_(initial_recv_window_size), | 99 recv_window_size_(initial_recv_window_size), |
| 100 unacked_recv_window_bytes_(0), | 100 unacked_recv_window_bytes_(0), |
| 101 response_received_(false), | |
| 102 session_(session), | 101 session_(session), |
| 103 delegate_(NULL), | 102 delegate_(NULL), |
| 104 send_status_( | 103 send_status_( |
| 105 (type_ == SPDY_PUSH_STREAM) ? | 104 (type_ == SPDY_PUSH_STREAM) ? |
| 106 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND), | 105 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND), |
| 107 request_time_(base::Time::Now()), | 106 request_time_(base::Time::Now()), |
| 108 response_(new SpdyHeaderBlock), | |
| 109 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE), | 107 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE), |
| 110 response_status_(OK), | 108 response_status_(OK), |
| 111 net_log_(net_log), | 109 net_log_(net_log), |
| 112 send_bytes_(0), | 110 send_bytes_(0), |
| 113 recv_bytes_(0), | 111 recv_bytes_(0), |
| 114 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE), | 112 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE), |
| 115 just_completed_frame_type_(DATA), | 113 just_completed_frame_type_(DATA), |
| 116 just_completed_frame_size_(0) { | 114 just_completed_frame_size_(0) { |
| 117 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || | 115 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || |
| 118 type_ == SPDY_REQUEST_RESPONSE_STREAM || | 116 type_ == SPDY_REQUEST_RESPONSE_STREAM || |
| 119 type_ == SPDY_PUSH_STREAM); | 117 type_ == SPDY_PUSH_STREAM); |
| 120 } | 118 } |
| 121 | 119 |
| 122 SpdyStream::~SpdyStream() { | 120 SpdyStream::~SpdyStream() { |
| 123 CHECK(!in_do_loop_); | 121 CHECK(!in_do_loop_); |
| 124 UpdateHistograms(); | 122 UpdateHistograms(); |
| 125 } | 123 } |
| 126 | 124 |
| 127 void SpdyStream::SetDelegate(Delegate* delegate) { | 125 void SpdyStream::SetDelegate(Delegate* delegate) { |
| 126 Delegate* old_delegate = delegate_; | |
|
Ryan Hamilton
2013/06/19 18:58:36
Is it "valid" to have more than one delegate in th
akalin
2013/06/21 21:13:25
Yeap, in the redirect case in SpdyProxyClientSocke
| |
| 128 CHECK(delegate); | 127 CHECK(delegate); |
|
Ryan Hamilton
2013/06/19 18:58:36
nit: can you make this the first line
akalin
2013/06/21 21:13:25
Done.
| |
| 129 delegate_ = delegate; | 128 delegate_ = delegate; |
| 130 | 129 |
| 131 if (type_ == SPDY_PUSH_STREAM) { | 130 if (type_ == SPDY_PUSH_STREAM && !old_delegate) { |
| 132 CHECK(response_received()); | 131 DCHECK(continue_buffering_data_); |
| 133 base::MessageLoop::current()->PostTask( | 132 base::MessageLoop::current()->PostTask( |
| 134 FROM_HERE, | 133 FROM_HERE, |
| 135 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr())); | 134 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr())); |
| 136 } else { | |
| 137 continue_buffering_data_ = false; | |
| 138 } | 135 } |
| 139 } | 136 } |
| 140 | 137 |
| 138 SpdyStream::Delegate* SpdyStream::GetDelegate() { | |
| 139 return delegate_; | |
| 140 } | |
| 141 | |
| 141 void SpdyStream::PushedStreamReplayData() { | 142 void SpdyStream::PushedStreamReplayData() { |
| 143 DCHECK_EQ(type_, SPDY_PUSH_STREAM); | |
| 142 DCHECK_NE(stream_id_, 0u); | 144 DCHECK_NE(stream_id_, 0u); |
| 143 | 145 DCHECK(continue_buffering_data_); |
| 144 if (!delegate_) | |
| 145 return; | |
| 146 | 146 |
| 147 continue_buffering_data_ = false; | 147 continue_buffering_data_ = false; |
| 148 | 148 |
| 149 // TODO(akalin): This call may delete this object. Figure out what | 149 // The delegate methods called below may delete |this|, so use |
| 150 // to do in that case. | 150 // |weak_this| to detect that. |
| 151 int rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, OK); | 151 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); |
| 152 | |
| 153 CHECK(delegate_); | |
| 154 CHECK(response_headers_); | |
| 155 int rv = delegate_->OnResponseHeadersUpdated(*response_headers_); | |
| 156 DCHECK(rv == OK || rv == ERR_INCOMPLETE_SPDY_HEADERS); | |
| 152 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) { | 157 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) { |
| 153 // We don't have complete headers. Assume we're waiting for another | 158 // Since ERR_INCOMPLETE_SPDY_HEADERS was returned, we know that |
| 154 // HEADERS frame. Since we don't have headers, we had better not have | 159 // we're not closed/deleted. Since we don't have complete headers, |
| 155 // any pending data frames. | 160 // assume we're waiting for another HEADERS frame, and we had |
| 156 if (pending_buffers_.size() != 0U) { | 161 // better not have any pending data frames. |
| 162 CHECK(weak_this); | |
| 163 if (!pending_buffers_.empty()) { | |
| 157 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, | 164 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, |
| 158 "HEADERS incomplete headers, but pending data frames."); | 165 "HEADERS incomplete headers, but pending data frames."); |
| 159 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); | 166 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); |
| 160 } | 167 } |
| 161 return; | 168 return; |
| 162 } | 169 } |
| 163 | 170 |
| 164 std::vector<SpdyBuffer*> buffers; | 171 if (!weak_this) |
| 165 pending_buffers_.release(&buffers); | 172 return; |
| 166 for (size_t i = 0; i < buffers.size(); ++i) { | 173 |
| 167 // It is always possible that a callback to the delegate results in | 174 while (!pending_buffers_.empty()) { |
| 168 // the delegate no longer being available. | 175 // Take ownership of the first element of |pending_buffers_|. |
| 169 if (!delegate_) | 176 scoped_ptr<SpdyBuffer> buffer(pending_buffers_.front()); |
| 170 break; | 177 pending_buffers_.weak_erase(pending_buffers_.begin()); |
| 171 if (buffers[i]) { | 178 |
| 172 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>(buffers[i])); | 179 bool eof = (buffer == NULL); |
| 173 } else { | 180 |
| 174 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>()); | 181 CHECK(delegate_); |
| 182 delegate_->OnDataReceived(buffer.Pass()); | |
| 183 | |
| 184 if (!weak_this) | |
| 185 return; | |
|
Ryan Hamilton
2013/06/19 18:58:36
do we need to make this check every time we invoke
akalin
2013/06/21 21:13:25
Audited the other delegate methods and added comme
| |
| 186 | |
| 187 if (eof) { | |
| 188 DCHECK(pending_buffers_.empty()); | |
| 175 session_->CloseActiveStream(stream_id_, OK); | 189 session_->CloseActiveStream(stream_id_, OK); |
| 176 // Note: |this| may be deleted after calling CloseActiveStream. | 190 DCHECK(!weak_this); |
| 177 DCHECK_EQ(buffers.size() - 1, i); | |
| 178 } | 191 } |
| 179 } | 192 } |
| 180 } | 193 } |
| 181 | 194 |
| 182 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { | 195 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { |
| 183 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE); | 196 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE); |
| 184 CHECK(request_); | 197 CHECK(request_headers_); |
| 185 CHECK_GT(stream_id_, 0u); | 198 CHECK_GT(stream_id_, 0u); |
| 186 | 199 |
| 187 SpdyControlFlags flags = | 200 SpdyControlFlags flags = |
| 188 (send_status_ == NO_MORE_DATA_TO_SEND) ? | 201 (send_status_ == NO_MORE_DATA_TO_SEND) ? |
| 189 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE; | 202 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE; |
| 190 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream( | 203 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream( |
| 191 stream_id_, priority_, slot_, flags, *request_)); | 204 stream_id_, priority_, slot_, flags, *request_headers_)); |
| 192 send_time_ = base::TimeTicks::Now(); | 205 send_time_ = base::TimeTicks::Now(); |
| 193 return frame.Pass(); | 206 return frame.Pass(); |
| 194 } | 207 } |
| 195 | 208 |
| 196 void SpdyStream::DetachDelegate() { | 209 void SpdyStream::DetachDelegate() { |
| 197 CHECK(!in_do_loop_); | 210 CHECK(!in_do_loop_); |
| 198 DCHECK(!closed()); | 211 DCHECK(!closed()); |
| 199 delegate_ = NULL; | 212 delegate_ = NULL; |
| 200 Cancel(); | 213 Cancel(); |
| 201 } | 214 } |
| 202 | 215 |
| 216 bool SpdyStream::ReceivedInitialResponseHeaders() const { | |
| 217 return response_headers_ != NULL; | |
| 218 } | |
| 219 | |
| 203 void SpdyStream::AdjustSendWindowSize(int32 delta_window_size) { | 220 void SpdyStream::AdjustSendWindowSize(int32 delta_window_size) { |
| 204 DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); | 221 DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); |
| 205 | 222 |
| 206 if (closed()) | 223 if (closed()) |
| 207 return; | 224 return; |
| 208 | 225 |
| 209 // Check for wraparound. | 226 // Check for wraparound. |
| 210 if (send_window_size_ > 0) { | 227 if (send_window_size_ > 0) { |
| 211 DCHECK_LE(delta_window_size, kint32max - send_window_size_); | 228 DCHECK_LE(delta_window_size, kint32max - send_window_size_); |
| 212 } | 229 } |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 } | 382 } |
| 366 | 383 |
| 367 base::Time SpdyStream::GetRequestTime() const { | 384 base::Time SpdyStream::GetRequestTime() const { |
| 368 return request_time_; | 385 return request_time_; |
| 369 } | 386 } |
| 370 | 387 |
| 371 void SpdyStream::SetRequestTime(base::Time t) { | 388 void SpdyStream::SetRequestTime(base::Time t) { |
| 372 request_time_ = t; | 389 request_time_ = t; |
| 373 } | 390 } |
| 374 | 391 |
| 375 int SpdyStream::OnResponseHeadersReceived(const SpdyHeaderBlock& response) { | 392 int SpdyStream::OnInitialResponseHeadersReceived( |
| 376 int rv = OK; | 393 const SpdyHeaderBlock& initial_response_headers, |
| 377 | 394 base::Time response_time, |
| 378 metrics_.StartStream(); | 395 base::TimeTicks recv_first_byte_time) { |
| 379 | 396 // SpdySession guarantees that this is called at most once. |
| 380 // TODO(akalin): This should be handled as a protocol error. | 397 CHECK(!response_headers_); |
| 381 DCHECK(response_->empty()); | |
| 382 *response_ = response; // TODO(ukai): avoid copy. | |
| 383 | |
| 384 recv_first_byte_time_ = base::TimeTicks::Now(); | |
| 385 response_time_ = base::Time::Now(); | |
|
Ryan Hamilton
2013/06/19 18:58:36
I see that you pushed this logic up from the strea
akalin
2013/06/21 21:13:25
There was a TODO somewhere to record the response
| |
| 386 | 398 |
| 387 // 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 |
| 388 // before we're ready for it. | 400 // before we're ready for it. |
| 389 switch (type_) { | 401 switch (type_) { |
| 390 case SPDY_BIDIRECTIONAL_STREAM: | 402 case SPDY_BIDIRECTIONAL_STREAM: |
| 391 // For a bidirectional stream, we're ready for the response | 403 // For a bidirectional stream, we're ready for the response |
| 392 // headers once we've finished sending the request headers. | 404 // headers once we've finished sending the request headers. |
| 393 if (io_state_ < STATE_OPEN) | 405 if (io_state_ < STATE_OPEN) |
| 394 return ERR_SPDY_PROTOCOL_ERROR; | 406 return ERR_SPDY_PROTOCOL_ERROR; |
| 395 break; | 407 break; |
| 396 | 408 |
| 397 case SPDY_REQUEST_RESPONSE_STREAM: | 409 case SPDY_REQUEST_RESPONSE_STREAM: |
| 398 // For a request/response stream, we're ready for the response | 410 // For a request/response stream, we're ready for the response |
| 399 // headers once we've finished sending the request headers and | 411 // headers once we've finished sending the request headers and |
| 400 // the request body (if we have one). | 412 // the request body (if we have one). |
| 401 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) || | 413 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) || |
| 402 pending_send_data_.get()) | 414 pending_send_data_.get()) |
| 403 return ERR_SPDY_PROTOCOL_ERROR; | 415 return ERR_SPDY_PROTOCOL_ERROR; |
| 404 break; | 416 break; |
| 405 | 417 |
| 406 case SPDY_PUSH_STREAM: | 418 case SPDY_PUSH_STREAM: |
| 407 // For a push stream, we're ready immediately. | 419 // For a push stream, we're ready immediately. |
| 408 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND); | 420 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND); |
| 409 DCHECK_EQ(io_state_, STATE_OPEN); | 421 DCHECK_EQ(io_state_, STATE_OPEN); |
| 410 break; | 422 break; |
| 411 } | 423 } |
| 412 | 424 |
| 425 metrics_.StartStream(); | |
|
Ryan Hamilton
2013/06/19 18:58:36
I notice that this moved to here. This means that
akalin
2013/06/21 21:13:25
I think so. That just means that erroneous streams
| |
| 426 | |
| 413 DCHECK_EQ(io_state_, STATE_OPEN); | 427 DCHECK_EQ(io_state_, STATE_OPEN); |
| 414 | 428 |
| 415 // TODO(akalin): Merge the code below with the code in OnHeaders(). | 429 response_headers_.reset(new SpdyHeaderBlock()); |
| 416 | 430 response_time_ = response_time; |
| 417 // Append all the headers into the response header block. | 431 recv_first_byte_time_ = recv_first_byte_time; |
| 418 for (SpdyHeaderBlock::const_iterator it = response.begin(); | 432 return MergeWithResponseHeaders(initial_response_headers); |
| 419 it != response.end(); ++it) { | |
| 420 // Disallow uppercase headers. | |
| 421 if (ContainsUpperAscii(it->first)) { | |
| 422 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 423 "Upper case characters in header: " + it->first); | |
| 424 return ERR_SPDY_PROTOCOL_ERROR; | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 if ((*response_).find("transfer-encoding") != (*response_).end()) { | |
| 429 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 430 "Received transfer-encoding header"); | |
| 431 return ERR_SPDY_PROTOCOL_ERROR; | |
| 432 } | |
| 433 | |
| 434 if (delegate_) { | |
| 435 // May delete this object. | |
| 436 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv); | |
| 437 } | |
| 438 // If delegate_ is not yet attached, we'll call | |
| 439 // OnResponseHeadersReceived after the delegate gets attached to the | |
| 440 // stream. | |
| 441 | |
| 442 return rv; | |
| 443 } | 433 } |
| 444 | 434 |
| 445 int SpdyStream::OnHeaders(const SpdyHeaderBlock& headers) { | 435 int SpdyStream::OnAdditionalResponseHeadersReceived( |
| 446 DCHECK(!response_->empty()); | 436 const SpdyHeaderBlock& additional_response_headers) { |
| 447 | 437 return MergeWithResponseHeaders(additional_response_headers); |
| 448 // Append all the headers into the response header block. | |
| 449 for (SpdyHeaderBlock::const_iterator it = headers.begin(); | |
| 450 it != headers.end(); ++it) { | |
| 451 // Disallow duplicate headers. This is just to be conservative. | |
| 452 if ((*response_).find(it->first) != (*response_).end()) { | |
| 453 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "HEADERS duplicate header"); | |
| 454 response_status_ = ERR_SPDY_PROTOCOL_ERROR; | |
| 455 return ERR_SPDY_PROTOCOL_ERROR; | |
| 456 } | |
| 457 | |
| 458 // Disallow uppercase headers. | |
| 459 if (ContainsUpperAscii(it->first)) { | |
| 460 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 461 "Upper case characters in header: " + it->first); | |
| 462 return ERR_SPDY_PROTOCOL_ERROR; | |
| 463 } | |
| 464 | |
| 465 (*response_)[it->first] = it->second; | |
| 466 } | |
| 467 | |
| 468 if ((*response_).find("transfer-encoding") != (*response_).end()) { | |
| 469 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 470 "Received transfer-encoding header"); | |
| 471 return ERR_SPDY_PROTOCOL_ERROR; | |
| 472 } | |
| 473 | |
| 474 int rv = OK; | |
| 475 if (delegate_) { | |
| 476 // May delete this object. | |
| 477 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv); | |
| 478 // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more | |
| 479 // headers before the response header block is complete. | |
| 480 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) | |
| 481 rv = OK; | |
| 482 } | |
| 483 return rv; | |
| 484 } | 438 } |
| 485 | 439 |
| 486 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { | 440 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { |
| 487 DCHECK(session_->IsStreamActive(stream_id_)); | 441 DCHECK(session_->IsStreamActive(stream_id_)); |
| 488 // If we don't have a response, then the SYN_REPLY did not come through. | 442 // If we don't have a response, then the SYN_REPLY did not come through. |
| 489 // We cannot pass data up to the caller unless the reply headers have been | 443 // We cannot pass data up to the caller unless the reply headers have been |
| 490 // received. | 444 // received. |
| 491 if (!response_received()) { | 445 if (!response_headers_) { |
| 492 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response."); | 446 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response."); |
| 493 session_->CloseActiveStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); | 447 session_->CloseActiveStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); |
| 494 return; | 448 return; |
| 495 } | 449 } |
| 496 | 450 |
| 497 if (!delegate_ || continue_buffering_data_) { | 451 if (!delegate_ || continue_buffering_data_) { |
| 452 DCHECK_EQ(type_, SPDY_PUSH_STREAM); | |
| 498 // It should be valid for this to happen in the server push case. | 453 // It should be valid for this to happen in the server push case. |
| 499 // We'll return received data when delegate gets attached to the stream. | 454 // We'll return received data when delegate gets attached to the stream. |
| 500 if (buffer) { | 455 if (buffer) { |
| 501 pending_buffers_.push_back(buffer.release()); | 456 pending_buffers_.push_back(buffer.release()); |
| 502 } else { | 457 } else { |
| 503 pending_buffers_.push_back(NULL); | 458 pending_buffers_.push_back(NULL); |
| 504 metrics_.StopStream(); | 459 metrics_.StopStream(); |
| 505 // Note: we leave the stream open in the session until the stream | 460 // Note: we leave the stream open in the session until the stream |
| 506 // is claimed. | 461 // is claimed. |
| 507 } | 462 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 | 539 |
| 585 void SpdyStream::Close() { | 540 void SpdyStream::Close() { |
| 586 CHECK(!in_do_loop_); | 541 CHECK(!in_do_loop_); |
| 587 if (stream_id_ != 0) { | 542 if (stream_id_ != 0) { |
| 588 session_->CloseActiveStream(stream_id_, OK); | 543 session_->CloseActiveStream(stream_id_, OK); |
| 589 } else { | 544 } else { |
| 590 session_->CloseCreatedStream(GetWeakPtr(), OK); | 545 session_->CloseCreatedStream(GetWeakPtr(), OK); |
| 591 } | 546 } |
| 592 } | 547 } |
| 593 | 548 |
| 594 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> headers, | 549 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> request_headers, |
| 595 SpdySendStatus send_status) { | 550 SpdySendStatus send_status) { |
| 596 CHECK_NE(type_, SPDY_PUSH_STREAM); | 551 CHECK_NE(type_, SPDY_PUSH_STREAM); |
| 597 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); | 552 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); |
| 598 CHECK(!request_); | 553 CHECK(!request_headers_); |
| 599 CHECK(!pending_send_data_.get()); | 554 CHECK(!pending_send_data_.get()); |
| 600 CHECK_EQ(io_state_, STATE_NONE); | 555 CHECK_EQ(io_state_, STATE_NONE); |
| 601 request_ = headers.Pass(); | 556 request_headers_ = request_headers.Pass(); |
| 602 send_status_ = send_status; | 557 send_status_ = send_status; |
| 603 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; | 558 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; |
| 604 return DoLoop(OK); | 559 return DoLoop(OK); |
| 605 } | 560 } |
| 606 | 561 |
| 607 void SpdyStream::SendData(IOBuffer* data, | 562 void SpdyStream::SendData(IOBuffer* data, |
| 608 int length, | 563 int length, |
| 609 SpdySendStatus send_status) { | 564 SpdySendStatus send_status) { |
| 610 CHECK_NE(type_, SPDY_PUSH_STREAM); | 565 CHECK_NE(type_, SPDY_PUSH_STREAM); |
| 611 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); | 566 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 639 QueueNextDataFrame(); | 594 QueueNextDataFrame(); |
| 640 } | 595 } |
| 641 } | 596 } |
| 642 | 597 |
| 643 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() { | 598 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() { |
| 644 return weak_ptr_factory_.GetWeakPtr(); | 599 return weak_ptr_factory_.GetWeakPtr(); |
| 645 } | 600 } |
| 646 | 601 |
| 647 bool SpdyStream::HasUrl() const { | 602 bool SpdyStream::HasUrl() const { |
| 648 if (type_ == SPDY_PUSH_STREAM) | 603 if (type_ == SPDY_PUSH_STREAM) |
| 649 return response_received(); | 604 return response_headers_ != NULL; |
| 650 return request_ != NULL; | 605 return request_headers_ != NULL; |
| 651 } | 606 } |
| 652 | 607 |
| 653 GURL SpdyStream::GetUrl() const { | 608 GURL SpdyStream::GetUrl() const { |
| 654 DCHECK(HasUrl()); | 609 DCHECK(HasUrl()); |
| 655 | 610 |
| 656 const SpdyHeaderBlock& headers = | 611 const SpdyHeaderBlock& headers = |
| 657 (type_ == SPDY_PUSH_STREAM) ? *response_ : *request_; | 612 (type_ == SPDY_PUSH_STREAM) ? *response_headers_ : *request_headers_; |
| 658 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(), | 613 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(), |
| 659 type_ == SPDY_PUSH_STREAM); | 614 type_ == SPDY_PUSH_STREAM); |
| 660 } | 615 } |
| 661 | 616 |
| 662 void SpdyStream::OnGetDomainBoundCertComplete(int result) { | 617 void SpdyStream::OnGetDomainBoundCertComplete(int result) { |
| 663 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); | 618 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); |
| 664 DoLoop(result); | 619 DoLoop(result); |
| 665 } | 620 } |
| 666 | 621 |
| 667 int SpdyStream::DoLoop(int result) { | 622 int SpdyStream::DoLoop(int result) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE && | 674 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE && |
| 720 io_state_ != STATE_OPEN); | 675 io_state_ != STATE_OPEN); |
| 721 | 676 |
| 722 CHECK(in_do_loop_); | 677 CHECK(in_do_loop_); |
| 723 in_do_loop_ = false; | 678 in_do_loop_ = false; |
| 724 | 679 |
| 725 return result; | 680 return result; |
| 726 } | 681 } |
| 727 | 682 |
| 728 int SpdyStream::DoGetDomainBoundCert() { | 683 int SpdyStream::DoGetDomainBoundCert() { |
| 729 CHECK(request_); | 684 CHECK(request_headers_); |
| 730 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 685 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
| 731 GURL url = GetUrl(); | 686 GURL url = GetUrl(); |
| 732 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) { | 687 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) { |
| 733 // Proceed directly to sending the request headers | 688 // Proceed directly to sending the request headers |
| 734 io_state_ = STATE_SEND_REQUEST_HEADERS; | 689 io_state_ = STATE_SEND_REQUEST_HEADERS; |
| 735 return OK; | 690 return OK; |
| 736 } | 691 } |
| 737 | 692 |
| 738 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl()); | 693 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl()); |
| 739 if (slot_ != SpdyCredentialState::kNoEntry) { | 694 if (slot_ != SpdyCredentialState::kNoEntry) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 759 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 714 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
| 760 if (result != OK) | 715 if (result != OK) |
| 761 return result; | 716 return result; |
| 762 | 717 |
| 763 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; | 718 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; |
| 764 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); | 719 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); |
| 765 return OK; | 720 return OK; |
| 766 } | 721 } |
| 767 | 722 |
| 768 int SpdyStream::DoSendDomainBoundCert() { | 723 int SpdyStream::DoSendDomainBoundCert() { |
| 769 CHECK(request_); | 724 CHECK(request_headers_); |
| 770 DCHECK_NE(type_, SPDY_PUSH_STREAM); | 725 DCHECK_NE(type_, SPDY_PUSH_STREAM); |
| 771 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; | 726 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; |
| 772 | 727 |
| 773 std::string origin = GetUrl().GetOrigin().spec(); | 728 std::string origin = GetUrl().GetOrigin().spec(); |
| 774 DCHECK(origin[origin.length() - 1] == '/'); | 729 DCHECK(origin[origin.length() - 1] == '/'); |
| 775 origin.erase(origin.length() - 1); // Trim trailing slash. | 730 origin.erase(origin.length() - 1); // Trim trailing slash. |
| 776 scoped_ptr<SpdyFrame> frame; | 731 scoped_ptr<SpdyFrame> frame; |
| 777 int rv = session_->CreateCredentialFrame( | 732 int rv = session_->CreateCredentialFrame( |
| 778 origin, domain_bound_cert_type_, domain_bound_private_key_, | 733 origin, domain_bound_cert_type_, domain_bound_private_key_, |
| 779 domain_bound_cert_, priority_, &frame); | 734 domain_bound_cert_, priority_, &frame); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 975 base::Bind(&SpdyStream::OnWriteBufferConsumed, | 930 base::Bind(&SpdyStream::OnWriteBufferConsumed, |
| 976 GetWeakPtr(), payload_size)); | 931 GetWeakPtr(), payload_size)); |
| 977 } | 932 } |
| 978 | 933 |
| 979 session_->EnqueueStreamWrite( | 934 session_->EnqueueStreamWrite( |
| 980 GetWeakPtr(), DATA, | 935 GetWeakPtr(), DATA, |
| 981 scoped_ptr<SpdyBufferProducer>( | 936 scoped_ptr<SpdyBufferProducer>( |
| 982 new SimpleBufferProducer(data_buffer.Pass()))); | 937 new SimpleBufferProducer(data_buffer.Pass()))); |
| 983 } | 938 } |
| 984 | 939 |
| 940 int SpdyStream::MergeWithResponseHeaders( | |
| 941 const SpdyHeaderBlock& new_response_headers) { | |
| 942 DCHECK(response_headers_); | |
| 943 | |
| 944 if (new_response_headers.find("transfer-encoding") != | |
| 945 new_response_headers.end()) { | |
| 946 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 947 "Received transfer-encoding header"); | |
| 948 return ERR_SPDY_PROTOCOL_ERROR; | |
| 949 } | |
| 950 | |
| 951 for (SpdyHeaderBlock::const_iterator it = new_response_headers.begin(); | |
| 952 it != new_response_headers.end(); ++it) { | |
| 953 // Disallow uppercase headers. | |
| 954 if (ContainsUppercaseAscii(it->first)) { | |
| 955 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR, | |
| 956 "Upper case characters in header: " + it->first); | |
| 957 return ERR_SPDY_PROTOCOL_ERROR; | |
| 958 } | |
| 959 | |
| 960 SpdyHeaderBlock::iterator it2 = response_headers_->lower_bound(it->first); | |
| 961 // Disallow duplicate headers. This is just to be conservative. | |
| 962 if (it2 != response_headers_->end() && it2->first == it->first) { | |
| 963 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "HEADERS duplicate header"); | |
| 964 response_status_ = ERR_SPDY_PROTOCOL_ERROR; | |
| 965 return ERR_SPDY_PROTOCOL_ERROR; | |
| 966 } | |
| 967 | |
| 968 response_headers_->insert(it2, *it); | |
| 969 } | |
| 970 | |
| 971 // If delegate_ is not yet attached, we'll call | |
| 972 // OnResponseHeadersUpdated() after the delegate gets attached to | |
| 973 // the stream. | |
| 974 if (delegate_) { | |
| 975 // The call to OnResponseHeadersUpdated() may delete this object | |
| 976 // if OK is returned, so store |type_| in a local variable. | |
| 977 SpdyStreamType type = type_; | |
| 978 int rv = delegate_->OnResponseHeadersUpdated(*response_headers_); | |
| 979 DCHECK(rv == OK || rv == ERR_INCOMPLETE_SPDY_HEADERS); | |
|
Ryan Hamilton
2013/06/19 18:58:36
boy, this sure screams "this method should return
akalin
2013/06/21 21:13:25
Done.
| |
| 980 // Incomplete headers are OK only for push streams. | |
| 981 if (type == SPDY_PUSH_STREAM && rv == ERR_INCOMPLETE_SPDY_HEADERS) | |
| 982 rv = OK; | |
| 983 if (rv != OK) | |
| 984 return rv; | |
| 985 } | |
| 986 | |
| 987 return OK; | |
| 988 } | |
| 989 | |
| 985 } // namespace net | 990 } // namespace net |
| OLD | NEW |