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 |