int32 initial_recv_window_size,
const BoundNetLog& net_log)
: type_(type),
- weak_ptr_factory_(this),
stream_id_(0),
url_(url),
priority_(priority),
raw_received_bytes_(0),
send_bytes_(0),
recv_bytes_(0),
- write_handler_guard_(false) {
+ write_handler_guard_(false),
+ weak_ptr_factory_(this) {
CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
type_ == SPDY_REQUEST_RESPONSE_STREAM ||
type_ == SPDY_PUSH_STREAM);
delegate_ = delegate;
CHECK(io_state_ == STATE_IDLE ||
- io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED);
+ io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED ||
+ io_state_ == STATE_RESERVED_REMOTE);
if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) {
DCHECK_EQ(type_, SPDY_PUSH_STREAM);
// Push streams transition to a locally half-closed state upon headers.
// We must continue to buffer data while waiting for a call to
// SetDelegate() (which may not ever happen).
- // TODO(jgraettinger): When PUSH_PROMISE is added, Handle RESERVED_REMOTE
- // cases here depending on whether the delegate is already set.
- CHECK_EQ(io_state_, STATE_IDLE);
- DCHECK(!delegate_);
- io_state_ = STATE_HALF_CLOSED_LOCAL_UNCLAIMED;
+ CHECK_EQ(io_state_, STATE_RESERVED_REMOTE);
+ if (!delegate_) {
+ io_state_ = STATE_HALF_CLOSED_LOCAL_UNCLAIMED;
+ } else {
+ io_state_ = STATE_HALF_CLOSED_LOCAL;
+ }
break;
}
return MergeWithResponseHeaders(additional_response_headers);
}
+void SpdyStream::OnPushPromiseHeadersReceived(const SpdyHeaderBlock& headers) {
+ CHECK(!request_headers_.get());
+ CHECK_EQ(io_state_, STATE_IDLE);
+ CHECK_EQ(type_, SPDY_PUSH_STREAM);
+ DCHECK(!delegate_);
+
+ io_state_ = STATE_RESERVED_REMOTE;
+ request_headers_.reset(new SpdyHeaderBlock(headers));
+}
+
void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
DCHECK(session_->IsStreamActive(stream_id_));
return io_state_ == STATE_OPEN;
}
+bool SpdyStream::IsReservedRemote() const {
+ return io_state_ == STATE_RESERVED_REMOTE;
+}
+
NextProto SpdyStream::GetProtocol() const {
return session_->protocol();
}
}
GURL SpdyStream::GetUrlFromHeaders() const {
- if (type_ != SPDY_PUSH_STREAM && !request_headers_)
+ if (!request_headers_)
return GURL();
- const SpdyHeaderBlock& headers =
- (type_ == SPDY_PUSH_STREAM) ? response_headers_ : *request_headers_;
- return GetUrlFromHeaderBlock(headers, GetProtocolVersion(),
- type_ == SPDY_PUSH_STREAM);
+ return GetUrlFromHeaderBlock(
+ *request_headers_, GetProtocolVersion(), type_ == SPDY_PUSH_STREAM);
}
bool SpdyStream::HasUrlFromHeaders() const {
io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_;
CHECK_GT(stream_id_, 0u);
CHECK(pending_send_data_.get());
- CHECK_GT(pending_send_data_->BytesRemaining(), 0);
+ // Only the final fame may have a length of 0.
+ if (pending_send_status_ == NO_MORE_DATA_TO_SEND) {
+ CHECK_GE(pending_send_data_->BytesRemaining(), 0);
+ } else {
+ CHECK_GT(pending_send_data_->BytesRemaining(), 0);
+ }
SpdyDataFlags flags =
(pending_send_status_ == NO_MORE_DATA_TO_SEND) ?
size_t payload_size =
data_buffer->GetRemainingSize() - session_->GetDataFrameMinimumSize();
DCHECK_LE(payload_size, session_->GetDataFrameMaximumPayload());
- DecreaseSendWindowSize(static_cast<int32>(payload_size));
- // This currently isn't strictly needed, since write frames are
- // discarded only if the stream is about to be closed. But have it
- // here anyway just in case this changes.
- data_buffer->AddConsumeCallback(
- base::Bind(&SpdyStream::OnWriteBufferConsumed,
- GetWeakPtr(), payload_size));
+
+ // Send window size is based on payload size, so nothing to do if this is
+ // just a FIN with no payload.
+ if (payload_size != 0) {
+ DecreaseSendWindowSize(static_cast<int32>(payload_size));
+ // This currently isn't strictly needed, since write frames are
+ // discarded only if the stream is about to be closed. But have it
+ // here anyway just in case this changes.
+ data_buffer->AddConsumeCallback(
+ base::Bind(&SpdyStream::OnWriteBufferConsumed,
+ GetWeakPtr(), payload_size));
+ }
}
session_->EnqueueStreamWrite(