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" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "net/spdy/spdy_frame_producer.h" | 15 #include "net/spdy/spdy_buffer_producer.h" |
16 #include "net/spdy/spdy_http_utils.h" | 16 #include "net/spdy/spdy_http_utils.h" |
17 #include "net/spdy/spdy_session.h" | 17 #include "net/spdy/spdy_session.h" |
18 | 18 |
19 namespace net { | 19 namespace net { |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
23 Value* NetLogSpdyStreamErrorCallback(SpdyStreamId stream_id, | 23 Value* NetLogSpdyStreamErrorCallback(SpdyStreamId stream_id, |
24 int status, | 24 int status, |
25 const std::string* description, | 25 const std::string* description, |
(...skipping 21 matching lines...) Expand all Loading... | |
47 if (*i >= 'A' && *i <= 'Z') { | 47 if (*i >= 'A' && *i <= 'Z') { |
48 return true; | 48 return true; |
49 } | 49 } |
50 } | 50 } |
51 return false; | 51 return false; |
52 } | 52 } |
53 | 53 |
54 } // namespace | 54 } // namespace |
55 | 55 |
56 // A wrapper around a stream that calls into ProduceSynStreamFrame(). | 56 // A wrapper around a stream that calls into ProduceSynStreamFrame(). |
57 class SpdyStream::SynStreamFrameProducer : public SpdyFrameProducer { | 57 class SpdyStream::SynStreamBufferProducer : public SpdyBufferProducer { |
58 public: | 58 public: |
59 SynStreamFrameProducer(const base::WeakPtr<SpdyStream>& stream) | 59 SynStreamBufferProducer(const base::WeakPtr<SpdyStream>& stream) |
60 : stream_(stream) { | 60 : stream_(stream) { |
61 DCHECK(stream_); | 61 DCHECK(stream_); |
62 } | 62 } |
63 | 63 |
64 virtual ~SynStreamFrameProducer() {} | 64 virtual ~SynStreamBufferProducer() {} |
65 | 65 |
66 virtual scoped_ptr<SpdyFrame> ProduceFrame() OVERRIDE { | 66 virtual scoped_ptr<SpdyBuffer> ProduceBuffer() OVERRIDE { |
67 if (!stream_) { | 67 if (!stream_) { |
68 NOTREACHED(); | 68 NOTREACHED(); |
69 return scoped_ptr<SpdyFrame>(); | 69 return scoped_ptr<SpdyBuffer>(); |
70 } | 70 } |
71 DCHECK_GT(stream_->stream_id(), 0u); | 71 DCHECK_GT(stream_->stream_id(), 0u); |
72 return stream_->ProduceSynStreamFrame(); | 72 return scoped_ptr<SpdyBuffer>( |
73 new SpdyBuffer(stream_->ProduceSynStreamFrame())); | |
73 } | 74 } |
74 | 75 |
75 private: | 76 private: |
76 const base::WeakPtr<SpdyStream> stream_; | 77 const base::WeakPtr<SpdyStream> stream_; |
77 }; | 78 }; |
78 | 79 |
79 // A wrapper around a stream that calls into ProduceHeaderFrame() with | 80 // A wrapper around a stream that calls into ProduceHeaderFrame() with |
80 // a given header block. | 81 // a given header block. |
81 class SpdyStream::HeaderFrameProducer : public SpdyFrameProducer { | 82 class SpdyStream::HeaderBufferProducer : public SpdyBufferProducer { |
82 public: | 83 public: |
83 HeaderFrameProducer(const base::WeakPtr<SpdyStream>& stream, | 84 HeaderBufferProducer(const base::WeakPtr<SpdyStream>& stream, |
84 scoped_ptr<SpdyHeaderBlock> headers) | 85 scoped_ptr<SpdyHeaderBlock> headers) |
85 : stream_(stream), | 86 : stream_(stream), |
86 headers_(headers.Pass()) { | 87 headers_(headers.Pass()) { |
87 DCHECK(stream_); | 88 DCHECK(stream_); |
88 DCHECK(headers_); | 89 DCHECK(headers_); |
89 } | 90 } |
90 | 91 |
91 virtual ~HeaderFrameProducer() {} | 92 virtual ~HeaderBufferProducer() {} |
92 | 93 |
93 virtual scoped_ptr<SpdyFrame> ProduceFrame() OVERRIDE { | 94 virtual scoped_ptr<SpdyBuffer> ProduceBuffer() OVERRIDE { |
94 if (!stream_) { | 95 if (!stream_) { |
95 NOTREACHED(); | 96 NOTREACHED(); |
96 return scoped_ptr<SpdyFrame>(); | 97 return scoped_ptr<SpdyBuffer>(); |
97 } | 98 } |
98 DCHECK_GT(stream_->stream_id(), 0u); | 99 DCHECK_GT(stream_->stream_id(), 0u); |
99 return stream_->ProduceHeaderFrame(headers_.Pass()); | 100 return scoped_ptr<SpdyBuffer>( |
101 new SpdyBuffer(stream_->ProduceHeaderFrame(headers_.Pass()))); | |
100 } | 102 } |
101 | 103 |
102 private: | 104 private: |
103 const base::WeakPtr<SpdyStream> stream_; | 105 const base::WeakPtr<SpdyStream> stream_; |
104 scoped_ptr<SpdyHeaderBlock> headers_; | 106 scoped_ptr<SpdyHeaderBlock> headers_; |
105 }; | 107 }; |
106 | 108 |
107 SpdyStream::SpdyStream(SpdySession* session, | 109 SpdyStream::SpdyStream(SpdySession* session, |
108 const std::string& path, | 110 const std::string& path, |
109 RequestPriority priority, | 111 RequestPriority priority, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
168 // HEADERS frame. Since we don't have headers, we had better not have | 170 // HEADERS frame. Since we don't have headers, we had better not have |
169 // any pending data frames. | 171 // any pending data frames. |
170 if (pending_buffers_.size() != 0U) { | 172 if (pending_buffers_.size() != 0U) { |
171 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, | 173 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, |
172 "HEADERS incomplete headers, but pending data frames."); | 174 "HEADERS incomplete headers, but pending data frames."); |
173 session_->CloseStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); | 175 session_->CloseStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); |
174 } | 176 } |
175 return; | 177 return; |
176 } | 178 } |
177 | 179 |
178 std::vector<scoped_refptr<IOBufferWithSize> > buffers; | 180 std::vector<SpdyBuffer*> buffers; |
179 buffers.swap(pending_buffers_); | 181 pending_buffers_.release(&buffers); |
180 for (size_t i = 0; i < buffers.size(); ++i) { | 182 for (size_t i = 0; i < buffers.size(); ++i) { |
181 // It is always possible that a callback to the delegate results in | 183 // It is always possible that a callback to the delegate results in |
182 // the delegate no longer being available. | 184 // the delegate no longer being available. |
183 if (!delegate_) | 185 if (!delegate_) |
184 break; | 186 break; |
185 if (buffers[i]) { | 187 if (buffers[i]) { |
186 delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size()); | 188 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>(buffers[i])); |
187 } else { | 189 } else { |
188 delegate_->OnDataReceived(NULL, 0); | 190 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>()); |
189 session_->CloseStream(stream_id_, net::OK); | 191 session_->CloseStream(stream_id_, net::OK); |
190 // Note: |this| may be deleted after calling CloseStream. | 192 // Note: |this| may be deleted after calling CloseStream. |
191 DCHECK_EQ(buffers.size() - 1, i); | 193 DCHECK_EQ(buffers.size() - 1, i); |
192 } | 194 } |
193 } | 195 } |
194 } | 196 } |
195 | 197 |
196 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { | 198 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { |
197 CHECK_EQ(io_state_, STATE_SEND_HEADERS_COMPLETE); | 199 CHECK_EQ(io_state_, STATE_SEND_HEADERS_COMPLETE); |
198 CHECK(request_.get()); | 200 CHECK(request_.get()); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
443 if (delegate_) { | 445 if (delegate_) { |
444 rv = delegate_->OnResponseReceived(*response_, response_time_, rv); | 446 rv = delegate_->OnResponseReceived(*response_, response_time_, rv); |
445 // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more | 447 // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more |
446 // headers before the response header block is complete. | 448 // headers before the response header block is complete. |
447 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) | 449 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) |
448 rv = OK; | 450 rv = OK; |
449 } | 451 } |
450 return rv; | 452 return rv; |
451 } | 453 } |
452 | 454 |
453 void SpdyStream::OnDataReceived(const char* data, size_t length) { | 455 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { |
454 DCHECK(session_->IsStreamActive(stream_id_)); | 456 DCHECK(session_->IsStreamActive(stream_id_)); |
455 DCHECK_LT(length, 1u << 24); | |
456 // If we don't have a response, then the SYN_REPLY did not come through. | 457 // If we don't have a response, then the SYN_REPLY did not come through. |
457 // We cannot pass data up to the caller unless the reply headers have been | 458 // We cannot pass data up to the caller unless the reply headers have been |
458 // received. | 459 // received. |
459 if (!response_received()) { | 460 if (!response_received()) { |
460 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response."); | 461 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response."); |
461 session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); | 462 session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); |
462 return; | 463 return; |
463 } | 464 } |
464 | 465 |
465 if (!delegate_ || continue_buffering_data_) { | 466 if (!delegate_ || continue_buffering_data_) { |
466 // It should be valid for this to happen in the server push case. | 467 // It should be valid for this to happen in the server push case. |
467 // We'll return received data when delegate gets attached to the stream. | 468 // We'll return received data when delegate gets attached to the stream. |
468 if (length > 0) { | 469 if (buffer) { |
469 IOBufferWithSize* buf = new IOBufferWithSize(length); | 470 pending_buffers_.push_back(buffer.release()); |
470 memcpy(buf->data(), data, length); | |
471 pending_buffers_.push_back(make_scoped_refptr(buf)); | |
472 } else { | 471 } else { |
473 pending_buffers_.push_back(NULL); | 472 pending_buffers_.push_back(NULL); |
474 metrics_.StopStream(); | 473 metrics_.StopStream(); |
475 // Note: we leave the stream open in the session until the stream | 474 // Note: we leave the stream open in the session until the stream |
476 // is claimed. | 475 // is claimed. |
477 } | 476 } |
478 return; | 477 return; |
479 } | 478 } |
480 | 479 |
481 CHECK(!closed()); | 480 CHECK(!closed()); |
482 | 481 |
483 // A zero-length read means that the stream is being closed. | 482 if (!buffer) { |
484 if (length == 0) { | |
485 metrics_.StopStream(); | 483 metrics_.StopStream(); |
486 session_->CloseStream(stream_id_, net::OK); | 484 session_->CloseStream(stream_id_, net::OK); |
487 // Note: |this| may be deleted after calling CloseStream. | 485 // Note: |this| may be deleted after calling CloseStream. |
488 return; | 486 return; |
489 } | 487 } |
490 | 488 |
491 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) | 489 if (buffer) { |
Ryan Hamilton
2013/04/16 18:44:25
Looks like you return on line 486 if !buffer, so n
akalin
2013/04/16 23:01:46
Done.
| |
492 DecreaseRecvWindowSize(static_cast<int32>(length)); | 490 size_t length = buffer->GetRemainingSize(); |
491 DCHECK_LE(length, session_->GetDataFrameMaximumPayload()); | |
492 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) | |
493 DecreaseRecvWindowSize(static_cast<int32>(length)); | |
493 | 494 |
494 // Track our bandwidth. | 495 // Track our bandwidth. |
495 metrics_.RecordBytes(length); | 496 metrics_.RecordBytes(length); |
496 recv_bytes_ += length; | 497 recv_bytes_ += length; |
498 } | |
497 recv_last_byte_time_ = base::TimeTicks::Now(); | 499 recv_last_byte_time_ = base::TimeTicks::Now(); |
498 | 500 |
499 if (delegate_->OnDataReceived(data, length) != net::OK) { | 501 if (delegate_->OnDataReceived(buffer.Pass()) != net::OK) { |
500 // |delegate_| rejected the data. | 502 // |delegate_| rejected the data. |
501 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "Delegate rejected the data"); | 503 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "Delegate rejected the data"); |
502 session_->CloseStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); | 504 session_->CloseStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); |
503 return; | 505 return; |
504 } | 506 } |
505 } | 507 } |
506 | 508 |
507 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, | 509 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, |
508 size_t frame_size) { | 510 size_t frame_size) { |
509 if (frame_size < session_->GetFrameMinimumSize() || | 511 if (frame_size < session_->GetFrameMinimumSize() || |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
573 } | 575 } |
574 | 576 |
575 void SpdyStream::QueueHeaders(scoped_ptr<SpdyHeaderBlock> headers) { | 577 void SpdyStream::QueueHeaders(scoped_ptr<SpdyHeaderBlock> headers) { |
576 // Until the first headers by SYN_STREAM have been completely sent, we can | 578 // Until the first headers by SYN_STREAM have been completely sent, we can |
577 // not be sure that our stream_id is correct. | 579 // not be sure that our stream_id is correct. |
578 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | 580 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); |
579 CHECK_GT(stream_id_, 0u); | 581 CHECK_GT(stream_id_, 0u); |
580 | 582 |
581 session_->EnqueueStreamWrite( | 583 session_->EnqueueStreamWrite( |
582 this, HEADERS, | 584 this, HEADERS, |
583 scoped_ptr<SpdyFrameProducer>( | 585 scoped_ptr<SpdyBufferProducer>( |
584 new HeaderFrameProducer( | 586 new HeaderBufferProducer( |
585 weak_ptr_factory_.GetWeakPtr(), headers.Pass()))); | 587 weak_ptr_factory_.GetWeakPtr(), headers.Pass()))); |
586 } | 588 } |
587 | 589 |
588 void SpdyStream::QueueStreamData(IOBuffer* data, | 590 void SpdyStream::QueueStreamData(IOBuffer* data, |
589 int length, | 591 int length, |
590 SpdyDataFlags flags) { | 592 SpdyDataFlags flags) { |
591 // Until the headers have been completely sent, we can not be sure | 593 // Until the headers have been completely sent, we can not be sure |
592 // that our stream_id is correct. | 594 // that our stream_id is correct. |
593 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); | 595 DCHECK_GT(io_state_, STATE_SEND_HEADERS_COMPLETE); |
594 CHECK_GT(stream_id_, 0u); | 596 CHECK_GT(stream_id_, 0u); |
595 CHECK(!cancelled()); | 597 CHECK(!cancelled()); |
596 | 598 |
597 scoped_ptr<SpdyFrame> data_frame(session_->CreateDataFrame( | 599 scoped_ptr<SpdyBuffer> data_buffer(session_->CreateDataBuffer( |
598 stream_id_, data, length, flags)); | 600 stream_id_, data, length, flags)); |
599 if (!data_frame) | 601 // We'll get called again by PossiblyResumeIfSendStalled(). |
602 if (!data_buffer) | |
600 return; | 603 return; |
601 | 604 |
602 session_->EnqueueStreamWrite( | 605 session_->EnqueueStreamWrite( |
603 this, DATA, | 606 this, DATA, |
604 scoped_ptr<SpdyFrameProducer>( | 607 scoped_ptr<SpdyBufferProducer>( |
605 new SimpleFrameProducer(data_frame.Pass()))); | 608 new SimpleBufferProducer(data_buffer.Pass()))); |
606 } | 609 } |
607 | 610 |
608 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, | 611 bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, |
609 bool* was_npn_negotiated, | 612 bool* was_npn_negotiated, |
610 NextProto* protocol_negotiated) { | 613 NextProto* protocol_negotiated) { |
611 return session_->GetSSLInfo( | 614 return session_->GetSSLInfo( |
612 ssl_info, was_npn_negotiated, protocol_negotiated); | 615 ssl_info, was_npn_negotiated, protocol_negotiated); |
613 } | 616 } |
614 | 617 |
615 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { | 618 bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
777 DCHECK(frame); | 780 DCHECK(frame); |
778 // TODO(akalin): Fix the following race condition: | 781 // TODO(akalin): Fix the following race condition: |
779 // | 782 // |
780 // Since this is decoupled from sending the SYN_STREAM frame, it is | 783 // Since this is decoupled from sending the SYN_STREAM frame, it is |
781 // possible that other domain-bound cert frames will clobber ours | 784 // possible that other domain-bound cert frames will clobber ours |
782 // before our SYN_STREAM frame gets sent. This can be solved by | 785 // before our SYN_STREAM frame gets sent. This can be solved by |
783 // immediately enqueueing the SYN_STREAM frame here and adjusting | 786 // immediately enqueueing the SYN_STREAM frame here and adjusting |
784 // the state machine appropriately. | 787 // the state machine appropriately. |
785 session_->EnqueueStreamWrite( | 788 session_->EnqueueStreamWrite( |
786 this, CREDENTIAL, | 789 this, CREDENTIAL, |
787 scoped_ptr<SpdyFrameProducer>(new SimpleFrameProducer(frame.Pass()))); | 790 scoped_ptr<SpdyBufferProducer>( |
791 new SimpleBufferProducer( | |
792 scoped_ptr<SpdyBuffer>(new SpdyBuffer(frame.Pass()))))); | |
788 return ERR_IO_PENDING; | 793 return ERR_IO_PENDING; |
789 } | 794 } |
790 | 795 |
791 int SpdyStream::DoSendDomainBoundCertComplete() { | 796 int SpdyStream::DoSendDomainBoundCertComplete() { |
792 DCHECK_EQ(just_completed_frame_type_, CREDENTIAL); | 797 DCHECK_EQ(just_completed_frame_type_, CREDENTIAL); |
793 io_state_ = STATE_SEND_HEADERS; | 798 io_state_ = STATE_SEND_HEADERS; |
794 return OK; | 799 return OK; |
795 } | 800 } |
796 | 801 |
797 int SpdyStream::DoSendHeaders() { | 802 int SpdyStream::DoSendHeaders() { |
798 CHECK(!cancelled_); | 803 CHECK(!cancelled_); |
799 io_state_ = STATE_SEND_HEADERS_COMPLETE; | 804 io_state_ = STATE_SEND_HEADERS_COMPLETE; |
800 | 805 |
801 session_->EnqueueStreamWrite( | 806 session_->EnqueueStreamWrite( |
802 this, SYN_STREAM, | 807 this, SYN_STREAM, |
803 scoped_ptr<SpdyFrameProducer>( | 808 scoped_ptr<SpdyBufferProducer>( |
804 new SynStreamFrameProducer(weak_ptr_factory_.GetWeakPtr()))); | 809 new SynStreamBufferProducer(weak_ptr_factory_.GetWeakPtr()))); |
805 return ERR_IO_PENDING; | 810 return ERR_IO_PENDING; |
806 } | 811 } |
807 | 812 |
808 int SpdyStream::DoSendHeadersComplete() { | 813 int SpdyStream::DoSendHeadersComplete() { |
809 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM); | 814 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM); |
810 DCHECK_NE(stream_id_, 0u); | 815 DCHECK_NE(stream_id_, 0u); |
811 if (!delegate_) | 816 if (!delegate_) |
812 return ERR_UNEXPECTED; | 817 return ERR_UNEXPECTED; |
813 | 818 |
814 io_state_ = | 819 io_state_ = |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
935 } | 940 } |
936 | 941 |
937 recv_window_size_ -= delta_window_size; | 942 recv_window_size_ -= delta_window_size; |
938 net_log_.AddEvent( | 943 net_log_.AddEvent( |
939 NetLog::TYPE_SPDY_STREAM_UPDATE_RECV_WINDOW, | 944 NetLog::TYPE_SPDY_STREAM_UPDATE_RECV_WINDOW, |
940 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, | 945 base::Bind(&NetLogSpdyStreamWindowUpdateCallback, |
941 stream_id_, -delta_window_size, recv_window_size_)); | 946 stream_id_, -delta_window_size, recv_window_size_)); |
942 } | 947 } |
943 | 948 |
944 } // namespace net | 949 } // namespace net |
OLD | NEW |