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

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

Issue 2526003002: Disallow multiple HEADERS frames on pushed streams. (Closed)
Patch Set: Rename enum, enum entry, and member. Created 4 years 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
« no previous file with comments | « net/spdy/spdy_stream.h ('k') | net/spdy/spdy_stream_test_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 dict->SetInteger("window_size", window_size); 52 dict->SetInteger("window_size", window_size);
53 return std::move(dict); 53 return std::move(dict);
54 } 54 }
55 55
56 bool ContainsUppercaseAscii(base::StringPiece str) { 56 bool ContainsUppercaseAscii(base::StringPiece str) {
57 return std::any_of(str.begin(), str.end(), base::IsAsciiUpper<char>); 57 return std::any_of(str.begin(), str.end(), base::IsAsciiUpper<char>);
58 } 58 }
59 59
60 } // namespace 60 } // namespace
61 61
62 void SpdyStream::Delegate::OnTrailers(const SpdyHeaderBlock& trailers) {}
63
64 // A wrapper around a stream that calls into ProduceHeadersFrame(). 62 // A wrapper around a stream that calls into ProduceHeadersFrame().
65 class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer { 63 class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer {
66 public: 64 public:
67 HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream) 65 HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream)
68 : stream_(stream) { 66 : stream_(stream) {
69 DCHECK(stream_.get()); 67 DCHECK(stream_.get());
70 } 68 }
71 69
72 ~HeadersBufferProducer() override {} 70 ~HeadersBufferProducer() override {}
73 71
(...skipping 25 matching lines...) Expand all
99 send_stalled_by_flow_control_(false), 97 send_stalled_by_flow_control_(false),
100 send_window_size_(initial_send_window_size), 98 send_window_size_(initial_send_window_size),
101 max_recv_window_size_(max_recv_window_size), 99 max_recv_window_size_(max_recv_window_size),
102 recv_window_size_(max_recv_window_size), 100 recv_window_size_(max_recv_window_size),
103 unacked_recv_window_bytes_(0), 101 unacked_recv_window_bytes_(0),
104 session_(session), 102 session_(session),
105 delegate_(NULL), 103 delegate_(NULL),
106 request_headers_valid_(false), 104 request_headers_valid_(false),
107 pending_send_status_(MORE_DATA_TO_SEND), 105 pending_send_status_(MORE_DATA_TO_SEND),
108 request_time_(base::Time::Now()), 106 request_time_(base::Time::Now()),
109 response_headers_status_(RESPONSE_HEADERS_ARE_INCOMPLETE), 107 response_state_(READY_FOR_HEADERS),
110 io_state_(STATE_IDLE), 108 io_state_(STATE_IDLE),
111 response_status_(OK), 109 response_status_(OK),
112 net_log_(net_log), 110 net_log_(net_log),
113 raw_received_bytes_(0), 111 raw_received_bytes_(0),
114 raw_sent_bytes_(0), 112 raw_sent_bytes_(0),
115 send_bytes_(0), 113 send_bytes_(0),
116 recv_bytes_(0), 114 recv_bytes_(0),
117 write_handler_guard_(false), 115 write_handler_guard_(false),
118 weak_ptr_factory_(this) { 116 weak_ptr_factory_(this) {
119 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || 117 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
(...skipping 30 matching lines...) Expand all
150 CHECK_EQ(stream_id_ % 2, 0u); 148 CHECK_EQ(stream_id_ % 2, 0u);
151 149
152 CHECK_EQ(io_state_, STATE_HALF_CLOSED_LOCAL_UNCLAIMED); 150 CHECK_EQ(io_state_, STATE_HALF_CLOSED_LOCAL_UNCLAIMED);
153 io_state_ = STATE_HALF_CLOSED_LOCAL; 151 io_state_ = STATE_HALF_CLOSED_LOCAL;
154 152
155 // The delegate methods called below may delete |this|, so use 153 // The delegate methods called below may delete |this|, so use
156 // |weak_this| to detect that. 154 // |weak_this| to detect that.
157 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); 155 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
158 156
159 CHECK(delegate_); 157 CHECK(delegate_);
160 SpdyResponseHeadersStatus status = 158 delegate_->OnHeadersReceived(response_headers_);
161 delegate_->OnResponseHeadersUpdated(response_headers_);
162 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) {
163 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not
164 // have been closed. Since we don't have complete headers, assume
165 // we're waiting for another HEADERS frame, and we had better not
166 // have any pending data frames.
167 CHECK(weak_this);
168 if (!pending_recv_data_.empty()) {
169 LogStreamError(ERR_SPDY_PROTOCOL_ERROR,
170 "Data received with incomplete headers.");
171 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR);
172 }
173 return;
174 }
175 159
176 // OnResponseHeadersUpdated() may have closed |this|. 160 // OnHeadersReceived() may have closed |this|.
177 if (!weak_this) 161 if (!weak_this)
178 return; 162 return;
179 163
180 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
181
182 while (!pending_recv_data_.empty()) { 164 while (!pending_recv_data_.empty()) {
183 // Take ownership of the first element of |pending_recv_data_|. 165 // Take ownership of the first element of |pending_recv_data_|.
184 std::unique_ptr<SpdyBuffer> buffer = std::move(pending_recv_data_.at(0)); 166 std::unique_ptr<SpdyBuffer> buffer = std::move(pending_recv_data_.at(0));
185 pending_recv_data_.erase(pending_recv_data_.begin()); 167 pending_recv_data_.erase(pending_recv_data_.begin());
186 168
187 bool eof = (buffer == NULL); 169 bool eof = (buffer == NULL);
188 170
189 CHECK(delegate_); 171 CHECK(delegate_);
190 delegate_->OnDataReceived(std::move(buffer)); 172 delegate_->OnDataReceived(std::move(buffer));
191 173
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 } 364 }
383 365
384 base::Time SpdyStream::GetRequestTime() const { 366 base::Time SpdyStream::GetRequestTime() const {
385 return request_time_; 367 return request_time_;
386 } 368 }
387 369
388 void SpdyStream::SetRequestTime(base::Time t) { 370 void SpdyStream::SetRequestTime(base::Time t) {
389 request_time_ = t; 371 request_time_ = t;
390 } 372 }
391 373
392 int SpdyStream::OnInitialResponseHeadersReceived( 374 void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers,
393 const SpdyHeaderBlock& initial_response_headers, 375 base::Time response_time,
394 base::Time response_time, 376 base::TimeTicks recv_first_byte_time) {
395 base::TimeTicks recv_first_byte_time) { 377 switch (response_state_) {
396 // SpdySession guarantees that this is called at most once. 378 case READY_FOR_HEADERS:
397 CHECK(response_headers_.empty()); 379 // No header block has been received yet.
380 DCHECK(response_headers_.empty());
398 381
399 // Check to make sure that we don't receive the response headers 382 if (response_headers.find(":status") == response_headers.end()) {
400 // before we're ready for it. 383 const std::string error("Response headers do not include :status.");
401 switch (type_) { 384 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
402 case SPDY_BIDIRECTIONAL_STREAM: 385 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
403 // For a bidirectional stream, we're ready for the response 386 return;
404 // headers once we've finished sending the request headers.
405 if (io_state_ == STATE_IDLE) {
406 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
407 "Response received before request sent");
408 return ERR_SPDY_PROTOCOL_ERROR;
409 } 387 }
388
389 response_state_ = READY_FOR_DATA_OR_TRAILERS;
390
391 switch (type_) {
392 case SPDY_BIDIRECTIONAL_STREAM:
393 case SPDY_REQUEST_RESPONSE_STREAM:
394 // A bidirectional stream or a request/response stream is ready for
395 // the response headers only after request headers are sent.
396 if (io_state_ == STATE_IDLE) {
397 const std::string error("Response received before request sent.");
398 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
399 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
400 return;
401 }
402 break;
403
404 case SPDY_PUSH_STREAM:
405 // Push streams transition to a locally half-closed state upon
406 // headers. We must continue to buffer data while waiting for a call
407 // to SetDelegate() (which may not ever happen).
408 DCHECK_EQ(io_state_, STATE_RESERVED_REMOTE);
409 if (!delegate_) {
410 io_state_ = STATE_HALF_CLOSED_LOCAL_UNCLAIMED;
411 } else {
412 io_state_ = STATE_HALF_CLOSED_LOCAL;
413 }
414 break;
415 }
416
417 DCHECK_NE(io_state_, STATE_IDLE);
418
419 response_time_ = response_time;
420 recv_first_byte_time_ = recv_first_byte_time;
421 SaveResponseHeaders(response_headers);
422
410 break; 423 break;
411 424
412 case SPDY_REQUEST_RESPONSE_STREAM: 425 case READY_FOR_DATA_OR_TRAILERS:
413 // For a request/response stream, we're ready for the response 426 // Second header block is trailers.
414 // headers once we've finished sending the request headers. 427 if (type_ == SPDY_PUSH_STREAM) {
415 if (io_state_ == STATE_IDLE) { 428 const std::string error("Trailers not supported for push stream.");
416 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, 429 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
417 "Response received before request sent"); 430 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
418 return ERR_SPDY_PROTOCOL_ERROR; 431 return;
419 } 432 }
433
434 response_state_ = TRAILERS_RECEIVED;
435 delegate_->OnTrailers(response_headers);
420 break; 436 break;
421 437
422 case SPDY_PUSH_STREAM: 438 case TRAILERS_RECEIVED:
423 // Push streams transition to a locally half-closed state upon headers. 439 // No further header blocks are allowed after trailers.
424 // We must continue to buffer data while waiting for a call to 440 const std::string error("Header block received after trailers.");
425 // SetDelegate() (which may not ever happen). 441 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
426 CHECK_EQ(io_state_, STATE_RESERVED_REMOTE); 442 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
427 if (!delegate_) { 443 return;
428 io_state_ = STATE_HALF_CLOSED_LOCAL_UNCLAIMED;
429 } else {
430 io_state_ = STATE_HALF_CLOSED_LOCAL;
431 }
432 break;
433 } 444 }
434
435 DCHECK_NE(io_state_, STATE_IDLE);
436
437 response_time_ = response_time;
438 recv_first_byte_time_ = recv_first_byte_time;
439 return MergeWithResponseHeaders(initial_response_headers);
440 }
441
442 int SpdyStream::OnAdditionalResponseHeadersReceived(
443 const SpdyHeaderBlock& additional_response_headers) {
444 if (type_ == SPDY_REQUEST_RESPONSE_STREAM) {
445 if (response_headers_status_ != RESPONSE_HEADERS_ARE_COMPLETE) {
446 session_->ResetStream(
447 stream_id_, RST_STREAM_PROTOCOL_ERROR,
448 "Additional headers received for request/response stream");
449 return ERR_SPDY_PROTOCOL_ERROR;
450 }
451 response_headers_status_ = TRAILERS_RECEIVED;
452 delegate_->OnTrailers(additional_response_headers);
453 return OK;
454 }
455 if (type_ == SPDY_BIDIRECTIONAL_STREAM) {
456 DCHECK_EQ(RESPONSE_HEADERS_ARE_COMPLETE, response_headers_status_);
457 response_headers_status_ = TRAILERS_RECEIVED;
458 delegate_->OnTrailers(additional_response_headers);
459 return OK;
460 }
461 if (type_ == SPDY_PUSH_STREAM &&
462 response_headers_status_ == RESPONSE_HEADERS_ARE_COMPLETE) {
463 session_->ResetStream(
464 stream_id_, RST_STREAM_PROTOCOL_ERROR,
465 "Additional headers received for push stream");
466 return ERR_SPDY_PROTOCOL_ERROR;
467 }
468 return MergeWithResponseHeaders(additional_response_headers);
469 } 445 }
470 446
471 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) { 447 void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) {
472 CHECK(!request_headers_valid_); 448 CHECK(!request_headers_valid_);
473 CHECK_EQ(io_state_, STATE_IDLE); 449 CHECK_EQ(io_state_, STATE_IDLE);
474 CHECK_EQ(type_, SPDY_PUSH_STREAM); 450 CHECK_EQ(type_, SPDY_PUSH_STREAM);
475 DCHECK(!delegate_); 451 DCHECK(!delegate_);
476 452
477 io_state_ = STATE_RESERVED_REMOTE; 453 io_state_ = STATE_RESERVED_REMOTE;
478 request_headers_ = std::move(headers); 454 request_headers_ = std::move(headers);
479 request_headers_valid_ = true; 455 request_headers_valid_ = true;
480 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_); 456 url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_);
481 } 457 }
482 458
483 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { 459 void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
484 DCHECK(session_->IsStreamActive(stream_id_)); 460 DCHECK(session_->IsStreamActive(stream_id_));
485 461
462 if (response_state_ == READY_FOR_HEADERS) {
463 const std::string error("DATA received before headers.");
464 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
465 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
466 return;
467 }
468
469 if (response_state_ == TRAILERS_RECEIVED && buffer) {
470 const std::string error("DATA received after trailers.");
471 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
472 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, error);
473 return;
474 }
475
486 // Track our bandwidth. 476 // Track our bandwidth.
487 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0; 477 recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0;
488 recv_last_byte_time_ = base::TimeTicks::Now(); 478 recv_last_byte_time_ = base::TimeTicks::Now();
489 479
490 // If we're still buffering data for a push stream, we will do the 480 // If we're still buffering data for a push stream, we will do the check for
491 // check for data received with incomplete headers in 481 // data received with incomplete headers in PushedStreamReplay().
492 // PushedStreamReplayData().
493 if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) { 482 if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) {
494 DCHECK_EQ(type_, SPDY_PUSH_STREAM); 483 DCHECK_EQ(type_, SPDY_PUSH_STREAM);
495 // It should be valid for this to happen in the server push case. 484 // It should be valid for this to happen in the server push case.
496 // We'll return received data when delegate gets attached to the stream. 485 // We'll return received data when delegate gets attached to the stream.
497 if (buffer) { 486 if (buffer) {
498 pending_recv_data_.push_back(std::move(buffer)); 487 pending_recv_data_.push_back(std::move(buffer));
499 } else { 488 } else {
500 pending_recv_data_.push_back(NULL); 489 pending_recv_data_.push_back(NULL);
501 // Note: we leave the stream open in the session until the stream 490 // Note: we leave the stream open in the session until the stream
502 // is claimed. 491 // is claimed.
503 } 492 }
504 return; 493 return;
505 } 494 }
506 495
507 if (response_headers_status_ == TRAILERS_RECEIVED && buffer) {
508 // TRAILERS_RECEIVED is only used in SPDY_REQUEST_RESPONSE_STREAM and
509 // SPDY_BIDIRECTIONAL_STREAM.
510 DCHECK(type_ == SPDY_REQUEST_RESPONSE_STREAM ||
511 type_ == SPDY_BIDIRECTIONAL_STREAM);
512 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
513 "Data received after trailers");
514 return;
515 }
516
517 // If we have response headers but the delegate has indicated that
518 // it's still incomplete, then that's a protocol error.
519 if (response_headers_status_ == RESPONSE_HEADERS_ARE_INCOMPLETE) {
520 LogStreamError(ERR_SPDY_PROTOCOL_ERROR,
521 "Data received with incomplete headers.");
522 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR);
523 return;
524 }
525
526 CHECK(!IsClosed()); 496 CHECK(!IsClosed());
527 497
528 if (!buffer) { 498 if (!buffer) {
529 if (io_state_ == STATE_OPEN) { 499 if (io_state_ == STATE_OPEN) {
530 io_state_ = STATE_HALF_CLOSED_REMOTE; 500 io_state_ = STATE_HALF_CLOSED_REMOTE;
531 } else if (io_state_ == STATE_HALF_CLOSED_LOCAL) { 501 } else if (io_state_ == STATE_HALF_CLOSED_LOCAL) {
532 io_state_ = STATE_CLOSED; 502 io_state_ = STATE_CLOSED;
533 // Deletes |this|. 503 // Deletes |this|.
534 session_->CloseActiveStream(stream_id_, OK); 504 session_->CloseActiveStream(stream_id_, OK);
535 } else { 505 } else {
(...skipping 28 matching lines...) Expand all
564 return; 534 return;
565 IncreaseRecvWindowSize(static_cast<int32_t>(len)); 535 IncreaseRecvWindowSize(static_cast<int32_t>(len));
566 } 536 }
567 537
568 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, 538 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type,
569 size_t frame_size) { 539 size_t frame_size) {
570 DCHECK_NE(type_, SPDY_PUSH_STREAM); 540 DCHECK_NE(type_, SPDY_PUSH_STREAM);
571 CHECK(frame_type == HEADERS || frame_type == DATA) << frame_type; 541 CHECK(frame_type == HEADERS || frame_type == DATA) << frame_type;
572 542
573 int result = 543 int result =
574 (frame_type == HEADERS) ? OnRequestHeadersSent() : OnDataSent(frame_size); 544 (frame_type == HEADERS) ? OnHeadersSent() : OnDataSent(frame_size);
575 if (result == ERR_IO_PENDING) { 545 if (result == ERR_IO_PENDING) {
576 // The write operation hasn't completed yet. 546 // The write operation hasn't completed yet.
577 return; 547 return;
578 } 548 }
579 549
580 if (pending_send_status_ == NO_MORE_DATA_TO_SEND) { 550 if (pending_send_status_ == NO_MORE_DATA_TO_SEND) {
581 if (io_state_ == STATE_OPEN) { 551 if (io_state_ == STATE_OPEN) {
582 io_state_ = STATE_HALF_CLOSED_LOCAL; 552 io_state_ = STATE_HALF_CLOSED_LOCAL;
583 } else if (io_state_ == STATE_HALF_CLOSED_REMOTE) { 553 } else if (io_state_ == STATE_HALF_CLOSED_REMOTE) {
584 io_state_ = STATE_CLOSED; 554 io_state_ = STATE_CLOSED;
585 } else { 555 } else {
586 NOTREACHED() << io_state_; 556 NOTREACHED() << io_state_;
587 } 557 }
588 } 558 }
589 // Notify delegate of write completion. Must not destroy |this|. 559 // Notify delegate of write completion. Must not destroy |this|.
590 CHECK(delegate_); 560 CHECK(delegate_);
591 { 561 {
592 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); 562 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
593 write_handler_guard_ = true; 563 write_handler_guard_ = true;
594 if (frame_type == HEADERS) { 564 if (frame_type == HEADERS) {
595 delegate_->OnRequestHeadersSent(); 565 delegate_->OnHeadersSent();
596 } else { 566 } else {
597 delegate_->OnDataSent(); 567 delegate_->OnDataSent();
598 } 568 }
599 CHECK(weak_this); 569 CHECK(weak_this);
600 write_handler_guard_ = false; 570 write_handler_guard_ = false;
601 } 571 }
602 572
603 if (io_state_ == STATE_CLOSED) { 573 if (io_state_ == STATE_CLOSED) {
604 // Deletes |this|. 574 // Deletes |this|.
605 session_->CloseActiveStream(stream_id_, OK); 575 session_->CloseActiveStream(stream_id_, OK);
606 } 576 }
607 } 577 }
608 578
609 int SpdyStream::OnRequestHeadersSent() { 579 int SpdyStream::OnHeadersSent() {
610 CHECK_EQ(io_state_, STATE_IDLE); 580 CHECK_EQ(io_state_, STATE_IDLE);
611 CHECK_NE(stream_id_, 0u); 581 CHECK_NE(stream_id_, 0u);
612 582
613 io_state_ = STATE_OPEN; 583 io_state_ = STATE_OPEN;
614 return OK; 584 return OK;
615 } 585 }
616 586
617 int SpdyStream::OnDataSent(size_t frame_size) { 587 int SpdyStream::OnDataSent(size_t frame_size) {
618 CHECK(io_state_ == STATE_OPEN || 588 CHECK(io_state_ == STATE_OPEN ||
619 io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_; 589 io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_;
(...skipping 21 matching lines...) Expand all
641 net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, 611 net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR,
642 base::Bind(&NetLogSpdyStreamErrorCallback, stream_id_, 612 base::Bind(&NetLogSpdyStreamErrorCallback, stream_id_,
643 status, &description)); 613 status, &description));
644 } 614 }
645 615
646 void SpdyStream::OnClose(int status) { 616 void SpdyStream::OnClose(int status) {
647 // In most cases, the stream should already be CLOSED. The exception is when a 617 // In most cases, the stream should already be CLOSED. The exception is when a
648 // SpdySession is shutting down while the stream is in an intermediate state. 618 // SpdySession is shutting down while the stream is in an intermediate state.
649 io_state_ = STATE_CLOSED; 619 io_state_ = STATE_CLOSED;
650 if (status == ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED) { 620 if (status == ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED) {
651 if (response_headers_status_ == RESPONSE_HEADERS_ARE_INCOMPLETE) { 621 if (response_state_ == READY_FOR_HEADERS) {
652 status = ERR_SPDY_PROTOCOL_ERROR; 622 status = ERR_SPDY_PROTOCOL_ERROR;
653 } else { 623 } else {
654 status = OK; 624 status = OK;
655 } 625 }
656 } 626 }
657 response_status_ = status; 627 response_status_ = status;
658 Delegate* delegate = delegate_; 628 Delegate* delegate = delegate_;
659 delegate_ = NULL; 629 delegate_ = NULL;
660 if (delegate) 630 if (delegate)
661 delegate->OnClose(status); 631 delegate->OnClose(status);
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 data_buffer->AddConsumeCallback(base::Bind( 832 data_buffer->AddConsumeCallback(base::Bind(
863 &SpdyStream::OnWriteBufferConsumed, GetWeakPtr(), payload_size)); 833 &SpdyStream::OnWriteBufferConsumed, GetWeakPtr(), payload_size));
864 } 834 }
865 835
866 session_->EnqueueStreamWrite( 836 session_->EnqueueStreamWrite(
867 GetWeakPtr(), DATA, 837 GetWeakPtr(), DATA,
868 std::unique_ptr<SpdyBufferProducer>( 838 std::unique_ptr<SpdyBufferProducer>(
869 new SimpleBufferProducer(std::move(data_buffer)))); 839 new SimpleBufferProducer(std::move(data_buffer))));
870 } 840 }
871 841
872 int SpdyStream::MergeWithResponseHeaders( 842 void SpdyStream::SaveResponseHeaders(const SpdyHeaderBlock& response_headers) {
873 const SpdyHeaderBlock& new_response_headers) { 843 DCHECK(response_headers_.empty());
874 if (new_response_headers.find("transfer-encoding") != 844 if (response_headers.find("transfer-encoding") != response_headers.end()) {
875 new_response_headers.end()) {
876 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR, 845 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
877 "Received transfer-encoding header"); 846 "Received transfer-encoding header");
878 return ERR_SPDY_PROTOCOL_ERROR; 847 return;
879 } 848 }
880 849
881 for (SpdyHeaderBlock::const_iterator it = new_response_headers.begin(); 850 for (SpdyHeaderBlock::const_iterator it = response_headers.begin();
882 it != new_response_headers.end(); ++it) { 851 it != response_headers.end(); ++it) {
883 // Disallow uppercase headers. 852 // Disallow uppercase headers.
884 if (ContainsUppercaseAscii(it->first)) { 853 if (ContainsUppercaseAscii(it->first)) {
885 session_->ResetStream( 854 session_->ResetStream(
886 stream_id_, RST_STREAM_PROTOCOL_ERROR, 855 stream_id_, RST_STREAM_PROTOCOL_ERROR,
887 "Upper case characters in header: " + it->first.as_string()); 856 "Upper case characters in header: " + it->first.as_string());
888 return ERR_SPDY_PROTOCOL_ERROR; 857 return;
889 }
890
891 SpdyHeaderBlock::iterator it2 = response_headers_.find(it->first);
892 // Disallow duplicate headers. This is just to be conservative.
893 if (it2 != response_headers_.end()) {
894 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
895 "Duplicate header: " + it->first.as_string());
896 return ERR_SPDY_PROTOCOL_ERROR;
897 } 858 }
898 859
899 response_headers_.insert(*it); 860 response_headers_.insert(*it);
900 } 861 }
901 862
902 // If delegate_ is not yet attached, we'll call 863 // If delegate is not yet attached, OnHeadersReceived() will be called after
903 // OnResponseHeadersUpdated() after the delegate gets attached to 864 // the delegate gets attached to the stream.
904 // the stream. 865 if (delegate_)
905 if (delegate_) { 866 delegate_->OnHeadersReceived(response_headers_);
906 // The call to OnResponseHeadersUpdated() below may delete |this|,
907 // so use |weak_this| to detect that.
908 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
909
910 SpdyResponseHeadersStatus status =
911 delegate_->OnResponseHeadersUpdated(response_headers_);
912 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) {
913 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not
914 // have been closed.
915 CHECK(weak_this);
916 // Incomplete headers are OK only for push streams.
917 if (type_ != SPDY_PUSH_STREAM) {
918 session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
919 "Incomplete headers");
920 return ERR_INCOMPLETE_SPDY_HEADERS;
921 }
922 } else if (weak_this) {
923 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
924 }
925 }
926
927 return OK;
928 } 867 }
929 868
930 #define STATE_CASE(s) \ 869 #define STATE_CASE(s) \
931 case s: \ 870 case s: \
932 description = base::StringPrintf("%s (0x%08X)", #s, s); \ 871 description = base::StringPrintf("%s (0x%08X)", #s, s); \
933 break 872 break
934 873
935 std::string SpdyStream::DescribeState(State state) { 874 std::string SpdyStream::DescribeState(State state) {
936 std::string description; 875 std::string description;
937 switch (state) { 876 switch (state) {
938 STATE_CASE(STATE_IDLE); 877 STATE_CASE(STATE_IDLE);
939 STATE_CASE(STATE_OPEN); 878 STATE_CASE(STATE_OPEN);
940 STATE_CASE(STATE_HALF_CLOSED_LOCAL_UNCLAIMED); 879 STATE_CASE(STATE_HALF_CLOSED_LOCAL_UNCLAIMED);
941 STATE_CASE(STATE_HALF_CLOSED_LOCAL); 880 STATE_CASE(STATE_HALF_CLOSED_LOCAL);
942 STATE_CASE(STATE_CLOSED); 881 STATE_CASE(STATE_CLOSED);
943 default: 882 default:
944 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, 883 description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
945 state); 884 state);
946 break; 885 break;
947 } 886 }
948 return description; 887 return description;
949 } 888 }
950 889
951 #undef STATE_CASE 890 #undef STATE_CASE
952 891
953 } // namespace net 892 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_stream.h ('k') | net/spdy/spdy_stream_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698