Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: net/spdy/spdy_stream.cc

Issue 17382012: [SPDY] Refactor SpdyStream's handling of response headers (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Forgot to rename a function Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698