1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_stream.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <limits>
9*6777b538SAndroid Build Coastguard Worker #include <string_view>
10*6777b538SAndroid Build Coastguard Worker #include <utility>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/memory_usage_estimator.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
24*6777b538SAndroid Build Coastguard Worker #include "net/base/load_timing_info.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/http/http_status_code.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_capture_mode.h"
28*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_buffer_producer.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_http_utils.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_log_util.h"
32*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_session.h"
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker namespace net {
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker namespace {
37*6777b538SAndroid Build Coastguard Worker
NetLogSpdyStreamErrorParams(spdy::SpdyStreamId stream_id,int net_error,std::string_view description)38*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyStreamErrorParams(spdy::SpdyStreamId stream_id,
39*6777b538SAndroid Build Coastguard Worker int net_error,
40*6777b538SAndroid Build Coastguard Worker std::string_view description) {
41*6777b538SAndroid Build Coastguard Worker return base::Value::Dict()
42*6777b538SAndroid Build Coastguard Worker .Set("stream_id", static_cast<int>(stream_id))
43*6777b538SAndroid Build Coastguard Worker .Set("net_error", ErrorToShortString(net_error))
44*6777b538SAndroid Build Coastguard Worker .Set("description", description);
45*6777b538SAndroid Build Coastguard Worker }
46*6777b538SAndroid Build Coastguard Worker
NetLogSpdyStreamWindowUpdateParams(spdy::SpdyStreamId stream_id,int32_t delta,int32_t window_size)47*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyStreamWindowUpdateParams(
48*6777b538SAndroid Build Coastguard Worker spdy::SpdyStreamId stream_id,
49*6777b538SAndroid Build Coastguard Worker int32_t delta,
50*6777b538SAndroid Build Coastguard Worker int32_t window_size) {
51*6777b538SAndroid Build Coastguard Worker return base::Value::Dict()
52*6777b538SAndroid Build Coastguard Worker .Set("stream_id", static_cast<int>(stream_id))
53*6777b538SAndroid Build Coastguard Worker .Set("delta", delta)
54*6777b538SAndroid Build Coastguard Worker .Set("window_size", window_size);
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker
NetLogSpdyDataParams(spdy::SpdyStreamId stream_id,int size,bool fin)57*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyDataParams(spdy::SpdyStreamId stream_id,
58*6777b538SAndroid Build Coastguard Worker int size,
59*6777b538SAndroid Build Coastguard Worker bool fin) {
60*6777b538SAndroid Build Coastguard Worker return base::Value::Dict()
61*6777b538SAndroid Build Coastguard Worker .Set("stream_id", static_cast<int>(stream_id))
62*6777b538SAndroid Build Coastguard Worker .Set("size", size)
63*6777b538SAndroid Build Coastguard Worker .Set("fin", fin);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker } // namespace
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker // A wrapper around a stream that calls into ProduceHeadersFrame().
69*6777b538SAndroid Build Coastguard Worker class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer {
70*6777b538SAndroid Build Coastguard Worker public:
HeadersBufferProducer(const base::WeakPtr<SpdyStream> & stream)71*6777b538SAndroid Build Coastguard Worker explicit HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream)
72*6777b538SAndroid Build Coastguard Worker : stream_(stream) {
73*6777b538SAndroid Build Coastguard Worker DCHECK(stream_.get());
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker ~HeadersBufferProducer() override = default;
77*6777b538SAndroid Build Coastguard Worker
ProduceBuffer()78*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
79*6777b538SAndroid Build Coastguard Worker if (!stream_.get()) {
80*6777b538SAndroid Build Coastguard Worker NOTREACHED();
81*6777b538SAndroid Build Coastguard Worker return nullptr;
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker DCHECK_GT(stream_->stream_id(), 0u);
84*6777b538SAndroid Build Coastguard Worker return std::make_unique<SpdyBuffer>(stream_->ProduceHeadersFrame());
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker private:
88*6777b538SAndroid Build Coastguard Worker const base::WeakPtr<SpdyStream> stream_;
89*6777b538SAndroid Build Coastguard Worker };
90*6777b538SAndroid Build Coastguard Worker
SpdyStream(SpdyStreamType type,const base::WeakPtr<SpdySession> & session,const GURL & url,RequestPriority priority,int32_t initial_send_window_size,int32_t max_recv_window_size,const NetLogWithSource & net_log,const NetworkTrafficAnnotationTag & traffic_annotation,bool detect_broken_connection)91*6777b538SAndroid Build Coastguard Worker SpdyStream::SpdyStream(SpdyStreamType type,
92*6777b538SAndroid Build Coastguard Worker const base::WeakPtr<SpdySession>& session,
93*6777b538SAndroid Build Coastguard Worker const GURL& url,
94*6777b538SAndroid Build Coastguard Worker RequestPriority priority,
95*6777b538SAndroid Build Coastguard Worker int32_t initial_send_window_size,
96*6777b538SAndroid Build Coastguard Worker int32_t max_recv_window_size,
97*6777b538SAndroid Build Coastguard Worker const NetLogWithSource& net_log,
98*6777b538SAndroid Build Coastguard Worker const NetworkTrafficAnnotationTag& traffic_annotation,
99*6777b538SAndroid Build Coastguard Worker bool detect_broken_connection)
100*6777b538SAndroid Build Coastguard Worker : type_(type),
101*6777b538SAndroid Build Coastguard Worker url_(url),
102*6777b538SAndroid Build Coastguard Worker priority_(priority),
103*6777b538SAndroid Build Coastguard Worker send_window_size_(initial_send_window_size),
104*6777b538SAndroid Build Coastguard Worker max_recv_window_size_(max_recv_window_size),
105*6777b538SAndroid Build Coastguard Worker recv_window_size_(max_recv_window_size),
106*6777b538SAndroid Build Coastguard Worker last_recv_window_update_(base::TimeTicks::Now()),
107*6777b538SAndroid Build Coastguard Worker session_(session),
108*6777b538SAndroid Build Coastguard Worker request_time_(base::Time::Now()),
109*6777b538SAndroid Build Coastguard Worker net_log_(net_log),
110*6777b538SAndroid Build Coastguard Worker traffic_annotation_(traffic_annotation),
111*6777b538SAndroid Build Coastguard Worker detect_broken_connection_(detect_broken_connection) {
112*6777b538SAndroid Build Coastguard Worker CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
113*6777b538SAndroid Build Coastguard Worker type_ == SPDY_REQUEST_RESPONSE_STREAM);
114*6777b538SAndroid Build Coastguard Worker CHECK_GE(priority_, MINIMUM_PRIORITY);
115*6777b538SAndroid Build Coastguard Worker CHECK_LE(priority_, MAXIMUM_PRIORITY);
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker
~SpdyStream()118*6777b538SAndroid Build Coastguard Worker SpdyStream::~SpdyStream() {
119*6777b538SAndroid Build Coastguard Worker CHECK(!write_handler_guard_);
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker
SetDelegate(Delegate * delegate)122*6777b538SAndroid Build Coastguard Worker void SpdyStream::SetDelegate(Delegate* delegate) {
123*6777b538SAndroid Build Coastguard Worker CHECK(!delegate_);
124*6777b538SAndroid Build Coastguard Worker CHECK(delegate);
125*6777b538SAndroid Build Coastguard Worker delegate_ = delegate;
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker CHECK(io_state_ == STATE_IDLE || io_state_ == STATE_RESERVED_REMOTE);
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker
ProduceHeadersFrame()130*6777b538SAndroid Build Coastguard Worker std::unique_ptr<spdy::SpdySerializedFrame> SpdyStream::ProduceHeadersFrame() {
131*6777b538SAndroid Build Coastguard Worker CHECK_EQ(io_state_, STATE_IDLE);
132*6777b538SAndroid Build Coastguard Worker CHECK(request_headers_valid_);
133*6777b538SAndroid Build Coastguard Worker CHECK_GT(stream_id_, 0u);
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker spdy::SpdyControlFlags flags = (pending_send_status_ == NO_MORE_DATA_TO_SEND)
136*6777b538SAndroid Build Coastguard Worker ? spdy::CONTROL_FLAG_FIN
137*6777b538SAndroid Build Coastguard Worker : spdy::CONTROL_FLAG_NONE;
138*6777b538SAndroid Build Coastguard Worker std::unique_ptr<spdy::SpdySerializedFrame> frame(session_->CreateHeaders(
139*6777b538SAndroid Build Coastguard Worker stream_id_, priority_, flags, std::move(request_headers_),
140*6777b538SAndroid Build Coastguard Worker delegate_->source_dependency()));
141*6777b538SAndroid Build Coastguard Worker request_headers_valid_ = false;
142*6777b538SAndroid Build Coastguard Worker send_time_ = base::TimeTicks::Now();
143*6777b538SAndroid Build Coastguard Worker return frame;
144*6777b538SAndroid Build Coastguard Worker }
145*6777b538SAndroid Build Coastguard Worker
DetachDelegate()146*6777b538SAndroid Build Coastguard Worker void SpdyStream::DetachDelegate() {
147*6777b538SAndroid Build Coastguard Worker DCHECK(!IsClosed());
148*6777b538SAndroid Build Coastguard Worker delegate_ = nullptr;
149*6777b538SAndroid Build Coastguard Worker Cancel(ERR_ABORTED);
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker
SetPriority(RequestPriority priority)152*6777b538SAndroid Build Coastguard Worker void SpdyStream::SetPriority(RequestPriority priority) {
153*6777b538SAndroid Build Coastguard Worker if (priority_ == priority) {
154*6777b538SAndroid Build Coastguard Worker return;
155*6777b538SAndroid Build Coastguard Worker }
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker session_->UpdateStreamPriority(this, /* old_priority = */ priority_,
158*6777b538SAndroid Build Coastguard Worker /* new_priority = */ priority);
159*6777b538SAndroid Build Coastguard Worker
160*6777b538SAndroid Build Coastguard Worker priority_ = priority;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker
AdjustSendWindowSize(int32_t delta_window_size)163*6777b538SAndroid Build Coastguard Worker bool SpdyStream::AdjustSendWindowSize(int32_t delta_window_size) {
164*6777b538SAndroid Build Coastguard Worker if (IsClosed())
165*6777b538SAndroid Build Coastguard Worker return true;
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker if (delta_window_size > 0) {
168*6777b538SAndroid Build Coastguard Worker if (send_window_size_ >
169*6777b538SAndroid Build Coastguard Worker std::numeric_limits<int32_t>::max() - delta_window_size) {
170*6777b538SAndroid Build Coastguard Worker return false;
171*6777b538SAndroid Build Coastguard Worker }
172*6777b538SAndroid Build Coastguard Worker } else {
173*6777b538SAndroid Build Coastguard Worker // Minimum allowed value for spdy::SETTINGS_INITIAL_WINDOW_SIZE is 0 and
174*6777b538SAndroid Build Coastguard Worker // maximum is 2^31-1. Data are not sent when |send_window_size_ < 0|, that
175*6777b538SAndroid Build Coastguard Worker // is, |send_window_size_ | can only decrease by a change in
176*6777b538SAndroid Build Coastguard Worker // spdy::SETTINGS_INITIAL_WINDOW_SIZE. Therefore |send_window_size_| should
177*6777b538SAndroid Build Coastguard Worker // never be able to become less than -(2^31-1).
178*6777b538SAndroid Build Coastguard Worker DCHECK_LE(std::numeric_limits<int32_t>::min() - delta_window_size,
179*6777b538SAndroid Build Coastguard Worker send_window_size_);
180*6777b538SAndroid Build Coastguard Worker }
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker send_window_size_ += delta_window_size;
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW, [&] {
185*6777b538SAndroid Build Coastguard Worker return NetLogSpdyStreamWindowUpdateParams(stream_id_, delta_window_size,
186*6777b538SAndroid Build Coastguard Worker send_window_size_);
187*6777b538SAndroid Build Coastguard Worker });
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker PossiblyResumeIfSendStalled();
190*6777b538SAndroid Build Coastguard Worker return true;
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker
OnWriteBufferConsumed(size_t frame_payload_size,size_t consume_size,SpdyBuffer::ConsumeSource consume_source)193*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnWriteBufferConsumed(
194*6777b538SAndroid Build Coastguard Worker size_t frame_payload_size,
195*6777b538SAndroid Build Coastguard Worker size_t consume_size,
196*6777b538SAndroid Build Coastguard Worker SpdyBuffer::ConsumeSource consume_source) {
197*6777b538SAndroid Build Coastguard Worker if (consume_source == SpdyBuffer::DISCARD) {
198*6777b538SAndroid Build Coastguard Worker // If we're discarding a frame or part of it, increase the send
199*6777b538SAndroid Build Coastguard Worker // window by the number of discarded bytes. (Although if we're
200*6777b538SAndroid Build Coastguard Worker // discarding part of a frame, it's probably because of a write
201*6777b538SAndroid Build Coastguard Worker // error and we'll be tearing down the stream soon.)
202*6777b538SAndroid Build Coastguard Worker size_t remaining_payload_bytes = std::min(consume_size, frame_payload_size);
203*6777b538SAndroid Build Coastguard Worker DCHECK_GT(remaining_payload_bytes, 0u);
204*6777b538SAndroid Build Coastguard Worker IncreaseSendWindowSize(static_cast<int32_t>(remaining_payload_bytes));
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker // For consumed bytes, the send window is increased when we receive
207*6777b538SAndroid Build Coastguard Worker // a WINDOW_UPDATE frame.
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker
IncreaseSendWindowSize(int32_t delta_window_size)210*6777b538SAndroid Build Coastguard Worker void SpdyStream::IncreaseSendWindowSize(int32_t delta_window_size) {
211*6777b538SAndroid Build Coastguard Worker DCHECK_GE(delta_window_size, 1);
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker if (!AdjustSendWindowSize(delta_window_size)) {
214*6777b538SAndroid Build Coastguard Worker std::string desc = base::StringPrintf(
215*6777b538SAndroid Build Coastguard Worker "Received WINDOW_UPDATE [delta: %d] for stream %d overflows "
216*6777b538SAndroid Build Coastguard Worker "send_window_size_ [current: %d]",
217*6777b538SAndroid Build Coastguard Worker delta_window_size, stream_id_, send_window_size_);
218*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_FLOW_CONTROL_ERROR, desc);
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker }
221*6777b538SAndroid Build Coastguard Worker
DecreaseSendWindowSize(int32_t delta_window_size)222*6777b538SAndroid Build Coastguard Worker void SpdyStream::DecreaseSendWindowSize(int32_t delta_window_size) {
223*6777b538SAndroid Build Coastguard Worker if (IsClosed())
224*6777b538SAndroid Build Coastguard Worker return;
225*6777b538SAndroid Build Coastguard Worker
226*6777b538SAndroid Build Coastguard Worker // We only call this method when sending a frame. Therefore,
227*6777b538SAndroid Build Coastguard Worker // |delta_window_size| should be within the valid frame size range.
228*6777b538SAndroid Build Coastguard Worker DCHECK_GE(delta_window_size, 1);
229*6777b538SAndroid Build Coastguard Worker DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker // |send_window_size_| should have been at least |delta_window_size| for
232*6777b538SAndroid Build Coastguard Worker // this call to happen.
233*6777b538SAndroid Build Coastguard Worker DCHECK_GE(send_window_size_, delta_window_size);
234*6777b538SAndroid Build Coastguard Worker
235*6777b538SAndroid Build Coastguard Worker send_window_size_ -= delta_window_size;
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW, [&] {
238*6777b538SAndroid Build Coastguard Worker return NetLogSpdyStreamWindowUpdateParams(stream_id_, -delta_window_size,
239*6777b538SAndroid Build Coastguard Worker send_window_size_);
240*6777b538SAndroid Build Coastguard Worker });
241*6777b538SAndroid Build Coastguard Worker }
242*6777b538SAndroid Build Coastguard Worker
OnReadBufferConsumed(size_t consume_size,SpdyBuffer::ConsumeSource consume_source)243*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnReadBufferConsumed(
244*6777b538SAndroid Build Coastguard Worker size_t consume_size,
245*6777b538SAndroid Build Coastguard Worker SpdyBuffer::ConsumeSource consume_source) {
246*6777b538SAndroid Build Coastguard Worker DCHECK_GE(consume_size, 1u);
247*6777b538SAndroid Build Coastguard Worker DCHECK_LE(consume_size,
248*6777b538SAndroid Build Coastguard Worker static_cast<size_t>(std::numeric_limits<int32_t>::max()));
249*6777b538SAndroid Build Coastguard Worker IncreaseRecvWindowSize(static_cast<int32_t>(consume_size));
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker
IncreaseRecvWindowSize(int32_t delta_window_size)252*6777b538SAndroid Build Coastguard Worker void SpdyStream::IncreaseRecvWindowSize(int32_t delta_window_size) {
253*6777b538SAndroid Build Coastguard Worker // By the time a read is processed by the delegate, this stream may
254*6777b538SAndroid Build Coastguard Worker // already be inactive.
255*6777b538SAndroid Build Coastguard Worker if (!session_->IsStreamActive(stream_id_))
256*6777b538SAndroid Build Coastguard Worker return;
257*6777b538SAndroid Build Coastguard Worker
258*6777b538SAndroid Build Coastguard Worker DCHECK_GE(unacked_recv_window_bytes_, 0);
259*6777b538SAndroid Build Coastguard Worker DCHECK_GE(recv_window_size_, unacked_recv_window_bytes_);
260*6777b538SAndroid Build Coastguard Worker DCHECK_GE(delta_window_size, 1);
261*6777b538SAndroid Build Coastguard Worker // Check for overflow.
262*6777b538SAndroid Build Coastguard Worker DCHECK_LE(delta_window_size,
263*6777b538SAndroid Build Coastguard Worker std::numeric_limits<int32_t>::max() - recv_window_size_);
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker recv_window_size_ += delta_window_size;
266*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW, [&] {
267*6777b538SAndroid Build Coastguard Worker return NetLogSpdyStreamWindowUpdateParams(stream_id_, delta_window_size,
268*6777b538SAndroid Build Coastguard Worker recv_window_size_);
269*6777b538SAndroid Build Coastguard Worker });
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker // Update the receive window once half of the buffer is ready to be acked
272*6777b538SAndroid Build Coastguard Worker // to prevent excessive window updates on fast downloads. Also send an update
273*6777b538SAndroid Build Coastguard Worker // if too much time has elapsed since the last update to deal with
274*6777b538SAndroid Build Coastguard Worker // slow-reading clients so the server doesn't think the stream is idle.
275*6777b538SAndroid Build Coastguard Worker unacked_recv_window_bytes_ += delta_window_size;
276*6777b538SAndroid Build Coastguard Worker const base::TimeDelta elapsed =
277*6777b538SAndroid Build Coastguard Worker base::TimeTicks::Now() - last_recv_window_update_;
278*6777b538SAndroid Build Coastguard Worker if (unacked_recv_window_bytes_ > max_recv_window_size_ / 2 ||
279*6777b538SAndroid Build Coastguard Worker elapsed >= session_->TimeToBufferSmallWindowUpdates()) {
280*6777b538SAndroid Build Coastguard Worker last_recv_window_update_ = base::TimeTicks::Now();
281*6777b538SAndroid Build Coastguard Worker session_->SendStreamWindowUpdate(
282*6777b538SAndroid Build Coastguard Worker stream_id_, static_cast<uint32_t>(unacked_recv_window_bytes_));
283*6777b538SAndroid Build Coastguard Worker unacked_recv_window_bytes_ = 0;
284*6777b538SAndroid Build Coastguard Worker }
285*6777b538SAndroid Build Coastguard Worker }
286*6777b538SAndroid Build Coastguard Worker
DecreaseRecvWindowSize(int32_t delta_window_size)287*6777b538SAndroid Build Coastguard Worker void SpdyStream::DecreaseRecvWindowSize(int32_t delta_window_size) {
288*6777b538SAndroid Build Coastguard Worker DCHECK(session_->IsStreamActive(stream_id_));
289*6777b538SAndroid Build Coastguard Worker DCHECK_GE(delta_window_size, 1);
290*6777b538SAndroid Build Coastguard Worker
291*6777b538SAndroid Build Coastguard Worker // The receiving window size as the peer knows it is
292*6777b538SAndroid Build Coastguard Worker // |recv_window_size_ - unacked_recv_window_bytes_|, if more data are sent by
293*6777b538SAndroid Build Coastguard Worker // the peer, that means that the receive window is not being respected.
294*6777b538SAndroid Build Coastguard Worker if (delta_window_size > recv_window_size_ - unacked_recv_window_bytes_) {
295*6777b538SAndroid Build Coastguard Worker session_->ResetStream(
296*6777b538SAndroid Build Coastguard Worker stream_id_, ERR_HTTP2_FLOW_CONTROL_ERROR,
297*6777b538SAndroid Build Coastguard Worker "delta_window_size is " + base::NumberToString(delta_window_size) +
298*6777b538SAndroid Build Coastguard Worker " in DecreaseRecvWindowSize, which is larger than the receive " +
299*6777b538SAndroid Build Coastguard Worker "window size of " + base::NumberToString(recv_window_size_));
300*6777b538SAndroid Build Coastguard Worker return;
301*6777b538SAndroid Build Coastguard Worker }
302*6777b538SAndroid Build Coastguard Worker
303*6777b538SAndroid Build Coastguard Worker recv_window_size_ -= delta_window_size;
304*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW, [&] {
305*6777b538SAndroid Build Coastguard Worker return NetLogSpdyStreamWindowUpdateParams(stream_id_, -delta_window_size,
306*6777b538SAndroid Build Coastguard Worker recv_window_size_);
307*6777b538SAndroid Build Coastguard Worker });
308*6777b538SAndroid Build Coastguard Worker }
309*6777b538SAndroid Build Coastguard Worker
GetPeerAddress(IPEndPoint * address) const310*6777b538SAndroid Build Coastguard Worker int SpdyStream::GetPeerAddress(IPEndPoint* address) const {
311*6777b538SAndroid Build Coastguard Worker return session_->GetPeerAddress(address);
312*6777b538SAndroid Build Coastguard Worker }
313*6777b538SAndroid Build Coastguard Worker
GetLocalAddress(IPEndPoint * address) const314*6777b538SAndroid Build Coastguard Worker int SpdyStream::GetLocalAddress(IPEndPoint* address) const {
315*6777b538SAndroid Build Coastguard Worker return session_->GetLocalAddress(address);
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker
WasEverUsed() const318*6777b538SAndroid Build Coastguard Worker bool SpdyStream::WasEverUsed() const {
319*6777b538SAndroid Build Coastguard Worker return session_->WasEverUsed();
320*6777b538SAndroid Build Coastguard Worker }
321*6777b538SAndroid Build Coastguard Worker
GetRequestTime() const322*6777b538SAndroid Build Coastguard Worker base::Time SpdyStream::GetRequestTime() const {
323*6777b538SAndroid Build Coastguard Worker return request_time_;
324*6777b538SAndroid Build Coastguard Worker }
325*6777b538SAndroid Build Coastguard Worker
SetRequestTime(base::Time t)326*6777b538SAndroid Build Coastguard Worker void SpdyStream::SetRequestTime(base::Time t) {
327*6777b538SAndroid Build Coastguard Worker request_time_ = t;
328*6777b538SAndroid Build Coastguard Worker }
329*6777b538SAndroid Build Coastguard Worker
OnHeadersReceived(const spdy::Http2HeaderBlock & response_headers,base::Time response_time,base::TimeTicks recv_first_byte_time)330*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnHeadersReceived(
331*6777b538SAndroid Build Coastguard Worker const spdy::Http2HeaderBlock& response_headers,
332*6777b538SAndroid Build Coastguard Worker base::Time response_time,
333*6777b538SAndroid Build Coastguard Worker base::TimeTicks recv_first_byte_time) {
334*6777b538SAndroid Build Coastguard Worker switch (response_state_) {
335*6777b538SAndroid Build Coastguard Worker case READY_FOR_HEADERS: {
336*6777b538SAndroid Build Coastguard Worker // No header block has been received yet.
337*6777b538SAndroid Build Coastguard Worker DCHECK(response_headers_.empty());
338*6777b538SAndroid Build Coastguard Worker
339*6777b538SAndroid Build Coastguard Worker spdy::Http2HeaderBlock::const_iterator it =
340*6777b538SAndroid Build Coastguard Worker response_headers.find(spdy::kHttp2StatusHeader);
341*6777b538SAndroid Build Coastguard Worker if (it == response_headers.end()) {
342*6777b538SAndroid Build Coastguard Worker const std::string error("Response headers do not include :status.");
343*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
344*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
345*6777b538SAndroid Build Coastguard Worker return;
346*6777b538SAndroid Build Coastguard Worker }
347*6777b538SAndroid Build Coastguard Worker
348*6777b538SAndroid Build Coastguard Worker int status;
349*6777b538SAndroid Build Coastguard Worker if (!base::StringToInt(it->second, &status)) {
350*6777b538SAndroid Build Coastguard Worker const std::string error("Cannot parse :status.");
351*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
352*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
353*6777b538SAndroid Build Coastguard Worker return;
354*6777b538SAndroid Build Coastguard Worker }
355*6777b538SAndroid Build Coastguard Worker
356*6777b538SAndroid Build Coastguard Worker base::UmaHistogramSparse("Net.SpdyResponseCode", status);
357*6777b538SAndroid Build Coastguard Worker
358*6777b538SAndroid Build Coastguard Worker // Include informational responses (1xx) in the TTFB as per the resource
359*6777b538SAndroid Build Coastguard Worker // timing spec for responseStart.
360*6777b538SAndroid Build Coastguard Worker if (recv_first_byte_time_.is_null())
361*6777b538SAndroid Build Coastguard Worker recv_first_byte_time_ = recv_first_byte_time;
362*6777b538SAndroid Build Coastguard Worker // Also record the TTFB of non-informational responses.
363*6777b538SAndroid Build Coastguard Worker if (status / 100 != 1) {
364*6777b538SAndroid Build Coastguard Worker DCHECK(recv_first_byte_time_for_non_informational_response_.is_null());
365*6777b538SAndroid Build Coastguard Worker recv_first_byte_time_for_non_informational_response_ =
366*6777b538SAndroid Build Coastguard Worker recv_first_byte_time;
367*6777b538SAndroid Build Coastguard Worker }
368*6777b538SAndroid Build Coastguard Worker
369*6777b538SAndroid Build Coastguard Worker // Handle informational responses (1xx):
370*6777b538SAndroid Build Coastguard Worker // * Pass through 101 Switching Protocols, because broken servers might
371*6777b538SAndroid Build Coastguard Worker // send this as a response to a WebSocket request, in which case it
372*6777b538SAndroid Build Coastguard Worker // needs to pass through so that the WebSocket layer can signal an
373*6777b538SAndroid Build Coastguard Worker // error.
374*6777b538SAndroid Build Coastguard Worker // * Plumb 103 Early Hints to the delegate.
375*6777b538SAndroid Build Coastguard Worker // * Ignore other informational responses.
376*6777b538SAndroid Build Coastguard Worker if (status / 100 == 1 && status != HTTP_SWITCHING_PROTOCOLS) {
377*6777b538SAndroid Build Coastguard Worker if (status == HTTP_EARLY_HINTS)
378*6777b538SAndroid Build Coastguard Worker OnEarlyHintsReceived(response_headers, recv_first_byte_time);
379*6777b538SAndroid Build Coastguard Worker return;
380*6777b538SAndroid Build Coastguard Worker }
381*6777b538SAndroid Build Coastguard Worker
382*6777b538SAndroid Build Coastguard Worker response_state_ = READY_FOR_DATA_OR_TRAILERS;
383*6777b538SAndroid Build Coastguard Worker
384*6777b538SAndroid Build Coastguard Worker switch (type_) {
385*6777b538SAndroid Build Coastguard Worker case SPDY_BIDIRECTIONAL_STREAM:
386*6777b538SAndroid Build Coastguard Worker case SPDY_REQUEST_RESPONSE_STREAM:
387*6777b538SAndroid Build Coastguard Worker // A bidirectional stream or a request/response stream is ready for
388*6777b538SAndroid Build Coastguard Worker // the response headers only after request headers are sent.
389*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_IDLE) {
390*6777b538SAndroid Build Coastguard Worker const std::string error("Response received before request sent.");
391*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
392*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
393*6777b538SAndroid Build Coastguard Worker return;
394*6777b538SAndroid Build Coastguard Worker }
395*6777b538SAndroid Build Coastguard Worker break;
396*6777b538SAndroid Build Coastguard Worker }
397*6777b538SAndroid Build Coastguard Worker
398*6777b538SAndroid Build Coastguard Worker DCHECK_NE(io_state_, STATE_IDLE);
399*6777b538SAndroid Build Coastguard Worker
400*6777b538SAndroid Build Coastguard Worker response_time_ = response_time;
401*6777b538SAndroid Build Coastguard Worker SaveResponseHeaders(response_headers, status);
402*6777b538SAndroid Build Coastguard Worker
403*6777b538SAndroid Build Coastguard Worker break;
404*6777b538SAndroid Build Coastguard Worker }
405*6777b538SAndroid Build Coastguard Worker case READY_FOR_DATA_OR_TRAILERS:
406*6777b538SAndroid Build Coastguard Worker // Second header block is trailers.
407*6777b538SAndroid Build Coastguard Worker response_state_ = TRAILERS_RECEIVED;
408*6777b538SAndroid Build Coastguard Worker delegate_->OnTrailers(response_headers);
409*6777b538SAndroid Build Coastguard Worker break;
410*6777b538SAndroid Build Coastguard Worker
411*6777b538SAndroid Build Coastguard Worker case TRAILERS_RECEIVED:
412*6777b538SAndroid Build Coastguard Worker // No further header blocks are allowed after trailers.
413*6777b538SAndroid Build Coastguard Worker const std::string error("Header block received after trailers.");
414*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
415*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
416*6777b538SAndroid Build Coastguard Worker break;
417*6777b538SAndroid Build Coastguard Worker }
418*6777b538SAndroid Build Coastguard Worker }
419*6777b538SAndroid Build Coastguard Worker
OnDataReceived(std::unique_ptr<SpdyBuffer> buffer)420*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
421*6777b538SAndroid Build Coastguard Worker DCHECK(session_->IsStreamActive(stream_id_));
422*6777b538SAndroid Build Coastguard Worker
423*6777b538SAndroid Build Coastguard Worker if (response_state_ == READY_FOR_HEADERS) {
424*6777b538SAndroid Build Coastguard Worker const std::string error("DATA received before headers.");
425*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
426*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
427*6777b538SAndroid Build Coastguard Worker return;
428*6777b538SAndroid Build Coastguard Worker }
429*6777b538SAndroid Build Coastguard Worker
430*6777b538SAndroid Build Coastguard Worker if (response_state_ == TRAILERS_RECEIVED && buffer) {
431*6777b538SAndroid Build Coastguard Worker const std::string error("DATA received after trailers.");
432*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
433*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
434*6777b538SAndroid Build Coastguard Worker return;
435*6777b538SAndroid Build Coastguard Worker }
436*6777b538SAndroid Build Coastguard Worker
437*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_HALF_CLOSED_REMOTE) {
438*6777b538SAndroid Build Coastguard Worker const std::string error("DATA received on half-closed (remove) stream.");
439*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_STREAM_CLOSED, error);
440*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_STREAM_CLOSED, error);
441*6777b538SAndroid Build Coastguard Worker return;
442*6777b538SAndroid Build Coastguard Worker }
443*6777b538SAndroid Build Coastguard Worker
444*6777b538SAndroid Build Coastguard Worker // Track our bandwidth.
445*6777b538SAndroid Build Coastguard Worker recv_bytes_ += buffer ? buffer->GetRemainingSize() : 0;
446*6777b538SAndroid Build Coastguard Worker recv_last_byte_time_ = base::TimeTicks::Now();
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker CHECK(!IsClosed());
449*6777b538SAndroid Build Coastguard Worker
450*6777b538SAndroid Build Coastguard Worker if (!buffer) {
451*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_OPEN) {
452*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_HALF_CLOSED_REMOTE;
453*6777b538SAndroid Build Coastguard Worker // Inform the delegate of EOF. This may delete |this|.
454*6777b538SAndroid Build Coastguard Worker delegate_->OnDataReceived(nullptr);
455*6777b538SAndroid Build Coastguard Worker } else if (io_state_ == STATE_HALF_CLOSED_LOCAL) {
456*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_CLOSED;
457*6777b538SAndroid Build Coastguard Worker // Deletes |this|.
458*6777b538SAndroid Build Coastguard Worker session_->CloseActiveStream(stream_id_, OK);
459*6777b538SAndroid Build Coastguard Worker } else {
460*6777b538SAndroid Build Coastguard Worker NOTREACHED() << io_state_;
461*6777b538SAndroid Build Coastguard Worker }
462*6777b538SAndroid Build Coastguard Worker return;
463*6777b538SAndroid Build Coastguard Worker }
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker size_t length = buffer->GetRemainingSize();
466*6777b538SAndroid Build Coastguard Worker DCHECK_LE(length, spdy::kHttp2DefaultFramePayloadLimit);
467*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
468*6777b538SAndroid Build Coastguard Worker // May close the stream.
469*6777b538SAndroid Build Coastguard Worker DecreaseRecvWindowSize(static_cast<int32_t>(length));
470*6777b538SAndroid Build Coastguard Worker if (!weak_this)
471*6777b538SAndroid Build Coastguard Worker return;
472*6777b538SAndroid Build Coastguard Worker buffer->AddConsumeCallback(
473*6777b538SAndroid Build Coastguard Worker base::BindRepeating(&SpdyStream::OnReadBufferConsumed, GetWeakPtr()));
474*6777b538SAndroid Build Coastguard Worker
475*6777b538SAndroid Build Coastguard Worker // May close |this|.
476*6777b538SAndroid Build Coastguard Worker delegate_->OnDataReceived(std::move(buffer));
477*6777b538SAndroid Build Coastguard Worker }
478*6777b538SAndroid Build Coastguard Worker
OnPaddingConsumed(size_t len)479*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnPaddingConsumed(size_t len) {
480*6777b538SAndroid Build Coastguard Worker // Decrease window size because padding bytes are received.
481*6777b538SAndroid Build Coastguard Worker // Increase window size because padding bytes are consumed (by discarding).
482*6777b538SAndroid Build Coastguard Worker // Net result: |unacked_recv_window_bytes_| increases by |len|,
483*6777b538SAndroid Build Coastguard Worker // |recv_window_size_| does not change.
484*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
485*6777b538SAndroid Build Coastguard Worker // May close the stream.
486*6777b538SAndroid Build Coastguard Worker DecreaseRecvWindowSize(static_cast<int32_t>(len));
487*6777b538SAndroid Build Coastguard Worker if (!weak_this)
488*6777b538SAndroid Build Coastguard Worker return;
489*6777b538SAndroid Build Coastguard Worker IncreaseRecvWindowSize(static_cast<int32_t>(len));
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker
OnFrameWriteComplete(spdy::SpdyFrameType frame_type,size_t frame_size)492*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnFrameWriteComplete(spdy::SpdyFrameType frame_type,
493*6777b538SAndroid Build Coastguard Worker size_t frame_size) {
494*6777b538SAndroid Build Coastguard Worker if (frame_type != spdy::SpdyFrameType::HEADERS &&
495*6777b538SAndroid Build Coastguard Worker frame_type != spdy::SpdyFrameType::DATA) {
496*6777b538SAndroid Build Coastguard Worker return;
497*6777b538SAndroid Build Coastguard Worker }
498*6777b538SAndroid Build Coastguard Worker
499*6777b538SAndroid Build Coastguard Worker int result = (frame_type == spdy::SpdyFrameType::HEADERS)
500*6777b538SAndroid Build Coastguard Worker ? OnHeadersSent()
501*6777b538SAndroid Build Coastguard Worker : OnDataSent(frame_size);
502*6777b538SAndroid Build Coastguard Worker if (result == ERR_IO_PENDING) {
503*6777b538SAndroid Build Coastguard Worker // The write operation hasn't completed yet.
504*6777b538SAndroid Build Coastguard Worker return;
505*6777b538SAndroid Build Coastguard Worker }
506*6777b538SAndroid Build Coastguard Worker
507*6777b538SAndroid Build Coastguard Worker if (pending_send_status_ == NO_MORE_DATA_TO_SEND) {
508*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_OPEN) {
509*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_HALF_CLOSED_LOCAL;
510*6777b538SAndroid Build Coastguard Worker } else if (io_state_ == STATE_HALF_CLOSED_REMOTE) {
511*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_CLOSED;
512*6777b538SAndroid Build Coastguard Worker } else {
513*6777b538SAndroid Build Coastguard Worker NOTREACHED() << io_state_;
514*6777b538SAndroid Build Coastguard Worker }
515*6777b538SAndroid Build Coastguard Worker }
516*6777b538SAndroid Build Coastguard Worker // Notify delegate of write completion. Must not destroy |this|.
517*6777b538SAndroid Build Coastguard Worker CHECK(delegate_);
518*6777b538SAndroid Build Coastguard Worker {
519*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
520*6777b538SAndroid Build Coastguard Worker write_handler_guard_ = true;
521*6777b538SAndroid Build Coastguard Worker if (frame_type == spdy::SpdyFrameType::HEADERS) {
522*6777b538SAndroid Build Coastguard Worker delegate_->OnHeadersSent();
523*6777b538SAndroid Build Coastguard Worker } else {
524*6777b538SAndroid Build Coastguard Worker delegate_->OnDataSent();
525*6777b538SAndroid Build Coastguard Worker }
526*6777b538SAndroid Build Coastguard Worker CHECK(weak_this);
527*6777b538SAndroid Build Coastguard Worker write_handler_guard_ = false;
528*6777b538SAndroid Build Coastguard Worker }
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_CLOSED) {
531*6777b538SAndroid Build Coastguard Worker // Deletes |this|.
532*6777b538SAndroid Build Coastguard Worker session_->CloseActiveStream(stream_id_, OK);
533*6777b538SAndroid Build Coastguard Worker }
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker
OnHeadersSent()536*6777b538SAndroid Build Coastguard Worker int SpdyStream::OnHeadersSent() {
537*6777b538SAndroid Build Coastguard Worker CHECK_EQ(io_state_, STATE_IDLE);
538*6777b538SAndroid Build Coastguard Worker CHECK_NE(stream_id_, 0u);
539*6777b538SAndroid Build Coastguard Worker
540*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_OPEN;
541*6777b538SAndroid Build Coastguard Worker return OK;
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker
OnDataSent(size_t frame_size)544*6777b538SAndroid Build Coastguard Worker int SpdyStream::OnDataSent(size_t frame_size) {
545*6777b538SAndroid Build Coastguard Worker CHECK(io_state_ == STATE_OPEN ||
546*6777b538SAndroid Build Coastguard Worker io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_;
547*6777b538SAndroid Build Coastguard Worker
548*6777b538SAndroid Build Coastguard Worker size_t frame_payload_size = frame_size - spdy::kDataFrameMinimumSize;
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker CHECK_GE(frame_size, spdy::kDataFrameMinimumSize);
551*6777b538SAndroid Build Coastguard Worker CHECK_LE(frame_payload_size, spdy::kHttp2DefaultFramePayloadLimit);
552*6777b538SAndroid Build Coastguard Worker
553*6777b538SAndroid Build Coastguard Worker // If more data is available to send, dispatch it and
554*6777b538SAndroid Build Coastguard Worker // return that the write operation is still ongoing.
555*6777b538SAndroid Build Coastguard Worker pending_send_data_->DidConsume(frame_payload_size);
556*6777b538SAndroid Build Coastguard Worker if (pending_send_data_->BytesRemaining() > 0) {
557*6777b538SAndroid Build Coastguard Worker QueueNextDataFrame();
558*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
559*6777b538SAndroid Build Coastguard Worker } else {
560*6777b538SAndroid Build Coastguard Worker pending_send_data_ = nullptr;
561*6777b538SAndroid Build Coastguard Worker return OK;
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker }
564*6777b538SAndroid Build Coastguard Worker
LogStreamError(int error,std::string_view description)565*6777b538SAndroid Build Coastguard Worker void SpdyStream::LogStreamError(int error, std::string_view description) {
566*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, [&] {
567*6777b538SAndroid Build Coastguard Worker return NetLogSpdyStreamErrorParams(stream_id_, error, description);
568*6777b538SAndroid Build Coastguard Worker });
569*6777b538SAndroid Build Coastguard Worker }
570*6777b538SAndroid Build Coastguard Worker
OnClose(int status)571*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnClose(int status) {
572*6777b538SAndroid Build Coastguard Worker // In most cases, the stream should already be CLOSED. The exception is when a
573*6777b538SAndroid Build Coastguard Worker // SpdySession is shutting down while the stream is in an intermediate state.
574*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_CLOSED;
575*6777b538SAndroid Build Coastguard Worker if (status == ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED) {
576*6777b538SAndroid Build Coastguard Worker if (response_state_ == READY_FOR_HEADERS) {
577*6777b538SAndroid Build Coastguard Worker status = ERR_HTTP2_PROTOCOL_ERROR;
578*6777b538SAndroid Build Coastguard Worker } else {
579*6777b538SAndroid Build Coastguard Worker status = OK;
580*6777b538SAndroid Build Coastguard Worker }
581*6777b538SAndroid Build Coastguard Worker }
582*6777b538SAndroid Build Coastguard Worker Delegate* delegate = delegate_;
583*6777b538SAndroid Build Coastguard Worker delegate_ = nullptr;
584*6777b538SAndroid Build Coastguard Worker if (delegate)
585*6777b538SAndroid Build Coastguard Worker delegate->OnClose(status);
586*6777b538SAndroid Build Coastguard Worker // Unset |stream_id_| last so that the delegate can look it up.
587*6777b538SAndroid Build Coastguard Worker stream_id_ = 0;
588*6777b538SAndroid Build Coastguard Worker }
589*6777b538SAndroid Build Coastguard Worker
Cancel(int error)590*6777b538SAndroid Build Coastguard Worker void SpdyStream::Cancel(int error) {
591*6777b538SAndroid Build Coastguard Worker // We may be called again from a delegate's OnClose().
592*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_CLOSED)
593*6777b538SAndroid Build Coastguard Worker return;
594*6777b538SAndroid Build Coastguard Worker
595*6777b538SAndroid Build Coastguard Worker if (stream_id_ != 0) {
596*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, error, std::string());
597*6777b538SAndroid Build Coastguard Worker } else {
598*6777b538SAndroid Build Coastguard Worker session_->CloseCreatedStream(GetWeakPtr(), error);
599*6777b538SAndroid Build Coastguard Worker }
600*6777b538SAndroid Build Coastguard Worker // |this| is invalid at this point.
601*6777b538SAndroid Build Coastguard Worker }
602*6777b538SAndroid Build Coastguard Worker
Close()603*6777b538SAndroid Build Coastguard Worker void SpdyStream::Close() {
604*6777b538SAndroid Build Coastguard Worker // We may be called again from a delegate's OnClose().
605*6777b538SAndroid Build Coastguard Worker if (io_state_ == STATE_CLOSED)
606*6777b538SAndroid Build Coastguard Worker return;
607*6777b538SAndroid Build Coastguard Worker
608*6777b538SAndroid Build Coastguard Worker if (stream_id_ != 0) {
609*6777b538SAndroid Build Coastguard Worker session_->CloseActiveStream(stream_id_, OK);
610*6777b538SAndroid Build Coastguard Worker } else {
611*6777b538SAndroid Build Coastguard Worker session_->CloseCreatedStream(GetWeakPtr(), OK);
612*6777b538SAndroid Build Coastguard Worker }
613*6777b538SAndroid Build Coastguard Worker // |this| is invalid at this point.
614*6777b538SAndroid Build Coastguard Worker }
615*6777b538SAndroid Build Coastguard Worker
GetWeakPtr()616*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() {
617*6777b538SAndroid Build Coastguard Worker return weak_ptr_factory_.GetWeakPtr();
618*6777b538SAndroid Build Coastguard Worker }
619*6777b538SAndroid Build Coastguard Worker
SendRequestHeaders(spdy::Http2HeaderBlock request_headers,SpdySendStatus send_status)620*6777b538SAndroid Build Coastguard Worker int SpdyStream::SendRequestHeaders(spdy::Http2HeaderBlock request_headers,
621*6777b538SAndroid Build Coastguard Worker SpdySendStatus send_status) {
622*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(
623*6777b538SAndroid Build Coastguard Worker NetLogEventType::HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS,
624*6777b538SAndroid Build Coastguard Worker [&](NetLogCaptureMode capture_mode) {
625*6777b538SAndroid Build Coastguard Worker return Http2HeaderBlockNetLogParams(&request_headers, capture_mode);
626*6777b538SAndroid Build Coastguard Worker });
627*6777b538SAndroid Build Coastguard Worker CHECK_EQ(pending_send_status_, MORE_DATA_TO_SEND);
628*6777b538SAndroid Build Coastguard Worker CHECK(!request_headers_valid_);
629*6777b538SAndroid Build Coastguard Worker CHECK(!pending_send_data_.get());
630*6777b538SAndroid Build Coastguard Worker CHECK_EQ(io_state_, STATE_IDLE);
631*6777b538SAndroid Build Coastguard Worker request_headers_ = std::move(request_headers);
632*6777b538SAndroid Build Coastguard Worker request_headers_valid_ = true;
633*6777b538SAndroid Build Coastguard Worker pending_send_status_ = send_status;
634*6777b538SAndroid Build Coastguard Worker session_->EnqueueStreamWrite(
635*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), spdy::SpdyFrameType::HEADERS,
636*6777b538SAndroid Build Coastguard Worker std::make_unique<HeadersBufferProducer>(GetWeakPtr()));
637*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
638*6777b538SAndroid Build Coastguard Worker }
639*6777b538SAndroid Build Coastguard Worker
SendData(IOBuffer * data,int length,SpdySendStatus send_status)640*6777b538SAndroid Build Coastguard Worker void SpdyStream::SendData(IOBuffer* data,
641*6777b538SAndroid Build Coastguard Worker int length,
642*6777b538SAndroid Build Coastguard Worker SpdySendStatus send_status) {
643*6777b538SAndroid Build Coastguard Worker CHECK_EQ(pending_send_status_, MORE_DATA_TO_SEND);
644*6777b538SAndroid Build Coastguard Worker CHECK(io_state_ == STATE_OPEN ||
645*6777b538SAndroid Build Coastguard Worker io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_;
646*6777b538SAndroid Build Coastguard Worker CHECK(!pending_send_data_.get());
647*6777b538SAndroid Build Coastguard Worker pending_send_data_ = base::MakeRefCounted<DrainableIOBuffer>(data, length);
648*6777b538SAndroid Build Coastguard Worker pending_send_status_ = send_status;
649*6777b538SAndroid Build Coastguard Worker QueueNextDataFrame();
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker
GetSSLInfo(SSLInfo * ssl_info) const652*6777b538SAndroid Build Coastguard Worker bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info) const {
653*6777b538SAndroid Build Coastguard Worker return session_->GetSSLInfo(ssl_info);
654*6777b538SAndroid Build Coastguard Worker }
655*6777b538SAndroid Build Coastguard Worker
GetNegotiatedProtocol() const656*6777b538SAndroid Build Coastguard Worker NextProto SpdyStream::GetNegotiatedProtocol() const {
657*6777b538SAndroid Build Coastguard Worker return session_->GetNegotiatedProtocol();
658*6777b538SAndroid Build Coastguard Worker }
659*6777b538SAndroid Build Coastguard Worker
PossiblyResumeIfSendStalled()660*6777b538SAndroid Build Coastguard Worker SpdyStream::ShouldRequeueStream SpdyStream::PossiblyResumeIfSendStalled() {
661*6777b538SAndroid Build Coastguard Worker if (IsLocallyClosed() || !send_stalled_by_flow_control_)
662*6777b538SAndroid Build Coastguard Worker return DoNotRequeue;
663*6777b538SAndroid Build Coastguard Worker if (session_->IsSendStalled() || send_window_size_ <= 0) {
664*6777b538SAndroid Build Coastguard Worker return Requeue;
665*6777b538SAndroid Build Coastguard Worker }
666*6777b538SAndroid Build Coastguard Worker net_log_.AddEventWithIntParams(
667*6777b538SAndroid Build Coastguard Worker NetLogEventType::HTTP2_STREAM_FLOW_CONTROL_UNSTALLED, "stream_id",
668*6777b538SAndroid Build Coastguard Worker stream_id_);
669*6777b538SAndroid Build Coastguard Worker send_stalled_by_flow_control_ = false;
670*6777b538SAndroid Build Coastguard Worker QueueNextDataFrame();
671*6777b538SAndroid Build Coastguard Worker return DoNotRequeue;
672*6777b538SAndroid Build Coastguard Worker }
673*6777b538SAndroid Build Coastguard Worker
IsClosed() const674*6777b538SAndroid Build Coastguard Worker bool SpdyStream::IsClosed() const {
675*6777b538SAndroid Build Coastguard Worker return io_state_ == STATE_CLOSED;
676*6777b538SAndroid Build Coastguard Worker }
677*6777b538SAndroid Build Coastguard Worker
IsLocallyClosed() const678*6777b538SAndroid Build Coastguard Worker bool SpdyStream::IsLocallyClosed() const {
679*6777b538SAndroid Build Coastguard Worker return io_state_ == STATE_HALF_CLOSED_LOCAL || io_state_ == STATE_CLOSED;
680*6777b538SAndroid Build Coastguard Worker }
681*6777b538SAndroid Build Coastguard Worker
IsIdle() const682*6777b538SAndroid Build Coastguard Worker bool SpdyStream::IsIdle() const {
683*6777b538SAndroid Build Coastguard Worker return io_state_ == STATE_IDLE;
684*6777b538SAndroid Build Coastguard Worker }
685*6777b538SAndroid Build Coastguard Worker
IsOpen() const686*6777b538SAndroid Build Coastguard Worker bool SpdyStream::IsOpen() const {
687*6777b538SAndroid Build Coastguard Worker return io_state_ == STATE_OPEN;
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker
IsReservedRemote() const690*6777b538SAndroid Build Coastguard Worker bool SpdyStream::IsReservedRemote() const {
691*6777b538SAndroid Build Coastguard Worker return io_state_ == STATE_RESERVED_REMOTE;
692*6777b538SAndroid Build Coastguard Worker }
693*6777b538SAndroid Build Coastguard Worker
AddRawReceivedBytes(size_t received_bytes)694*6777b538SAndroid Build Coastguard Worker void SpdyStream::AddRawReceivedBytes(size_t received_bytes) {
695*6777b538SAndroid Build Coastguard Worker raw_received_bytes_ += received_bytes;
696*6777b538SAndroid Build Coastguard Worker }
697*6777b538SAndroid Build Coastguard Worker
AddRawSentBytes(size_t sent_bytes)698*6777b538SAndroid Build Coastguard Worker void SpdyStream::AddRawSentBytes(size_t sent_bytes) {
699*6777b538SAndroid Build Coastguard Worker raw_sent_bytes_ += sent_bytes;
700*6777b538SAndroid Build Coastguard Worker }
701*6777b538SAndroid Build Coastguard Worker
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const702*6777b538SAndroid Build Coastguard Worker bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
703*6777b538SAndroid Build Coastguard Worker if (stream_id_ == 0)
704*6777b538SAndroid Build Coastguard Worker return false;
705*6777b538SAndroid Build Coastguard Worker bool result = session_->GetLoadTimingInfo(stream_id_, load_timing_info);
706*6777b538SAndroid Build Coastguard Worker // TODO(acomminos): recv_first_byte_time_ is actually the time after all
707*6777b538SAndroid Build Coastguard Worker // headers have been parsed. We should add support for reporting the time the
708*6777b538SAndroid Build Coastguard Worker // first bytes of the HEADERS frame were received to BufferedSpdyFramer
709*6777b538SAndroid Build Coastguard Worker // (https://crbug.com/568024).
710*6777b538SAndroid Build Coastguard Worker load_timing_info->receive_headers_start = recv_first_byte_time_;
711*6777b538SAndroid Build Coastguard Worker load_timing_info->receive_non_informational_headers_start =
712*6777b538SAndroid Build Coastguard Worker recv_first_byte_time_for_non_informational_response_;
713*6777b538SAndroid Build Coastguard Worker load_timing_info->first_early_hints_time = first_early_hints_time_;
714*6777b538SAndroid Build Coastguard Worker return result;
715*6777b538SAndroid Build Coastguard Worker }
716*6777b538SAndroid Build Coastguard Worker
QueueNextDataFrame()717*6777b538SAndroid Build Coastguard Worker void SpdyStream::QueueNextDataFrame() {
718*6777b538SAndroid Build Coastguard Worker // Until the request has been completely sent, we cannot be sure
719*6777b538SAndroid Build Coastguard Worker // that our stream_id is correct.
720*6777b538SAndroid Build Coastguard Worker CHECK(io_state_ == STATE_OPEN ||
721*6777b538SAndroid Build Coastguard Worker io_state_ == STATE_HALF_CLOSED_REMOTE) << io_state_;
722*6777b538SAndroid Build Coastguard Worker CHECK_GT(stream_id_, 0u);
723*6777b538SAndroid Build Coastguard Worker CHECK(pending_send_data_.get());
724*6777b538SAndroid Build Coastguard Worker // Only the final fame may have a length of 0.
725*6777b538SAndroid Build Coastguard Worker if (pending_send_status_ == NO_MORE_DATA_TO_SEND) {
726*6777b538SAndroid Build Coastguard Worker CHECK_GE(pending_send_data_->BytesRemaining(), 0);
727*6777b538SAndroid Build Coastguard Worker } else {
728*6777b538SAndroid Build Coastguard Worker CHECK_GT(pending_send_data_->BytesRemaining(), 0);
729*6777b538SAndroid Build Coastguard Worker }
730*6777b538SAndroid Build Coastguard Worker
731*6777b538SAndroid Build Coastguard Worker spdy::SpdyDataFlags flags = (pending_send_status_ == NO_MORE_DATA_TO_SEND)
732*6777b538SAndroid Build Coastguard Worker ? spdy::DATA_FLAG_FIN
733*6777b538SAndroid Build Coastguard Worker : spdy::DATA_FLAG_NONE;
734*6777b538SAndroid Build Coastguard Worker int effective_len;
735*6777b538SAndroid Build Coastguard Worker bool end_stream;
736*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBuffer> data_buffer(
737*6777b538SAndroid Build Coastguard Worker session_->CreateDataBuffer(stream_id_, pending_send_data_.get(),
738*6777b538SAndroid Build Coastguard Worker pending_send_data_->BytesRemaining(), flags,
739*6777b538SAndroid Build Coastguard Worker &effective_len, &end_stream));
740*6777b538SAndroid Build Coastguard Worker // We'll get called again by PossiblyResumeIfSendStalled().
741*6777b538SAndroid Build Coastguard Worker if (!data_buffer)
742*6777b538SAndroid Build Coastguard Worker return;
743*6777b538SAndroid Build Coastguard Worker
744*6777b538SAndroid Build Coastguard Worker DCHECK_GE(data_buffer->GetRemainingSize(), spdy::kDataFrameMinimumSize);
745*6777b538SAndroid Build Coastguard Worker size_t payload_size =
746*6777b538SAndroid Build Coastguard Worker data_buffer->GetRemainingSize() - spdy::kDataFrameMinimumSize;
747*6777b538SAndroid Build Coastguard Worker DCHECK_LE(payload_size, spdy::kHttp2DefaultFramePayloadLimit);
748*6777b538SAndroid Build Coastguard Worker
749*6777b538SAndroid Build Coastguard Worker // Send window size is based on payload size, so nothing to do if this is
750*6777b538SAndroid Build Coastguard Worker // just a FIN with no payload.
751*6777b538SAndroid Build Coastguard Worker if (payload_size != 0) {
752*6777b538SAndroid Build Coastguard Worker DecreaseSendWindowSize(static_cast<int32_t>(payload_size));
753*6777b538SAndroid Build Coastguard Worker // This currently isn't strictly needed, since write frames are
754*6777b538SAndroid Build Coastguard Worker // discarded only if the stream is about to be closed. But have it
755*6777b538SAndroid Build Coastguard Worker // here anyway just in case this changes.
756*6777b538SAndroid Build Coastguard Worker data_buffer->AddConsumeCallback(base::BindRepeating(
757*6777b538SAndroid Build Coastguard Worker &SpdyStream::OnWriteBufferConsumed, GetWeakPtr(), payload_size));
758*6777b538SAndroid Build Coastguard Worker }
759*6777b538SAndroid Build Coastguard Worker
760*6777b538SAndroid Build Coastguard Worker if (session_->GreasedFramesEnabled() && delegate_ &&
761*6777b538SAndroid Build Coastguard Worker delegate_->CanGreaseFrameType()) {
762*6777b538SAndroid Build Coastguard Worker session_->EnqueueGreasedFrame(GetWeakPtr());
763*6777b538SAndroid Build Coastguard Worker }
764*6777b538SAndroid Build Coastguard Worker
765*6777b538SAndroid Build Coastguard Worker session_->net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA, [&] {
766*6777b538SAndroid Build Coastguard Worker return NetLogSpdyDataParams(stream_id_, effective_len, end_stream);
767*6777b538SAndroid Build Coastguard Worker });
768*6777b538SAndroid Build Coastguard Worker
769*6777b538SAndroid Build Coastguard Worker session_->EnqueueStreamWrite(
770*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), spdy::SpdyFrameType::DATA,
771*6777b538SAndroid Build Coastguard Worker std::make_unique<SimpleBufferProducer>(std::move(data_buffer)));
772*6777b538SAndroid Build Coastguard Worker }
773*6777b538SAndroid Build Coastguard Worker
OnEarlyHintsReceived(const spdy::Http2HeaderBlock & response_headers,base::TimeTicks recv_first_byte_time)774*6777b538SAndroid Build Coastguard Worker void SpdyStream::OnEarlyHintsReceived(
775*6777b538SAndroid Build Coastguard Worker const spdy::Http2HeaderBlock& response_headers,
776*6777b538SAndroid Build Coastguard Worker base::TimeTicks recv_first_byte_time) {
777*6777b538SAndroid Build Coastguard Worker // Record the timing of the 103 Early Hints response for the experiment
778*6777b538SAndroid Build Coastguard Worker // (https://crbug.com/1093693).
779*6777b538SAndroid Build Coastguard Worker if (first_early_hints_time_.is_null())
780*6777b538SAndroid Build Coastguard Worker first_early_hints_time_ = recv_first_byte_time;
781*6777b538SAndroid Build Coastguard Worker
782*6777b538SAndroid Build Coastguard Worker // Transfer-encoding is a connection specific header.
783*6777b538SAndroid Build Coastguard Worker if (response_headers.find("transfer-encoding") != response_headers.end()) {
784*6777b538SAndroid Build Coastguard Worker const char error[] = "Received transfer-encoding header";
785*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
786*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
787*6777b538SAndroid Build Coastguard Worker return;
788*6777b538SAndroid Build Coastguard Worker }
789*6777b538SAndroid Build Coastguard Worker
790*6777b538SAndroid Build Coastguard Worker if (type_ != SPDY_REQUEST_RESPONSE_STREAM || io_state_ == STATE_IDLE) {
791*6777b538SAndroid Build Coastguard Worker const char error[] = "Early Hints received before request sent.";
792*6777b538SAndroid Build Coastguard Worker LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, error);
793*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR, error);
794*6777b538SAndroid Build Coastguard Worker return;
795*6777b538SAndroid Build Coastguard Worker }
796*6777b538SAndroid Build Coastguard Worker
797*6777b538SAndroid Build Coastguard Worker // `delegate_` must be attached at this point when `type_` is
798*6777b538SAndroid Build Coastguard Worker // SPDY_REQUEST_RESPONSE_STREAM.
799*6777b538SAndroid Build Coastguard Worker CHECK(delegate_);
800*6777b538SAndroid Build Coastguard Worker delegate_->OnEarlyHintsReceived(response_headers);
801*6777b538SAndroid Build Coastguard Worker }
802*6777b538SAndroid Build Coastguard Worker
SaveResponseHeaders(const spdy::Http2HeaderBlock & response_headers,int status)803*6777b538SAndroid Build Coastguard Worker void SpdyStream::SaveResponseHeaders(
804*6777b538SAndroid Build Coastguard Worker const spdy::Http2HeaderBlock& response_headers,
805*6777b538SAndroid Build Coastguard Worker int status) {
806*6777b538SAndroid Build Coastguard Worker if (response_headers.contains("transfer-encoding")) {
807*6777b538SAndroid Build Coastguard Worker session_->ResetStream(stream_id_, ERR_HTTP2_PROTOCOL_ERROR,
808*6777b538SAndroid Build Coastguard Worker "Received transfer-encoding header");
809*6777b538SAndroid Build Coastguard Worker return;
810*6777b538SAndroid Build Coastguard Worker }
811*6777b538SAndroid Build Coastguard Worker
812*6777b538SAndroid Build Coastguard Worker DCHECK(response_headers_.empty());
813*6777b538SAndroid Build Coastguard Worker response_headers_ = response_headers.Clone();
814*6777b538SAndroid Build Coastguard Worker
815*6777b538SAndroid Build Coastguard Worker // If delegate is not yet attached, OnHeadersReceived() will be called after
816*6777b538SAndroid Build Coastguard Worker // the delegate gets attached to the stream.
817*6777b538SAndroid Build Coastguard Worker if (!delegate_)
818*6777b538SAndroid Build Coastguard Worker return;
819*6777b538SAndroid Build Coastguard Worker
820*6777b538SAndroid Build Coastguard Worker delegate_->OnHeadersReceived(response_headers_);
821*6777b538SAndroid Build Coastguard Worker }
822*6777b538SAndroid Build Coastguard Worker
823*6777b538SAndroid Build Coastguard Worker #define STATE_CASE(s) \
824*6777b538SAndroid Build Coastguard Worker case s: \
825*6777b538SAndroid Build Coastguard Worker description = base::StringPrintf("%s (0x%08X)", #s, s); \
826*6777b538SAndroid Build Coastguard Worker break
827*6777b538SAndroid Build Coastguard Worker
DescribeState(State state)828*6777b538SAndroid Build Coastguard Worker std::string SpdyStream::DescribeState(State state) {
829*6777b538SAndroid Build Coastguard Worker std::string description;
830*6777b538SAndroid Build Coastguard Worker switch (state) {
831*6777b538SAndroid Build Coastguard Worker STATE_CASE(STATE_IDLE);
832*6777b538SAndroid Build Coastguard Worker STATE_CASE(STATE_OPEN);
833*6777b538SAndroid Build Coastguard Worker STATE_CASE(STATE_HALF_CLOSED_LOCAL);
834*6777b538SAndroid Build Coastguard Worker STATE_CASE(STATE_CLOSED);
835*6777b538SAndroid Build Coastguard Worker default:
836*6777b538SAndroid Build Coastguard Worker description =
837*6777b538SAndroid Build Coastguard Worker base::StringPrintf("Unknown state 0x%08X (%u)", state, state);
838*6777b538SAndroid Build Coastguard Worker break;
839*6777b538SAndroid Build Coastguard Worker }
840*6777b538SAndroid Build Coastguard Worker return description;
841*6777b538SAndroid Build Coastguard Worker }
842*6777b538SAndroid Build Coastguard Worker
843*6777b538SAndroid Build Coastguard Worker #undef STATE_CASE
844*6777b538SAndroid Build Coastguard Worker
845*6777b538SAndroid Build Coastguard Worker } // namespace net
846