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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 if (*i >= 'A' && *i <= 'Z') { | 43 if (*i >= 'A' && *i <= 'Z') { |
| 44 return true; | 44 return true; |
| 45 } | 45 } |
| 46 } | 46 } |
| 47 return false; | 47 return false; |
| 48 } | 48 } |
| 49 | 49 |
| 50 } // namespace | 50 } // namespace |
| 51 | 51 |
| 52 SpdyStream::SpdyStream(SpdySession* session, | 52 SpdyStream::SpdyStream(SpdySession* session, |
| 53 SpdyStreamId stream_id, | |
| 54 bool pushed, | 53 bool pushed, |
| 55 const BoundNetLog& net_log) | 54 const BoundNetLog& net_log) |
| 56 : continue_buffering_data_(true), | 55 : continue_buffering_data_(true), |
| 57 stream_id_(stream_id), | 56 stream_id_(0), |
| 58 priority_(HIGHEST), | 57 priority_(HIGHEST), |
| 59 slot_(0), | 58 slot_(0), |
| 60 stalled_by_flow_control_(false), | 59 stalled_by_flow_control_(false), |
| 61 send_window_size_(kSpdyStreamInitialWindowSize), | 60 send_window_size_(kSpdyStreamInitialWindowSize), |
| 62 recv_window_size_(kSpdyStreamInitialWindowSize), | 61 recv_window_size_(kSpdyStreamInitialWindowSize), |
| 63 unacked_recv_window_bytes_(0), | 62 unacked_recv_window_bytes_(0), |
| 64 pushed_(pushed), | 63 pushed_(pushed), |
| 65 response_received_(false), | 64 response_received_(false), |
| 66 session_(session), | 65 session_(session), |
| 67 delegate_(NULL), | 66 delegate_(NULL), |
| 68 request_time_(base::Time::Now()), | 67 request_time_(base::Time::Now()), |
| 69 response_(new SpdyHeaderBlock), | 68 response_(new SpdyHeaderBlock), |
| 70 io_state_(STATE_NONE), | 69 io_state_(STATE_NONE), |
| 71 response_status_(OK), | 70 response_status_(OK), |
| 72 cancelled_(false), | 71 cancelled_(false), |
| 73 has_upload_data_(false), | 72 has_upload_data_(false), |
| 74 net_log_(net_log), | 73 net_log_(net_log), |
| 75 send_bytes_(0), | 74 send_bytes_(0), |
| 76 recv_bytes_(0), | 75 recv_bytes_(0), |
| 77 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE) { | 76 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE) { |
| 78 } | 77 } |
| 79 | 78 |
| 79 class SpdyStream::SpdyStreamIOBufferProducer | |
| 80 : public SpdySession::SpdyIOBufferProducer { | |
| 81 public: | |
| 82 SpdyStreamIOBufferProducer(SpdyStream* stream) : stream_(stream) {} | |
| 83 | |
| 84 // SpdyFrameProducer | |
| 85 virtual RequestPriority GetPriority() const OVERRIDE { | |
| 86 return stream_->priority(); | |
| 87 } | |
| 88 | |
| 89 virtual SpdyIOBuffer* ProduceNextBuffer(SpdySession* session) OVERRIDE { | |
| 90 if (stream_->stream_id() == 0) | |
| 91 SpdySession::SpdyIOBufferProducer::ActivateStream(session, stream_); | |
| 92 SpdyFrame* frame = stream_->ProduceNextFrame(); | |
| 93 return frame == NULL ? NULL : | |
| 94 SpdySession::SpdyIOBufferProducer::CreateIOBuffer( | |
| 95 frame, GetPriority(), stream_); | |
| 96 } | |
| 97 | |
| 98 private: | |
| 99 scoped_refptr<SpdyStream> stream_; | |
| 100 | |
|
ramant (doing other things)
2012/06/26 23:30:25
overly nit: extra blank line.
Ryan Hamilton
2012/06/27 16:58:28
Done.
| |
| 101 }; | |
| 102 | |
| 103 void SpdyStream::SetHasWriteAvailable() { | |
| 104 session_->SetStreamHasWriteAvailable(this, | |
| 105 new SpdyStreamIOBufferProducer(this)); | |
| 106 } | |
| 107 | |
| 108 SpdyFrame* SpdyStream::ProduceNextFrame() { | |
| 109 if (io_state_ == STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE) { | |
| 110 CHECK(request_.get()); | |
| 111 CHECK_GT(stream_id_, 0u); | |
| 112 | |
| 113 std::string origin = GetUrl().GetOrigin().spec(); | |
| 114 origin.erase(origin.length() - 1); // trim trailing slash | |
| 115 SpdyCredentialControlFrame* frame = session_->CreateCredentialFrame( | |
|
ramant (doing other things)
2012/06/26 23:30:25
nit: should we DCHECK that "origin" ends with slas
Ryan Hamilton
2012/06/27 16:58:28
Done.
| |
| 116 origin, domain_bound_cert_type_, domain_bound_private_key_, | |
| 117 domain_bound_cert_, priority_); | |
| 118 return frame; | |
| 119 } else if (io_state_ == STATE_SEND_HEADERS_COMPLETE) { | |
| 120 CHECK(request_.get()); | |
| 121 CHECK_GT(stream_id_, 0u); | |
| 122 | |
| 123 SpdyControlFlags flags = | |
| 124 has_upload_data_ ? CONTROL_FLAG_NONE : CONTROL_FLAG_FIN; | |
| 125 SpdySynStreamControlFrame* frame = session_->CreateSynStream( | |
| 126 stream_id_, priority_, slot_, flags, request_); | |
| 127 set_stream_id(frame->stream_id()); | |
|
ramant (doing other things)
2012/06/26 23:30:25
nit: why call set_stream_id again? stream_id_ is n
Ryan Hamilton
2012/06/27 16:58:28
I *swear* I removed that line of code earlier, but
| |
| 128 send_time_ = base::TimeTicks::Now(); | |
| 129 return frame; | |
| 130 } else { | |
| 131 CHECK(!cancelled()); | |
| 132 // We must need to write stream data. | |
| 133 // Until the headers have been completely sent, we can not be sure | |
| 134 // that our stream_id is correct. | |
| 135 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | |
| 136 DCHECK_GT(stream_id_, 0u); | |
| 137 DCHECK(!pending_data_frames_.empty()); | |
| 138 SpdyFrame* frame = pending_data_frames_.front(); | |
| 139 pending_data_frames_.pop_front(); | |
| 140 return frame; | |
| 141 } | |
| 142 } | |
| 143 | |
| 80 SpdyStream::~SpdyStream() { | 144 SpdyStream::~SpdyStream() { |
| 81 UpdateHistograms(); | 145 UpdateHistograms(); |
| 146 while (!pending_data_frames_.empty()) { | |
| 147 SpdyFrame* frame = pending_data_frames_.back(); | |
| 148 pending_data_frames_.pop_back(); | |
| 149 delete frame; | |
| 150 } | |
| 82 } | 151 } |
| 83 | 152 |
| 84 void SpdyStream::SetDelegate(Delegate* delegate) { | 153 void SpdyStream::SetDelegate(Delegate* delegate) { |
| 85 CHECK(delegate); | 154 CHECK(delegate); |
| 86 delegate_ = delegate; | 155 delegate_ = delegate; |
| 87 | 156 |
| 88 if (pushed_) { | 157 if (pushed_) { |
| 89 CHECK(response_received()); | 158 CHECK(response_received()); |
| 90 MessageLoop::current()->PostTask( | 159 MessageLoop::current()->PostTask( |
| 91 FROM_HERE, base::Bind(&SpdyStream::PushedStreamReplayData, this)); | 160 FROM_HERE, base::Bind(&SpdyStream::PushedStreamReplayData, this)); |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 void SpdyStream::Cancel() { | 534 void SpdyStream::Cancel() { |
| 466 if (cancelled()) | 535 if (cancelled()) |
| 467 return; | 536 return; |
| 468 | 537 |
| 469 cancelled_ = true; | 538 cancelled_ = true; |
| 470 if (session_->IsStreamActive(stream_id_)) | 539 if (session_->IsStreamActive(stream_id_)) |
| 471 session_->ResetStream(stream_id_, CANCEL, ""); | 540 session_->ResetStream(stream_id_, CANCEL, ""); |
| 472 } | 541 } |
| 473 | 542 |
| 474 void SpdyStream::Close() { | 543 void SpdyStream::Close() { |
| 475 session_->CloseStream(stream_id_, net::OK); | 544 if (stream_id_ != 0) |
| 545 session_->CloseStream(stream_id_, net::OK); | |
| 546 else | |
| 547 session_->CloseCreatedStream(this, OK); | |
| 476 } | 548 } |
| 477 | 549 |
| 478 int SpdyStream::SendRequest(bool has_upload_data) { | 550 int SpdyStream::SendRequest(bool has_upload_data) { |
| 479 if (delegate_) | 551 if (delegate_) |
| 480 delegate_->set_chunk_callback(this); | 552 delegate_->set_chunk_callback(this); |
| 481 | 553 |
| 482 // Pushed streams do not send any data, and should always be in STATE_OPEN or | 554 // Pushed streams do not send any data, and should always be in STATE_OPEN or |
| 483 // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push | 555 // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push |
| 484 // behavior. | 556 // behavior. |
| 485 has_upload_data_ = has_upload_data; | 557 has_upload_data_ = has_upload_data; |
| 486 if (pushed_) { | 558 if (pushed_) { |
| 487 send_time_ = base::TimeTicks::Now(); | 559 send_time_ = base::TimeTicks::Now(); |
| 488 DCHECK(!has_upload_data_); | 560 DCHECK(!has_upload_data_); |
| 489 DCHECK(response_received()); | 561 DCHECK(response_received()); |
| 490 return ERR_IO_PENDING; | 562 return ERR_IO_PENDING; |
| 491 } | 563 } |
| 492 CHECK_EQ(STATE_NONE, io_state_); | 564 CHECK_EQ(STATE_NONE, io_state_); |
| 493 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; | 565 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; |
| 494 return DoLoop(OK); | 566 return DoLoop(OK); |
| 495 } | 567 } |
| 496 | 568 |
| 497 int SpdyStream::WriteStreamData(IOBuffer* data, int length, | 569 int SpdyStream::WriteStreamData(IOBuffer* data, int length, |
| 498 SpdyDataFlags flags) { | 570 SpdyDataFlags flags) { |
| 499 // Until the headers have been completely sent, we can not be sure | 571 // Until the headers have been completely sent, we can not be sure |
| 500 // that our stream_id is correct. | 572 // that our stream_id is correct. |
| 501 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | 573 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); |
| 502 return session_->WriteStreamData(stream_id_, data, length, flags); | 574 CHECK_GT(stream_id_, 0u); |
| 575 | |
| 576 pending_data_frames_.push_back( | |
| 577 session_->CreateDataFrame(stream_id_, data, length, flags)); | |
| 578 | |
| 579 SetHasWriteAvailable(); | |
| 580 return ERR_IO_PENDING; | |
| 503 } | 581 } |
| 504 | 582 |
| 505 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, | 583 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, |
| 506 bool* was_npn_negotiated, | 584 bool* was_npn_negotiated, |
| 507 NextProto* protocol_negotiated) { | 585 NextProto* protocol_negotiated) { |
| 508 return session_->GetSSLInfo( | 586 return session_->GetSSLInfo( |
| 509 ssl_info, was_npn_negotiated, protocol_negotiated); | 587 ssl_info, was_npn_negotiated, protocol_negotiated); |
| 510 } | 588 } |
| 511 | 589 |
| 512 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { | 590 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 return result; | 714 return result; |
| 637 | 715 |
| 638 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; | 716 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; |
| 639 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); | 717 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); |
| 640 return OK; | 718 return OK; |
| 641 } | 719 } |
| 642 | 720 |
| 643 int SpdyStream::DoSendDomainBoundCert() { | 721 int SpdyStream::DoSendDomainBoundCert() { |
| 644 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; | 722 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; |
| 645 CHECK(request_.get()); | 723 CHECK(request_.get()); |
| 646 std::string origin = GetUrl().GetOrigin().spec(); | 724 SetHasWriteAvailable(); |
| 647 origin.erase(origin.length() - 1); // trim trailing slash | 725 return ERR_IO_PENDING; |
| 648 int rv = session_->WriteCredentialFrame( | |
| 649 origin, domain_bound_cert_type_, domain_bound_private_key_, | |
| 650 domain_bound_cert_, priority_); | |
| 651 if (rv != ERR_IO_PENDING) | |
| 652 return rv; | |
| 653 return OK; | |
| 654 } | 726 } |
| 655 | 727 |
| 656 int SpdyStream::DoSendDomainBoundCertComplete(int result) { | 728 int SpdyStream::DoSendDomainBoundCertComplete(int result) { |
| 657 if (result < 0) | 729 if (result < 0) |
| 658 return result; | 730 return result; |
| 659 | 731 |
| 660 io_state_ = STATE_SEND_HEADERS; | 732 io_state_ = STATE_SEND_HEADERS; |
| 661 return OK; | 733 return OK; |
| 662 } | 734 } |
| 663 | 735 |
| 664 int SpdyStream::DoSendHeaders() { | 736 int SpdyStream::DoSendHeaders() { |
| 665 CHECK(!cancelled_); | 737 CHECK(!cancelled_); |
| 666 | 738 |
| 667 SpdyControlFlags flags = CONTROL_FLAG_NONE; | 739 SetHasWriteAvailable(); |
| 668 if (!has_upload_data_) | |
| 669 flags = CONTROL_FLAG_FIN; | |
| 670 | |
| 671 CHECK(request_.get()); | |
| 672 int result = session_->WriteSynStream( | |
| 673 stream_id_, priority_, slot_, flags, | |
| 674 request_); | |
| 675 if (result != ERR_IO_PENDING) | |
| 676 return result; | |
| 677 | |
| 678 send_time_ = base::TimeTicks::Now(); | |
| 679 io_state_ = STATE_SEND_HEADERS_COMPLETE; | 740 io_state_ = STATE_SEND_HEADERS_COMPLETE; |
| 680 return ERR_IO_PENDING; | 741 return ERR_IO_PENDING; |
| 681 } | 742 } |
| 682 | 743 |
| 683 int SpdyStream::DoSendHeadersComplete(int result) { | 744 int SpdyStream::DoSendHeadersComplete(int result) { |
| 684 if (result < 0) | 745 if (result < 0) |
| 685 return result; | 746 return result; |
| 686 | 747 |
| 687 CHECK_GT(result, 0); | 748 CHECK_GT(result, 0); |
| 688 | 749 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 748 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", | 809 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", |
| 749 recv_last_byte_time_ - recv_first_byte_time_); | 810 recv_last_byte_time_ - recv_first_byte_time_); |
| 750 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", | 811 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", |
| 751 recv_last_byte_time_ - send_time_); | 812 recv_last_byte_time_ - send_time_); |
| 752 | 813 |
| 753 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); | 814 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); |
| 754 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); | 815 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); |
| 755 } | 816 } |
| 756 | 817 |
| 757 } // namespace net | 818 } // namespace net |
| OLD | NEW |