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 | |
101 }; | |
102 | |
103 SpdySession::SpdyIOBufferProducer* SpdyStream::CreateProducer() { | |
willchan no longer on Chromium
2012/06/26 17:07:27
I don't feel strongly. I don't really know why I f
Ryan Hamilton
2012/06/26 17:55:24
Done. Heh, fair enough. Both approaches work for
| |
104 return new SpdyStreamIOBufferProducer(this); | |
105 } | |
106 | |
107 SpdyFrame* SpdyStream::ProduceNextFrame() { | |
108 if (io_state_ == STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE) { | |
109 CHECK(request_.get()); | |
110 CHECK_GT(stream_id_, 0u); | |
111 | |
112 std::string origin = GetUrl().GetOrigin().spec(); | |
113 origin.erase(origin.length() - 1); // trim trailing slash | |
114 SpdyCredentialControlFrame* frame = session_->CreateCredentialFrame( | |
115 origin, domain_bound_cert_type_, domain_bound_private_key_, | |
116 domain_bound_cert_, priority_); | |
117 return frame; | |
118 } else if (io_state_ == STATE_SEND_HEADERS_COMPLETE) { | |
119 CHECK(request_.get()); | |
120 CHECK_GT(stream_id_, 0u); | |
121 | |
122 SpdyControlFlags flags = | |
123 has_upload_data_ ? CONTROL_FLAG_NONE : CONTROL_FLAG_FIN; | |
124 SpdySynStreamControlFrame* frame = session_->CreateSynStream( | |
125 stream_id_, priority_, slot_, flags, request_); | |
126 set_stream_id(frame->stream_id()); | |
127 send_time_ = base::TimeTicks::Now(); | |
128 return frame; | |
129 } else { | |
130 CHECK(!cancelled()); | |
131 // We must need to write stream data. | |
132 // Until the headers have been completely sent, we can not be sure | |
133 // that our stream_id is correct. | |
134 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | |
135 DCHECK_GT(stream_id_, 0u); | |
136 DCHECK(!pending_data_frames_.empty()); | |
137 SpdyFrame* frame = pending_data_frames_.front(); | |
138 pending_data_frames_.pop_front(); | |
139 return frame; | |
140 } | |
141 } | |
142 | |
80 SpdyStream::~SpdyStream() { | 143 SpdyStream::~SpdyStream() { |
81 UpdateHistograms(); | 144 UpdateHistograms(); |
145 while (!pending_data_frames_.empty()) { | |
146 SpdyFrame* frame = pending_data_frames_.back(); | |
147 pending_data_frames_.pop_back(); | |
148 delete frame; | |
149 } | |
82 } | 150 } |
83 | 151 |
84 void SpdyStream::SetDelegate(Delegate* delegate) { | 152 void SpdyStream::SetDelegate(Delegate* delegate) { |
85 CHECK(delegate); | 153 CHECK(delegate); |
86 delegate_ = delegate; | 154 delegate_ = delegate; |
87 | 155 |
88 if (pushed_) { | 156 if (pushed_) { |
89 CHECK(response_received()); | 157 CHECK(response_received()); |
90 MessageLoop::current()->PostTask( | 158 MessageLoop::current()->PostTask( |
91 FROM_HERE, base::Bind(&SpdyStream::PushedStreamReplayData, this)); | 159 FROM_HERE, base::Bind(&SpdyStream::PushedStreamReplayData, this)); |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
465 void SpdyStream::Cancel() { | 533 void SpdyStream::Cancel() { |
466 if (cancelled()) | 534 if (cancelled()) |
467 return; | 535 return; |
468 | 536 |
469 cancelled_ = true; | 537 cancelled_ = true; |
470 if (session_->IsStreamActive(stream_id_)) | 538 if (session_->IsStreamActive(stream_id_)) |
471 session_->ResetStream(stream_id_, CANCEL, ""); | 539 session_->ResetStream(stream_id_, CANCEL, ""); |
472 } | 540 } |
473 | 541 |
474 void SpdyStream::Close() { | 542 void SpdyStream::Close() { |
475 session_->CloseStream(stream_id_, net::OK); | 543 if (stream_id_ != 0) |
544 session_->CloseStream(stream_id_, net::OK); | |
545 else | |
546 session_->CloseCreatedStream(this, OK); | |
476 } | 547 } |
477 | 548 |
478 int SpdyStream::SendRequest(bool has_upload_data) { | 549 int SpdyStream::SendRequest(bool has_upload_data) { |
479 if (delegate_) | 550 if (delegate_) |
480 delegate_->set_chunk_callback(this); | 551 delegate_->set_chunk_callback(this); |
481 | 552 |
482 // Pushed streams do not send any data, and should always be in STATE_OPEN or | 553 // 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 | 554 // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push |
484 // behavior. | 555 // behavior. |
485 has_upload_data_ = has_upload_data; | 556 has_upload_data_ = has_upload_data; |
486 if (pushed_) { | 557 if (pushed_) { |
487 send_time_ = base::TimeTicks::Now(); | 558 send_time_ = base::TimeTicks::Now(); |
488 DCHECK(!has_upload_data_); | 559 DCHECK(!has_upload_data_); |
489 DCHECK(response_received()); | 560 DCHECK(response_received()); |
490 return ERR_IO_PENDING; | 561 return ERR_IO_PENDING; |
491 } | 562 } |
492 CHECK_EQ(STATE_NONE, io_state_); | 563 CHECK_EQ(STATE_NONE, io_state_); |
493 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; | 564 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; |
494 return DoLoop(OK); | 565 return DoLoop(OK); |
495 } | 566 } |
496 | 567 |
497 int SpdyStream::WriteStreamData(IOBuffer* data, int length, | 568 int SpdyStream::WriteStreamData(IOBuffer* data, int length, |
498 SpdyDataFlags flags) { | 569 SpdyDataFlags flags) { |
499 // Until the headers have been completely sent, we can not be sure | 570 // Until the headers have been completely sent, we can not be sure |
500 // that our stream_id is correct. | 571 // that our stream_id is correct. |
501 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | 572 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); |
502 return session_->WriteStreamData(stream_id_, data, length, flags); | 573 CHECK_GT(stream_id_, 0u); |
574 | |
575 pending_data_frames_.push_back( | |
576 session_->CreateDataFrame(stream_id_, data, length, flags)); | |
577 | |
578 session_->SetStreamHasWriteAvailable(this); | |
579 return ERR_IO_PENDING; | |
503 } | 580 } |
504 | 581 |
505 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, | 582 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, |
506 bool* was_npn_negotiated, | 583 bool* was_npn_negotiated, |
507 NextProto* protocol_negotiated) { | 584 NextProto* protocol_negotiated) { |
508 return session_->GetSSLInfo( | 585 return session_->GetSSLInfo( |
509 ssl_info, was_npn_negotiated, protocol_negotiated); | 586 ssl_info, was_npn_negotiated, protocol_negotiated); |
510 } | 587 } |
511 | 588 |
512 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { | 589 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
636 return result; | 713 return result; |
637 | 714 |
638 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; | 715 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; |
639 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); | 716 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); |
640 return OK; | 717 return OK; |
641 } | 718 } |
642 | 719 |
643 int SpdyStream::DoSendDomainBoundCert() { | 720 int SpdyStream::DoSendDomainBoundCert() { |
644 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; | 721 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; |
645 CHECK(request_.get()); | 722 CHECK(request_.get()); |
646 std::string origin = GetUrl().GetOrigin().spec(); | 723 session_->SetStreamHasWriteAvailable(this); |
647 origin.erase(origin.length() - 1); // trim trailing slash | 724 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 } | 725 } |
655 | 726 |
656 int SpdyStream::DoSendDomainBoundCertComplete(int result) { | 727 int SpdyStream::DoSendDomainBoundCertComplete(int result) { |
657 if (result < 0) | 728 if (result < 0) |
658 return result; | 729 return result; |
659 | 730 |
660 io_state_ = STATE_SEND_HEADERS; | 731 io_state_ = STATE_SEND_HEADERS; |
661 return OK; | 732 return OK; |
662 } | 733 } |
663 | 734 |
664 int SpdyStream::DoSendHeaders() { | 735 int SpdyStream::DoSendHeaders() { |
665 CHECK(!cancelled_); | 736 CHECK(!cancelled_); |
666 | 737 |
667 SpdyControlFlags flags = CONTROL_FLAG_NONE; | 738 session_->SetStreamHasWriteAvailable(this); |
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; | 739 io_state_ = STATE_SEND_HEADERS_COMPLETE; |
680 return ERR_IO_PENDING; | 740 return ERR_IO_PENDING; |
681 } | 741 } |
682 | 742 |
683 int SpdyStream::DoSendHeadersComplete(int result) { | 743 int SpdyStream::DoSendHeadersComplete(int result) { |
684 if (result < 0) | 744 if (result < 0) |
685 return result; | 745 return result; |
686 | 746 |
687 CHECK_GT(result, 0); | 747 CHECK_GT(result, 0); |
688 | 748 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
748 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", | 808 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", |
749 recv_last_byte_time_ - recv_first_byte_time_); | 809 recv_last_byte_time_ - recv_first_byte_time_); |
750 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", | 810 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", |
751 recv_last_byte_time_ - send_time_); | 811 recv_last_byte_time_ - send_time_); |
752 | 812 |
753 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); | 813 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); |
754 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); | 814 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); |
755 } | 815 } |
756 | 816 |
757 } // namespace net | 817 } // namespace net |
OLD | NEW |