xref: /aosp_15_r20/external/cronet/net/spdy/spdy_session.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_session.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <limits>
8*6777b538SAndroid Build Coastguard Worker #include <map>
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker #include <tuple>
12*6777b538SAndroid Build Coastguard Worker #include <utility>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/contains.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/memory_usage_estimator.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
33*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
34*6777b538SAndroid Build Coastguard Worker #include "net/base/proxy_chain.h"
35*6777b538SAndroid Build Coastguard Worker #include "net/base/proxy_string_util.h"
36*6777b538SAndroid Build Coastguard Worker #include "net/base/tracing.h"
37*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
38*6777b538SAndroid Build Coastguard Worker #include "net/cert/asn1_util.h"
39*6777b538SAndroid Build Coastguard Worker #include "net/cert/cert_verify_result.h"
40*6777b538SAndroid Build Coastguard Worker #include "net/cert/ct_policy_status.h"
41*6777b538SAndroid Build Coastguard Worker #include "net/http/http_network_session.h"
42*6777b538SAndroid Build Coastguard Worker #include "net/http/http_server_properties.h"
43*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
44*6777b538SAndroid Build Coastguard Worker #include "net/http/http_vary_data.h"
45*6777b538SAndroid Build Coastguard Worker #include "net/http/transport_security_state.h"
46*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log.h"
47*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_capture_mode.h"
48*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
49*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_source_type.h"
50*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_with_source.h"
51*6777b538SAndroid Build Coastguard Worker #include "net/nqe/network_quality_estimator.h"
52*6777b538SAndroid Build Coastguard Worker #include "net/quic/quic_http_utils.h"
53*6777b538SAndroid Build Coastguard Worker #include "net/socket/client_socket_handle.h"
54*6777b538SAndroid Build Coastguard Worker #include "net/socket/socket.h"
55*6777b538SAndroid Build Coastguard Worker #include "net/socket/ssl_client_socket.h"
56*6777b538SAndroid Build Coastguard Worker #include "net/spdy/alps_decoder.h"
57*6777b538SAndroid Build Coastguard Worker #include "net/spdy/header_coalescer.h"
58*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_buffer_producer.h"
59*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_http_utils.h"
60*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_log_util.h"
61*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_session_pool.h"
62*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_stream.h"
63*6777b538SAndroid Build Coastguard Worker #include "net/ssl/ssl_cipher_suite_names.h"
64*6777b538SAndroid Build Coastguard Worker #include "net/ssl/ssl_connection_status_flags.h"
65*6777b538SAndroid Build Coastguard Worker #include "net/third_party/quiche/src/quiche/spdy/core/spdy_frame_builder.h"
66*6777b538SAndroid Build Coastguard Worker #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
67*6777b538SAndroid Build Coastguard Worker #include "url/scheme_host_port.h"
68*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
69*6777b538SAndroid Build Coastguard Worker 
70*6777b538SAndroid Build Coastguard Worker namespace net {
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker namespace {
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker constexpr net::NetworkTrafficAnnotationTag
75*6777b538SAndroid Build Coastguard Worker     kSpdySessionCommandsTrafficAnnotation =
76*6777b538SAndroid Build Coastguard Worker         net::DefineNetworkTrafficAnnotation("spdy_session_control", R"(
77*6777b538SAndroid Build Coastguard Worker         semantics {
78*6777b538SAndroid Build Coastguard Worker           sender: "Spdy Session"
79*6777b538SAndroid Build Coastguard Worker           description:
80*6777b538SAndroid Build Coastguard Worker             "Sends commands to control an HTTP/2 session."
81*6777b538SAndroid Build Coastguard Worker           trigger:
82*6777b538SAndroid Build Coastguard Worker             "Required control commands like initiating stream, requesting "
83*6777b538SAndroid Build Coastguard Worker             "stream reset, changing priorities, etc."
84*6777b538SAndroid Build Coastguard Worker           data: "No user data."
85*6777b538SAndroid Build Coastguard Worker           destination: OTHER
86*6777b538SAndroid Build Coastguard Worker           destination_other:
87*6777b538SAndroid Build Coastguard Worker             "Any destination the HTTP/2 session is connected to."
88*6777b538SAndroid Build Coastguard Worker         }
89*6777b538SAndroid Build Coastguard Worker         policy {
90*6777b538SAndroid Build Coastguard Worker           cookies_allowed: NO
91*6777b538SAndroid Build Coastguard Worker           setting: "This feature cannot be disabled in settings."
92*6777b538SAndroid Build Coastguard Worker           policy_exception_justification: "Essential for network access."
93*6777b538SAndroid Build Coastguard Worker         }
94*6777b538SAndroid Build Coastguard Worker     )");
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker const int kReadBufferSize = 8 * 1024;
97*6777b538SAndroid Build Coastguard Worker const int kDefaultConnectionAtRiskOfLossSeconds = 10;
98*6777b538SAndroid Build Coastguard Worker const int kHungIntervalSeconds = 10;
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker // Default initial value for HTTP/2 SETTINGS.
101*6777b538SAndroid Build Coastguard Worker const uint32_t kDefaultInitialHeaderTableSize = 4096;
102*6777b538SAndroid Build Coastguard Worker const uint32_t kDefaultInitialEnablePush = 1;
103*6777b538SAndroid Build Coastguard Worker const uint32_t kDefaultInitialInitialWindowSize = 65535;
104*6777b538SAndroid Build Coastguard Worker const uint32_t kDefaultInitialMaxFrameSize = 16384;
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker // These values are persisted to logs. Entries should not be renumbered, and
107*6777b538SAndroid Build Coastguard Worker // numeric values should never be reused.
108*6777b538SAndroid Build Coastguard Worker enum class SpdyAcceptChEntries {
109*6777b538SAndroid Build Coastguard Worker   kNoEntries = 0,
110*6777b538SAndroid Build Coastguard Worker   kOnlyValidEntries = 1,
111*6777b538SAndroid Build Coastguard Worker   kOnlyInvalidEntries = 2,
112*6777b538SAndroid Build Coastguard Worker   kBothValidAndInvalidEntries = 3,
113*6777b538SAndroid Build Coastguard Worker   kMaxValue = kBothValidAndInvalidEntries,
114*6777b538SAndroid Build Coastguard Worker };
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker // A SpdyBufferProducer implementation that creates an HTTP/2 frame by adding
117*6777b538SAndroid Build Coastguard Worker // stream ID to greased frame parameters.
118*6777b538SAndroid Build Coastguard Worker class GreasedBufferProducer : public SpdyBufferProducer {
119*6777b538SAndroid Build Coastguard Worker  public:
120*6777b538SAndroid Build Coastguard Worker   GreasedBufferProducer() = delete;
GreasedBufferProducer(base::WeakPtr<SpdyStream> stream,const SpdySessionPool::GreasedHttp2Frame * greased_http2_frame,BufferedSpdyFramer * buffered_spdy_framer)121*6777b538SAndroid Build Coastguard Worker   GreasedBufferProducer(
122*6777b538SAndroid Build Coastguard Worker       base::WeakPtr<SpdyStream> stream,
123*6777b538SAndroid Build Coastguard Worker       const SpdySessionPool::GreasedHttp2Frame* greased_http2_frame,
124*6777b538SAndroid Build Coastguard Worker       BufferedSpdyFramer* buffered_spdy_framer)
125*6777b538SAndroid Build Coastguard Worker       : stream_(stream),
126*6777b538SAndroid Build Coastguard Worker         greased_http2_frame_(greased_http2_frame),
127*6777b538SAndroid Build Coastguard Worker         buffered_spdy_framer_(buffered_spdy_framer) {}
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker   ~GreasedBufferProducer() override = default;
130*6777b538SAndroid Build Coastguard Worker 
ProduceBuffer()131*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
132*6777b538SAndroid Build Coastguard Worker     const spdy::SpdyStreamId stream_id = stream_ ? stream_->stream_id() : 0;
133*6777b538SAndroid Build Coastguard Worker     spdy::SpdyUnknownIR frame(stream_id, greased_http2_frame_->type,
134*6777b538SAndroid Build Coastguard Worker                               greased_http2_frame_->flags,
135*6777b538SAndroid Build Coastguard Worker                               greased_http2_frame_->payload);
136*6777b538SAndroid Build Coastguard Worker     auto serialized_frame = std::make_unique<spdy::SpdySerializedFrame>(
137*6777b538SAndroid Build Coastguard Worker         buffered_spdy_framer_->SerializeFrame(frame));
138*6777b538SAndroid Build Coastguard Worker     return std::make_unique<SpdyBuffer>(std::move(serialized_frame));
139*6777b538SAndroid Build Coastguard Worker   }
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker  private:
142*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<SpdyStream> stream_;
143*6777b538SAndroid Build Coastguard Worker   const raw_ptr<const SpdySessionPool::GreasedHttp2Frame> greased_http2_frame_;
144*6777b538SAndroid Build Coastguard Worker   raw_ptr<BufferedSpdyFramer> buffered_spdy_framer_;
145*6777b538SAndroid Build Coastguard Worker };
146*6777b538SAndroid Build Coastguard Worker 
IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,uint32_t value)147*6777b538SAndroid Build Coastguard Worker bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,
148*6777b538SAndroid Build Coastguard Worker                                         uint32_t value) {
149*6777b538SAndroid Build Coastguard Worker   switch (setting_id) {
150*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_HEADER_TABLE_SIZE:
151*6777b538SAndroid Build Coastguard Worker       return value == kDefaultInitialHeaderTableSize;
152*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_ENABLE_PUSH:
153*6777b538SAndroid Build Coastguard Worker       return value == kDefaultInitialEnablePush;
154*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
155*6777b538SAndroid Build Coastguard Worker       // There is no initial limit on the number of concurrent streams.
156*6777b538SAndroid Build Coastguard Worker       return false;
157*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_INITIAL_WINDOW_SIZE:
158*6777b538SAndroid Build Coastguard Worker       return value == kDefaultInitialInitialWindowSize;
159*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_MAX_FRAME_SIZE:
160*6777b538SAndroid Build Coastguard Worker       return value == kDefaultInitialMaxFrameSize;
161*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_MAX_HEADER_LIST_SIZE:
162*6777b538SAndroid Build Coastguard Worker       // There is no initial limit on the size of the header list.
163*6777b538SAndroid Build Coastguard Worker       return false;
164*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL:
165*6777b538SAndroid Build Coastguard Worker       return value == 0;
166*6777b538SAndroid Build Coastguard Worker     default:
167*6777b538SAndroid Build Coastguard Worker       // Undefined parameters have no initial value.
168*6777b538SAndroid Build Coastguard Worker       return false;
169*6777b538SAndroid Build Coastguard Worker   }
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker 
LogSpdyAcceptChForOriginHistogram(bool value)172*6777b538SAndroid Build Coastguard Worker void LogSpdyAcceptChForOriginHistogram(bool value) {
173*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramBoolean("Net.SpdySession.AcceptChForOrigin", value);
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyHeadersSentParams(const spdy::Http2HeaderBlock * headers,bool fin,spdy::SpdyStreamId stream_id,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,NetLogSource source_dependency,NetLogCaptureMode capture_mode)176*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyHeadersSentParams(
177*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock* headers,
178*6777b538SAndroid Build Coastguard Worker     bool fin,
179*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
180*6777b538SAndroid Build Coastguard Worker     bool has_priority,
181*6777b538SAndroid Build Coastguard Worker     int weight,
182*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId parent_stream_id,
183*6777b538SAndroid Build Coastguard Worker     bool exclusive,
184*6777b538SAndroid Build Coastguard Worker     NetLogSource source_dependency,
185*6777b538SAndroid Build Coastguard Worker     NetLogCaptureMode capture_mode) {
186*6777b538SAndroid Build Coastguard Worker   auto dict = base::Value::Dict()
187*6777b538SAndroid Build Coastguard Worker                   .Set("headers",
188*6777b538SAndroid Build Coastguard Worker                        ElideHttp2HeaderBlockForNetLog(*headers, capture_mode))
189*6777b538SAndroid Build Coastguard Worker                   .Set("fin", fin)
190*6777b538SAndroid Build Coastguard Worker                   .Set("stream_id", static_cast<int>(stream_id))
191*6777b538SAndroid Build Coastguard Worker                   .Set("has_priority", has_priority);
192*6777b538SAndroid Build Coastguard Worker   if (has_priority) {
193*6777b538SAndroid Build Coastguard Worker     dict.Set("parent_stream_id", static_cast<int>(parent_stream_id));
194*6777b538SAndroid Build Coastguard Worker     dict.Set("weight", weight);
195*6777b538SAndroid Build Coastguard Worker     dict.Set("exclusive", exclusive);
196*6777b538SAndroid Build Coastguard Worker   }
197*6777b538SAndroid Build Coastguard Worker   if (source_dependency.IsValid()) {
198*6777b538SAndroid Build Coastguard Worker     source_dependency.AddToEventParameters(dict);
199*6777b538SAndroid Build Coastguard Worker   }
200*6777b538SAndroid Build Coastguard Worker   return dict;
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyHeadersReceivedParams(const spdy::Http2HeaderBlock * headers,bool fin,spdy::SpdyStreamId stream_id,NetLogCaptureMode capture_mode)203*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyHeadersReceivedParams(
204*6777b538SAndroid Build Coastguard Worker     const spdy::Http2HeaderBlock* headers,
205*6777b538SAndroid Build Coastguard Worker     bool fin,
206*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
207*6777b538SAndroid Build Coastguard Worker     NetLogCaptureMode capture_mode) {
208*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
209*6777b538SAndroid Build Coastguard Worker       .Set("headers", ElideHttp2HeaderBlockForNetLog(*headers, capture_mode))
210*6777b538SAndroid Build Coastguard Worker       .Set("fin", fin)
211*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id));
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySessionCloseParams(int net_error,const std::string & description)214*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySessionCloseParams(int net_error,
215*6777b538SAndroid Build Coastguard Worker                                                const std::string& description) {
216*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
217*6777b538SAndroid Build Coastguard Worker       .Set("net_error", net_error)
218*6777b538SAndroid Build Coastguard Worker       .Set("description", description);
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySessionParams(const HostPortProxyPair & host_pair)221*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySessionParams(const HostPortProxyPair& host_pair) {
222*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
223*6777b538SAndroid Build Coastguard Worker       .Set("host", host_pair.first.ToString())
224*6777b538SAndroid Build Coastguard Worker       .Set("proxy", host_pair.second.ToDebugString());
225*6777b538SAndroid Build Coastguard Worker }
226*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyInitializedParams(NetLogSource source)227*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyInitializedParams(NetLogSource source) {
228*6777b538SAndroid Build Coastguard Worker   base::Value::Dict dict;
229*6777b538SAndroid Build Coastguard Worker   if (source.IsValid()) {
230*6777b538SAndroid Build Coastguard Worker     source.AddToEventParameters(dict);
231*6777b538SAndroid Build Coastguard Worker   }
232*6777b538SAndroid Build Coastguard Worker   dict.Set("protocol", NextProtoToString(kProtoHTTP2));
233*6777b538SAndroid Build Coastguard Worker   return dict;
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySendSettingsParams(const spdy::SettingsMap * settings)236*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySendSettingsParams(
237*6777b538SAndroid Build Coastguard Worker     const spdy::SettingsMap* settings) {
238*6777b538SAndroid Build Coastguard Worker   base::Value::List settings_list;
239*6777b538SAndroid Build Coastguard Worker   for (const auto& setting : *settings) {
240*6777b538SAndroid Build Coastguard Worker     const spdy::SpdySettingsId id = setting.first;
241*6777b538SAndroid Build Coastguard Worker     const uint32_t value = setting.second;
242*6777b538SAndroid Build Coastguard Worker     settings_list.Append(
243*6777b538SAndroid Build Coastguard Worker         base::StringPrintf("[id:%u (%s) value:%u]", id,
244*6777b538SAndroid Build Coastguard Worker                            spdy::SettingsIdToString(id).c_str(), value));
245*6777b538SAndroid Build Coastguard Worker   }
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict().Set("settings", std::move(settings_list));
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyRecvAcceptChParams(spdy::AcceptChOriginValuePair entry)250*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyRecvAcceptChParams(
251*6777b538SAndroid Build Coastguard Worker     spdy::AcceptChOriginValuePair entry) {
252*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
253*6777b538SAndroid Build Coastguard Worker       .Set("origin", entry.origin)
254*6777b538SAndroid Build Coastguard Worker       .Set("accept_ch", entry.value);
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyRecvSettingParams(spdy::SpdySettingsId id,uint32_t value)257*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyRecvSettingParams(spdy::SpdySettingsId id,
258*6777b538SAndroid Build Coastguard Worker                                               uint32_t value) {
259*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
260*6777b538SAndroid Build Coastguard Worker       .Set("id", base::StringPrintf("%u (%s)", id,
261*6777b538SAndroid Build Coastguard Worker                                     spdy::SettingsIdToString(id).c_str()))
262*6777b538SAndroid Build Coastguard Worker       .Set("value", static_cast<int>(value));
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyWindowUpdateFrameParams(spdy::SpdyStreamId stream_id,uint32_t delta)265*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyWindowUpdateFrameParams(
266*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
267*6777b538SAndroid Build Coastguard Worker     uint32_t delta) {
268*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
269*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
270*6777b538SAndroid Build Coastguard Worker       .Set("delta", static_cast<int>(delta));
271*6777b538SAndroid Build Coastguard Worker }
272*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySessionWindowUpdateParams(int32_t delta,int32_t window_size)273*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySessionWindowUpdateParams(int32_t delta,
274*6777b538SAndroid Build Coastguard Worker                                                       int32_t window_size) {
275*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
276*6777b538SAndroid Build Coastguard Worker       .Set("delta", delta)
277*6777b538SAndroid Build Coastguard Worker       .Set("window_size", window_size);
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyDataParams(spdy::SpdyStreamId stream_id,int size,bool fin)280*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyDataParams(spdy::SpdyStreamId stream_id,
281*6777b538SAndroid Build Coastguard Worker                                        int size,
282*6777b538SAndroid Build Coastguard Worker                                        bool fin) {
283*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
284*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
285*6777b538SAndroid Build Coastguard Worker       .Set("size", size)
286*6777b538SAndroid Build Coastguard Worker       .Set("fin", fin);
287*6777b538SAndroid Build Coastguard Worker }
288*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyRecvRstStreamParams(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)289*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyRecvRstStreamParams(
290*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
291*6777b538SAndroid Build Coastguard Worker     spdy::SpdyErrorCode error_code) {
292*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
293*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
294*6777b538SAndroid Build Coastguard Worker       .Set("error_code", base::StringPrintf("%u (%s)", error_code,
295*6777b538SAndroid Build Coastguard Worker                                             ErrorCodeToString(error_code)));
296*6777b538SAndroid Build Coastguard Worker }
297*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySendRstStreamParams(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code,const std::string & description)298*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySendRstStreamParams(
299*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
300*6777b538SAndroid Build Coastguard Worker     spdy::SpdyErrorCode error_code,
301*6777b538SAndroid Build Coastguard Worker     const std::string& description) {
302*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
303*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
304*6777b538SAndroid Build Coastguard Worker       .Set("error_code", base::StringPrintf("%u (%s)", error_code,
305*6777b538SAndroid Build Coastguard Worker                                             ErrorCodeToString(error_code)))
306*6777b538SAndroid Build Coastguard Worker       .Set("description", description);
307*6777b538SAndroid Build Coastguard Worker }
308*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyPingParams(spdy::SpdyPingId unique_id,bool is_ack,const char * type)309*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyPingParams(spdy::SpdyPingId unique_id,
310*6777b538SAndroid Build Coastguard Worker                                        bool is_ack,
311*6777b538SAndroid Build Coastguard Worker                                        const char* type) {
312*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
313*6777b538SAndroid Build Coastguard Worker       .Set("unique_id", static_cast<int>(unique_id))
314*6777b538SAndroid Build Coastguard Worker       .Set("type", type)
315*6777b538SAndroid Build Coastguard Worker       .Set("is_ack", is_ack);
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyRecvGoAwayParams(spdy::SpdyStreamId last_stream_id,int active_streams,spdy::SpdyErrorCode error_code,std::string_view debug_data,NetLogCaptureMode capture_mode)318*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyRecvGoAwayParams(spdy::SpdyStreamId last_stream_id,
319*6777b538SAndroid Build Coastguard Worker                                              int active_streams,
320*6777b538SAndroid Build Coastguard Worker                                              spdy::SpdyErrorCode error_code,
321*6777b538SAndroid Build Coastguard Worker                                              std::string_view debug_data,
322*6777b538SAndroid Build Coastguard Worker                                              NetLogCaptureMode capture_mode) {
323*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
324*6777b538SAndroid Build Coastguard Worker       .Set("last_accepted_stream_id", static_cast<int>(last_stream_id))
325*6777b538SAndroid Build Coastguard Worker       .Set("active_streams", active_streams)
326*6777b538SAndroid Build Coastguard Worker       .Set("error_code", base::StringPrintf("%u (%s)", error_code,
327*6777b538SAndroid Build Coastguard Worker                                             ErrorCodeToString(error_code)))
328*6777b538SAndroid Build Coastguard Worker       .Set("debug_data",
329*6777b538SAndroid Build Coastguard Worker            ElideGoAwayDebugDataForNetLog(capture_mode, debug_data));
330*6777b538SAndroid Build Coastguard Worker }
331*6777b538SAndroid Build Coastguard Worker 
NetLogSpdySessionStalledParams(size_t num_active_streams,size_t num_created_streams,size_t max_concurrent_streams,const std::string & url)332*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdySessionStalledParams(size_t num_active_streams,
333*6777b538SAndroid Build Coastguard Worker                                                  size_t num_created_streams,
334*6777b538SAndroid Build Coastguard Worker                                                  size_t max_concurrent_streams,
335*6777b538SAndroid Build Coastguard Worker                                                  const std::string& url) {
336*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
337*6777b538SAndroid Build Coastguard Worker       .Set("num_active_streams", static_cast<int>(num_active_streams))
338*6777b538SAndroid Build Coastguard Worker       .Set("num_created_streams", static_cast<int>(num_created_streams))
339*6777b538SAndroid Build Coastguard Worker       .Set("max_concurrent_streams", static_cast<int>(max_concurrent_streams))
340*6777b538SAndroid Build Coastguard Worker       .Set("url", url);
341*6777b538SAndroid Build Coastguard Worker }
342*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyPriorityParams(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId parent_stream_id,int weight,bool exclusive)343*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyPriorityParams(spdy::SpdyStreamId stream_id,
344*6777b538SAndroid Build Coastguard Worker                                            spdy::SpdyStreamId parent_stream_id,
345*6777b538SAndroid Build Coastguard Worker                                            int weight,
346*6777b538SAndroid Build Coastguard Worker                                            bool exclusive) {
347*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
348*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
349*6777b538SAndroid Build Coastguard Worker       .Set("parent_stream_id", static_cast<int>(parent_stream_id))
350*6777b538SAndroid Build Coastguard Worker       .Set("weight", weight)
351*6777b538SAndroid Build Coastguard Worker       .Set("exclusive", exclusive);
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker 
NetLogSpdyGreasedFrameParams(spdy::SpdyStreamId stream_id,uint8_t type,uint8_t flags,size_t length,RequestPriority priority)354*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogSpdyGreasedFrameParams(spdy::SpdyStreamId stream_id,
355*6777b538SAndroid Build Coastguard Worker                                                uint8_t type,
356*6777b538SAndroid Build Coastguard Worker                                                uint8_t flags,
357*6777b538SAndroid Build Coastguard Worker                                                size_t length,
358*6777b538SAndroid Build Coastguard Worker                                                RequestPriority priority) {
359*6777b538SAndroid Build Coastguard Worker   return base::Value::Dict()
360*6777b538SAndroid Build Coastguard Worker       .Set("stream_id", static_cast<int>(stream_id))
361*6777b538SAndroid Build Coastguard Worker       .Set("type", type)
362*6777b538SAndroid Build Coastguard Worker       .Set("flags", flags)
363*6777b538SAndroid Build Coastguard Worker       .Set("length", static_cast<int>(length))
364*6777b538SAndroid Build Coastguard Worker       .Set("priority", RequestPriorityToString(priority));
365*6777b538SAndroid Build Coastguard Worker }
366*6777b538SAndroid Build Coastguard Worker 
367*6777b538SAndroid Build Coastguard Worker // Helper function to return the total size of an array of objects
368*6777b538SAndroid Build Coastguard Worker // with .size() member functions.
369*6777b538SAndroid Build Coastguard Worker template <typename T, size_t N>
GetTotalSize(const T (& arr)[N])370*6777b538SAndroid Build Coastguard Worker size_t GetTotalSize(const T (&arr)[N]) {
371*6777b538SAndroid Build Coastguard Worker   size_t total_size = 0;
372*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < N; ++i) {
373*6777b538SAndroid Build Coastguard Worker     total_size += arr[i].size();
374*6777b538SAndroid Build Coastguard Worker   }
375*6777b538SAndroid Build Coastguard Worker   return total_size;
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker 
378*6777b538SAndroid Build Coastguard Worker // The maximum number of concurrent streams we will ever create.  Even if
379*6777b538SAndroid Build Coastguard Worker // the server permits more, we will never exceed this limit.
380*6777b538SAndroid Build Coastguard Worker const size_t kMaxConcurrentStreamLimit = 256;
381*6777b538SAndroid Build Coastguard Worker 
382*6777b538SAndroid Build Coastguard Worker }  // namespace
383*6777b538SAndroid Build Coastguard Worker 
384*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kH2InitialMaxConcurrentStreamsOverride,
385*6777b538SAndroid Build Coastguard Worker              "H2InitialMaxConcurrentStreamsOverride",
386*6777b538SAndroid Build Coastguard Worker              base::FEATURE_DISABLED_BY_DEFAULT);
387*6777b538SAndroid Build Coastguard Worker 
388*6777b538SAndroid Build Coastguard Worker const base::FeatureParam<int> kH2InitialMaxConcurrentStreams(
389*6777b538SAndroid Build Coastguard Worker     &kH2InitialMaxConcurrentStreamsOverride,
390*6777b538SAndroid Build Coastguard Worker     "initial_max_concurrent_streams",
391*6777b538SAndroid Build Coastguard Worker     kDefaultInitialMaxConcurrentStreams);
392*6777b538SAndroid Build Coastguard Worker 
MapFramerErrorToProtocolError(http2::Http2DecoderAdapter::SpdyFramerError err)393*6777b538SAndroid Build Coastguard Worker SpdyProtocolErrorDetails MapFramerErrorToProtocolError(
394*6777b538SAndroid Build Coastguard Worker     http2::Http2DecoderAdapter::SpdyFramerError err) {
395*6777b538SAndroid Build Coastguard Worker   switch (err) {
396*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_NO_ERROR:
397*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_NO_ERROR;
398*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_STREAM_ID:
399*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INVALID_STREAM_ID;
400*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME:
401*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INVALID_CONTROL_FRAME;
402*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_CONTROL_PAYLOAD_TOO_LARGE:
403*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_CONTROL_PAYLOAD_TOO_LARGE;
404*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_DECOMPRESS_FAILURE:
405*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_DECOMPRESS_FAILURE;
406*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_PADDING:
407*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INVALID_PADDING;
408*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_DATA_FRAME_FLAGS:
409*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INVALID_DATA_FRAME_FLAGS;
410*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME:
411*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_UNEXPECTED_FRAME;
412*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INTERNAL_FRAMER_ERROR:
413*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INTERNAL_FRAMER_ERROR;
414*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE:
415*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_INVALID_CONTROL_FRAME_SIZE;
416*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_OVERSIZED_PAYLOAD:
417*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_OVERSIZED_PAYLOAD;
418*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INDEX_VARINT_ERROR:
419*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_INDEX_VARINT_ERROR;
420*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_LENGTH_VARINT_ERROR:
421*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_NAME_LENGTH_VARINT_ERROR;
422*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR:
423*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_VALUE_LENGTH_VARINT_ERROR;
424*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_TOO_LONG:
425*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_NAME_TOO_LONG;
426*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_TOO_LONG:
427*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_VALUE_TOO_LONG;
428*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_HUFFMAN_ERROR:
429*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_NAME_HUFFMAN_ERROR;
430*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_HUFFMAN_ERROR:
431*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_VALUE_HUFFMAN_ERROR;
432*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
433*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
434*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE;
435*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INVALID_INDEX:
436*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_INVALID_INDEX;
437*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INVALID_NAME_INDEX:
438*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_INVALID_NAME_INDEX;
439*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
440*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
441*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED;
442*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
443*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
444*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK;
445*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
446*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
447*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING;
448*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_TRUNCATED_BLOCK:
449*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_TRUNCATED_BLOCK;
450*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_FRAGMENT_TOO_LONG:
451*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_FRAGMENT_TOO_LONG;
452*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
453*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
454*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT;
455*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_STOP_PROCESSING:
456*6777b538SAndroid Build Coastguard Worker       return SPDY_ERROR_STOP_PROCESSING;
457*6777b538SAndroid Build Coastguard Worker 
458*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::LAST_ERROR:
459*6777b538SAndroid Build Coastguard Worker       NOTREACHED();
460*6777b538SAndroid Build Coastguard Worker   }
461*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
462*6777b538SAndroid Build Coastguard Worker   return static_cast<SpdyProtocolErrorDetails>(-1);
463*6777b538SAndroid Build Coastguard Worker }
464*6777b538SAndroid Build Coastguard Worker 
MapFramerErrorToNetError(http2::Http2DecoderAdapter::SpdyFramerError err)465*6777b538SAndroid Build Coastguard Worker Error MapFramerErrorToNetError(
466*6777b538SAndroid Build Coastguard Worker     http2::Http2DecoderAdapter::SpdyFramerError err) {
467*6777b538SAndroid Build Coastguard Worker   switch (err) {
468*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_NO_ERROR:
469*6777b538SAndroid Build Coastguard Worker       return OK;
470*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME:
471*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
472*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_CONTROL_PAYLOAD_TOO_LARGE:
473*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_FRAME_SIZE_ERROR;
474*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_DECOMPRESS_FAILURE:
475*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INDEX_VARINT_ERROR:
476*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_LENGTH_VARINT_ERROR:
477*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR:
478*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_TOO_LONG:
479*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_TOO_LONG:
480*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_NAME_HUFFMAN_ERROR:
481*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_VALUE_HUFFMAN_ERROR:
482*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
483*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
484*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INVALID_INDEX:
485*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_INVALID_NAME_INDEX:
486*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
487*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
488*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
489*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
490*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
491*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
492*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_TRUNCATED_BLOCK:
493*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_HPACK_FRAGMENT_TOO_LONG:
494*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::
495*6777b538SAndroid Build Coastguard Worker         SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
496*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_COMPRESSION_ERROR;
497*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_STOP_PROCESSING:
498*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_COMPRESSION_ERROR;
499*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_PADDING:
500*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
501*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_DATA_FRAME_FLAGS:
502*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
503*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME:
504*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
505*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INTERNAL_FRAMER_ERROR:
506*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
507*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE:
508*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_FRAME_SIZE_ERROR;
509*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_INVALID_STREAM_ID:
510*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_PROTOCOL_ERROR;
511*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::SPDY_OVERSIZED_PAYLOAD:
512*6777b538SAndroid Build Coastguard Worker       return ERR_HTTP2_FRAME_SIZE_ERROR;
513*6777b538SAndroid Build Coastguard Worker     case http2::Http2DecoderAdapter::LAST_ERROR:
514*6777b538SAndroid Build Coastguard Worker       NOTREACHED();
515*6777b538SAndroid Build Coastguard Worker   }
516*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
517*6777b538SAndroid Build Coastguard Worker   return ERR_HTTP2_PROTOCOL_ERROR;
518*6777b538SAndroid Build Coastguard Worker }
519*6777b538SAndroid Build Coastguard Worker 
MapRstStreamStatusToProtocolError(spdy::SpdyErrorCode error_code)520*6777b538SAndroid Build Coastguard Worker SpdyProtocolErrorDetails MapRstStreamStatusToProtocolError(
521*6777b538SAndroid Build Coastguard Worker     spdy::SpdyErrorCode error_code) {
522*6777b538SAndroid Build Coastguard Worker   switch (error_code) {
523*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_NO_ERROR:
524*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_NO_ERROR;
525*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_PROTOCOL_ERROR:
526*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_PROTOCOL_ERROR;
527*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_INTERNAL_ERROR:
528*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_INTERNAL_ERROR;
529*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_FLOW_CONTROL_ERROR:
530*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_FLOW_CONTROL_ERROR;
531*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_SETTINGS_TIMEOUT:
532*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_SETTINGS_TIMEOUT;
533*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_STREAM_CLOSED:
534*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_STREAM_CLOSED;
535*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_FRAME_SIZE_ERROR:
536*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_FRAME_SIZE_ERROR;
537*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_REFUSED_STREAM:
538*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_REFUSED_STREAM;
539*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_CANCEL:
540*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_CANCEL;
541*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_COMPRESSION_ERROR:
542*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_COMPRESSION_ERROR;
543*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_CONNECT_ERROR:
544*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_CONNECT_ERROR;
545*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_ENHANCE_YOUR_CALM:
546*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_ENHANCE_YOUR_CALM;
547*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_INADEQUATE_SECURITY:
548*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_INADEQUATE_SECURITY;
549*6777b538SAndroid Build Coastguard Worker     case spdy::ERROR_CODE_HTTP_1_1_REQUIRED:
550*6777b538SAndroid Build Coastguard Worker       return STATUS_CODE_HTTP_1_1_REQUIRED;
551*6777b538SAndroid Build Coastguard Worker   }
552*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
553*6777b538SAndroid Build Coastguard Worker   return static_cast<SpdyProtocolErrorDetails>(-1);
554*6777b538SAndroid Build Coastguard Worker }
555*6777b538SAndroid Build Coastguard Worker 
MapNetErrorToGoAwayStatus(Error err)556*6777b538SAndroid Build Coastguard Worker spdy::SpdyErrorCode MapNetErrorToGoAwayStatus(Error err) {
557*6777b538SAndroid Build Coastguard Worker   switch (err) {
558*6777b538SAndroid Build Coastguard Worker     case OK:
559*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_NO_ERROR;
560*6777b538SAndroid Build Coastguard Worker     case ERR_HTTP2_PROTOCOL_ERROR:
561*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_PROTOCOL_ERROR;
562*6777b538SAndroid Build Coastguard Worker     case ERR_HTTP2_FLOW_CONTROL_ERROR:
563*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_FLOW_CONTROL_ERROR;
564*6777b538SAndroid Build Coastguard Worker     case ERR_HTTP2_FRAME_SIZE_ERROR:
565*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_FRAME_SIZE_ERROR;
566*6777b538SAndroid Build Coastguard Worker     case ERR_HTTP2_COMPRESSION_ERROR:
567*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_COMPRESSION_ERROR;
568*6777b538SAndroid Build Coastguard Worker     case ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY:
569*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_INADEQUATE_SECURITY;
570*6777b538SAndroid Build Coastguard Worker     default:
571*6777b538SAndroid Build Coastguard Worker       return spdy::ERROR_CODE_PROTOCOL_ERROR;
572*6777b538SAndroid Build Coastguard Worker   }
573*6777b538SAndroid Build Coastguard Worker }
574*6777b538SAndroid Build Coastguard Worker 
SpdyStreamRequest()575*6777b538SAndroid Build Coastguard Worker SpdyStreamRequest::SpdyStreamRequest() {
576*6777b538SAndroid Build Coastguard Worker   Reset();
577*6777b538SAndroid Build Coastguard Worker }
578*6777b538SAndroid Build Coastguard Worker 
~SpdyStreamRequest()579*6777b538SAndroid Build Coastguard Worker SpdyStreamRequest::~SpdyStreamRequest() {
580*6777b538SAndroid Build Coastguard Worker   CancelRequest();
581*6777b538SAndroid Build Coastguard Worker }
582*6777b538SAndroid Build Coastguard Worker 
StartRequest(SpdyStreamType type,const base::WeakPtr<SpdySession> & session,const GURL & url,bool can_send_early,RequestPriority priority,const SocketTag & socket_tag,const NetLogWithSource & net_log,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation,bool detect_broken_connection,base::TimeDelta heartbeat_interval)583*6777b538SAndroid Build Coastguard Worker int SpdyStreamRequest::StartRequest(
584*6777b538SAndroid Build Coastguard Worker     SpdyStreamType type,
585*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdySession>& session,
586*6777b538SAndroid Build Coastguard Worker     const GURL& url,
587*6777b538SAndroid Build Coastguard Worker     bool can_send_early,
588*6777b538SAndroid Build Coastguard Worker     RequestPriority priority,
589*6777b538SAndroid Build Coastguard Worker     const SocketTag& socket_tag,
590*6777b538SAndroid Build Coastguard Worker     const NetLogWithSource& net_log,
591*6777b538SAndroid Build Coastguard Worker     CompletionOnceCallback callback,
592*6777b538SAndroid Build Coastguard Worker     const NetworkTrafficAnnotationTag& traffic_annotation,
593*6777b538SAndroid Build Coastguard Worker     bool detect_broken_connection,
594*6777b538SAndroid Build Coastguard Worker     base::TimeDelta heartbeat_interval) {
595*6777b538SAndroid Build Coastguard Worker   DCHECK(session);
596*6777b538SAndroid Build Coastguard Worker   DCHECK(!session_);
597*6777b538SAndroid Build Coastguard Worker   DCHECK(!stream_);
598*6777b538SAndroid Build Coastguard Worker   DCHECK(callback_.is_null());
599*6777b538SAndroid Build Coastguard Worker   DCHECK(url.is_valid()) << url.possibly_invalid_spec();
600*6777b538SAndroid Build Coastguard Worker 
601*6777b538SAndroid Build Coastguard Worker   type_ = type;
602*6777b538SAndroid Build Coastguard Worker   session_ = session;
603*6777b538SAndroid Build Coastguard Worker   url_ = SimplifyUrlForRequest(url);
604*6777b538SAndroid Build Coastguard Worker   priority_ = priority;
605*6777b538SAndroid Build Coastguard Worker   socket_tag_ = socket_tag;
606*6777b538SAndroid Build Coastguard Worker   net_log_ = net_log;
607*6777b538SAndroid Build Coastguard Worker   callback_ = std::move(callback);
608*6777b538SAndroid Build Coastguard Worker   traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation);
609*6777b538SAndroid Build Coastguard Worker   detect_broken_connection_ = detect_broken_connection;
610*6777b538SAndroid Build Coastguard Worker   heartbeat_interval_ = heartbeat_interval;
611*6777b538SAndroid Build Coastguard Worker 
612*6777b538SAndroid Build Coastguard Worker   // If early data is not allowed, confirm the handshake first.
613*6777b538SAndroid Build Coastguard Worker   int rv = OK;
614*6777b538SAndroid Build Coastguard Worker   if (!can_send_early) {
615*6777b538SAndroid Build Coastguard Worker     rv = session_->ConfirmHandshake(
616*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&SpdyStreamRequest::OnConfirmHandshakeComplete,
617*6777b538SAndroid Build Coastguard Worker                        weak_ptr_factory_.GetWeakPtr()));
618*6777b538SAndroid Build Coastguard Worker   }
619*6777b538SAndroid Build Coastguard Worker   if (rv != OK) {
620*6777b538SAndroid Build Coastguard Worker     // If rv is ERR_IO_PENDING, OnConfirmHandshakeComplete() will call
621*6777b538SAndroid Build Coastguard Worker     // TryCreateStream() later.
622*6777b538SAndroid Build Coastguard Worker     return rv;
623*6777b538SAndroid Build Coastguard Worker   }
624*6777b538SAndroid Build Coastguard Worker 
625*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<SpdyStream> stream;
626*6777b538SAndroid Build Coastguard Worker   rv = session->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
627*6777b538SAndroid Build Coastguard Worker   if (rv != OK) {
628*6777b538SAndroid Build Coastguard Worker     // If rv is ERR_IO_PENDING, the SpdySession will call
629*6777b538SAndroid Build Coastguard Worker     // OnRequestCompleteSuccess() or OnRequestCompleteFailure() later.
630*6777b538SAndroid Build Coastguard Worker     return rv;
631*6777b538SAndroid Build Coastguard Worker   }
632*6777b538SAndroid Build Coastguard Worker 
633*6777b538SAndroid Build Coastguard Worker   Reset();
634*6777b538SAndroid Build Coastguard Worker   stream_ = stream;
635*6777b538SAndroid Build Coastguard Worker   return OK;
636*6777b538SAndroid Build Coastguard Worker }
637*6777b538SAndroid Build Coastguard Worker 
CancelRequest()638*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::CancelRequest() {
639*6777b538SAndroid Build Coastguard Worker   if (session_)
640*6777b538SAndroid Build Coastguard Worker     session_->CancelStreamRequest(weak_ptr_factory_.GetWeakPtr());
641*6777b538SAndroid Build Coastguard Worker   Reset();
642*6777b538SAndroid Build Coastguard Worker   // Do this to cancel any pending CompleteStreamRequest() and
643*6777b538SAndroid Build Coastguard Worker   // OnConfirmHandshakeComplete() tasks.
644*6777b538SAndroid Build Coastguard Worker   weak_ptr_factory_.InvalidateWeakPtrs();
645*6777b538SAndroid Build Coastguard Worker }
646*6777b538SAndroid Build Coastguard Worker 
ReleaseStream()647*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() {
648*6777b538SAndroid Build Coastguard Worker   DCHECK(!session_);
649*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<SpdyStream> stream = stream_;
650*6777b538SAndroid Build Coastguard Worker   DCHECK(stream);
651*6777b538SAndroid Build Coastguard Worker   Reset();
652*6777b538SAndroid Build Coastguard Worker   return stream;
653*6777b538SAndroid Build Coastguard Worker }
654*6777b538SAndroid Build Coastguard Worker 
SetPriority(RequestPriority priority)655*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::SetPriority(RequestPriority priority) {
656*6777b538SAndroid Build Coastguard Worker   if (priority_ == priority)
657*6777b538SAndroid Build Coastguard Worker     return;
658*6777b538SAndroid Build Coastguard Worker 
659*6777b538SAndroid Build Coastguard Worker   if (stream_)
660*6777b538SAndroid Build Coastguard Worker     stream_->SetPriority(priority);
661*6777b538SAndroid Build Coastguard Worker   if (session_)
662*6777b538SAndroid Build Coastguard Worker     session_->ChangeStreamRequestPriority(weak_ptr_factory_.GetWeakPtr(),
663*6777b538SAndroid Build Coastguard Worker                                           priority);
664*6777b538SAndroid Build Coastguard Worker   priority_ = priority;
665*6777b538SAndroid Build Coastguard Worker }
666*6777b538SAndroid Build Coastguard Worker 
OnRequestCompleteSuccess(const base::WeakPtr<SpdyStream> & stream)667*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::OnRequestCompleteSuccess(
668*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStream>& stream) {
669*6777b538SAndroid Build Coastguard Worker   DCHECK(session_);
670*6777b538SAndroid Build Coastguard Worker   DCHECK(!stream_);
671*6777b538SAndroid Build Coastguard Worker   DCHECK(!callback_.is_null());
672*6777b538SAndroid Build Coastguard Worker   CompletionOnceCallback callback = std::move(callback_);
673*6777b538SAndroid Build Coastguard Worker   Reset();
674*6777b538SAndroid Build Coastguard Worker   DCHECK(stream);
675*6777b538SAndroid Build Coastguard Worker   stream_ = stream;
676*6777b538SAndroid Build Coastguard Worker   std::move(callback).Run(OK);
677*6777b538SAndroid Build Coastguard Worker }
678*6777b538SAndroid Build Coastguard Worker 
OnRequestCompleteFailure(int rv)679*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::OnRequestCompleteFailure(int rv) {
680*6777b538SAndroid Build Coastguard Worker   DCHECK(session_);
681*6777b538SAndroid Build Coastguard Worker   DCHECK(!stream_);
682*6777b538SAndroid Build Coastguard Worker   DCHECK(!callback_.is_null());
683*6777b538SAndroid Build Coastguard Worker   CompletionOnceCallback callback = std::move(callback_);
684*6777b538SAndroid Build Coastguard Worker   Reset();
685*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(rv, OK);
686*6777b538SAndroid Build Coastguard Worker   std::move(callback).Run(rv);
687*6777b538SAndroid Build Coastguard Worker }
688*6777b538SAndroid Build Coastguard Worker 
Reset()689*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::Reset() {
690*6777b538SAndroid Build Coastguard Worker   type_ = SPDY_BIDIRECTIONAL_STREAM;
691*6777b538SAndroid Build Coastguard Worker   session_.reset();
692*6777b538SAndroid Build Coastguard Worker   stream_.reset();
693*6777b538SAndroid Build Coastguard Worker   url_ = GURL();
694*6777b538SAndroid Build Coastguard Worker   priority_ = MINIMUM_PRIORITY;
695*6777b538SAndroid Build Coastguard Worker   socket_tag_ = SocketTag();
696*6777b538SAndroid Build Coastguard Worker   net_log_ = NetLogWithSource();
697*6777b538SAndroid Build Coastguard Worker   callback_.Reset();
698*6777b538SAndroid Build Coastguard Worker   traffic_annotation_.reset();
699*6777b538SAndroid Build Coastguard Worker }
700*6777b538SAndroid Build Coastguard Worker 
OnConfirmHandshakeComplete(int rv)701*6777b538SAndroid Build Coastguard Worker void SpdyStreamRequest::OnConfirmHandshakeComplete(int rv) {
702*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(ERR_IO_PENDING, rv);
703*6777b538SAndroid Build Coastguard Worker   if (!session_)
704*6777b538SAndroid Build Coastguard Worker     return;
705*6777b538SAndroid Build Coastguard Worker 
706*6777b538SAndroid Build Coastguard Worker   if (rv != OK) {
707*6777b538SAndroid Build Coastguard Worker     OnRequestCompleteFailure(rv);
708*6777b538SAndroid Build Coastguard Worker     return;
709*6777b538SAndroid Build Coastguard Worker   }
710*6777b538SAndroid Build Coastguard Worker 
711*6777b538SAndroid Build Coastguard Worker   // ConfirmHandshake() completed asynchronously. Record the time so the caller
712*6777b538SAndroid Build Coastguard Worker   // can adjust LoadTimingInfo.
713*6777b538SAndroid Build Coastguard Worker   confirm_handshake_end_ = base::TimeTicks::Now();
714*6777b538SAndroid Build Coastguard Worker 
715*6777b538SAndroid Build Coastguard Worker   if (!session_) {
716*6777b538SAndroid Build Coastguard Worker     OnRequestCompleteFailure(ERR_CONNECTION_CLOSED);
717*6777b538SAndroid Build Coastguard Worker     return;
718*6777b538SAndroid Build Coastguard Worker   }
719*6777b538SAndroid Build Coastguard Worker 
720*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<SpdyStream> stream;
721*6777b538SAndroid Build Coastguard Worker   rv = session_->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
722*6777b538SAndroid Build Coastguard Worker   if (rv == OK) {
723*6777b538SAndroid Build Coastguard Worker     OnRequestCompleteSuccess(stream);
724*6777b538SAndroid Build Coastguard Worker   } else if (rv != ERR_IO_PENDING) {
725*6777b538SAndroid Build Coastguard Worker     // If rv is ERR_IO_PENDING, the SpdySession will call
726*6777b538SAndroid Build Coastguard Worker     // OnRequestCompleteSuccess() or OnRequestCompleteFailure() later.
727*6777b538SAndroid Build Coastguard Worker     OnRequestCompleteFailure(rv);
728*6777b538SAndroid Build Coastguard Worker   }
729*6777b538SAndroid Build Coastguard Worker }
730*6777b538SAndroid Build Coastguard Worker 
731*6777b538SAndroid Build Coastguard Worker // static
CanPool(TransportSecurityState * transport_security_state,const SSLInfo & ssl_info,const SSLConfigService & ssl_config_service,std::string_view old_hostname,std::string_view new_hostname)732*6777b538SAndroid Build Coastguard Worker bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
733*6777b538SAndroid Build Coastguard Worker                           const SSLInfo& ssl_info,
734*6777b538SAndroid Build Coastguard Worker                           const SSLConfigService& ssl_config_service,
735*6777b538SAndroid Build Coastguard Worker                           std::string_view old_hostname,
736*6777b538SAndroid Build Coastguard Worker                           std::string_view new_hostname) {
737*6777b538SAndroid Build Coastguard Worker   // Pooling is prohibited if the server cert is not valid for the new domain,
738*6777b538SAndroid Build Coastguard Worker   // and for connections on which client certs were sent. It is also prohibited
739*6777b538SAndroid Build Coastguard Worker   // when channel ID was sent if the hosts are from different eTLDs+1.
740*6777b538SAndroid Build Coastguard Worker   if (IsCertStatusError(ssl_info.cert_status))
741*6777b538SAndroid Build Coastguard Worker     return false;
742*6777b538SAndroid Build Coastguard Worker 
743*6777b538SAndroid Build Coastguard Worker   if (ssl_info.client_cert_sent &&
744*6777b538SAndroid Build Coastguard Worker       !(ssl_config_service.CanShareConnectionWithClientCerts(old_hostname) &&
745*6777b538SAndroid Build Coastguard Worker         ssl_config_service.CanShareConnectionWithClientCerts(new_hostname))) {
746*6777b538SAndroid Build Coastguard Worker     return false;
747*6777b538SAndroid Build Coastguard Worker   }
748*6777b538SAndroid Build Coastguard Worker 
749*6777b538SAndroid Build Coastguard Worker   if (!ssl_info.cert->VerifyNameMatch(new_hostname))
750*6777b538SAndroid Build Coastguard Worker     return false;
751*6777b538SAndroid Build Coastguard Worker 
752*6777b538SAndroid Build Coastguard Worker   // Port is left at 0 as it is never used.
753*6777b538SAndroid Build Coastguard Worker   if (transport_security_state->CheckPublicKeyPins(
754*6777b538SAndroid Build Coastguard Worker           HostPortPair(new_hostname, 0), ssl_info.is_issued_by_known_root,
755*6777b538SAndroid Build Coastguard Worker           ssl_info.public_key_hashes) ==
756*6777b538SAndroid Build Coastguard Worker       TransportSecurityState::PKPStatus::VIOLATED) {
757*6777b538SAndroid Build Coastguard Worker     return false;
758*6777b538SAndroid Build Coastguard Worker   }
759*6777b538SAndroid Build Coastguard Worker 
760*6777b538SAndroid Build Coastguard Worker   switch (transport_security_state->CheckCTRequirements(
761*6777b538SAndroid Build Coastguard Worker       HostPortPair(new_hostname, 0), ssl_info.is_issued_by_known_root,
762*6777b538SAndroid Build Coastguard Worker       ssl_info.public_key_hashes, ssl_info.cert.get(),
763*6777b538SAndroid Build Coastguard Worker       ssl_info.ct_policy_compliance)) {
764*6777b538SAndroid Build Coastguard Worker     case TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
765*6777b538SAndroid Build Coastguard Worker       return false;
766*6777b538SAndroid Build Coastguard Worker     case TransportSecurityState::CT_REQUIREMENTS_MET:
767*6777b538SAndroid Build Coastguard Worker     case TransportSecurityState::CT_NOT_REQUIRED:
768*6777b538SAndroid Build Coastguard Worker       // Intentional fallthrough; this case is just here to make sure that all
769*6777b538SAndroid Build Coastguard Worker       // possible values of CheckCTRequirements() are handled.
770*6777b538SAndroid Build Coastguard Worker       break;
771*6777b538SAndroid Build Coastguard Worker   }
772*6777b538SAndroid Build Coastguard Worker 
773*6777b538SAndroid Build Coastguard Worker   return true;
774*6777b538SAndroid Build Coastguard Worker }
775*6777b538SAndroid Build Coastguard Worker 
SpdySession(const SpdySessionKey & spdy_session_key,HttpServerProperties * http_server_properties,TransportSecurityState * transport_security_state,SSLConfigService * ssl_config_service,const quic::ParsedQuicVersionVector & quic_supported_versions,bool enable_sending_initial_data,bool enable_ping_based_connection_checking,bool is_http2_enabled,bool is_quic_enabled,size_t session_max_recv_window_size,int session_max_queued_capped_frames,const spdy::SettingsMap & initial_settings,bool enable_http2_settings_grease,const std::optional<SpdySessionPool::GreasedHttp2Frame> & greased_http2_frame,bool http2_end_stream_with_data_frame,bool enable_priority_update,TimeFunc time_func,NetworkQualityEstimator * network_quality_estimator,NetLog * net_log)776*6777b538SAndroid Build Coastguard Worker SpdySession::SpdySession(
777*6777b538SAndroid Build Coastguard Worker     const SpdySessionKey& spdy_session_key,
778*6777b538SAndroid Build Coastguard Worker     HttpServerProperties* http_server_properties,
779*6777b538SAndroid Build Coastguard Worker     TransportSecurityState* transport_security_state,
780*6777b538SAndroid Build Coastguard Worker     SSLConfigService* ssl_config_service,
781*6777b538SAndroid Build Coastguard Worker     const quic::ParsedQuicVersionVector& quic_supported_versions,
782*6777b538SAndroid Build Coastguard Worker     bool enable_sending_initial_data,
783*6777b538SAndroid Build Coastguard Worker     bool enable_ping_based_connection_checking,
784*6777b538SAndroid Build Coastguard Worker     bool is_http2_enabled,
785*6777b538SAndroid Build Coastguard Worker     bool is_quic_enabled,
786*6777b538SAndroid Build Coastguard Worker     size_t session_max_recv_window_size,
787*6777b538SAndroid Build Coastguard Worker     int session_max_queued_capped_frames,
788*6777b538SAndroid Build Coastguard Worker     const spdy::SettingsMap& initial_settings,
789*6777b538SAndroid Build Coastguard Worker     bool enable_http2_settings_grease,
790*6777b538SAndroid Build Coastguard Worker     const std::optional<SpdySessionPool::GreasedHttp2Frame>&
791*6777b538SAndroid Build Coastguard Worker         greased_http2_frame,
792*6777b538SAndroid Build Coastguard Worker     bool http2_end_stream_with_data_frame,
793*6777b538SAndroid Build Coastguard Worker     bool enable_priority_update,
794*6777b538SAndroid Build Coastguard Worker     TimeFunc time_func,
795*6777b538SAndroid Build Coastguard Worker     NetworkQualityEstimator* network_quality_estimator,
796*6777b538SAndroid Build Coastguard Worker     NetLog* net_log)
797*6777b538SAndroid Build Coastguard Worker     : spdy_session_key_(spdy_session_key),
798*6777b538SAndroid Build Coastguard Worker       http_server_properties_(http_server_properties),
799*6777b538SAndroid Build Coastguard Worker       transport_security_state_(transport_security_state),
800*6777b538SAndroid Build Coastguard Worker       ssl_config_service_(ssl_config_service),
801*6777b538SAndroid Build Coastguard Worker       stream_hi_water_mark_(kFirstStreamId),
802*6777b538SAndroid Build Coastguard Worker       initial_settings_(initial_settings),
803*6777b538SAndroid Build Coastguard Worker       enable_http2_settings_grease_(enable_http2_settings_grease),
804*6777b538SAndroid Build Coastguard Worker       greased_http2_frame_(greased_http2_frame),
805*6777b538SAndroid Build Coastguard Worker       http2_end_stream_with_data_frame_(http2_end_stream_with_data_frame),
806*6777b538SAndroid Build Coastguard Worker       enable_priority_update_(enable_priority_update),
807*6777b538SAndroid Build Coastguard Worker       max_concurrent_streams_(kH2InitialMaxConcurrentStreams.Get()),
808*6777b538SAndroid Build Coastguard Worker       last_read_time_(time_func()),
809*6777b538SAndroid Build Coastguard Worker       session_max_recv_window_size_(session_max_recv_window_size),
810*6777b538SAndroid Build Coastguard Worker       session_max_queued_capped_frames_(session_max_queued_capped_frames),
811*6777b538SAndroid Build Coastguard Worker       last_recv_window_update_(base::TimeTicks::Now()),
812*6777b538SAndroid Build Coastguard Worker       time_to_buffer_small_window_updates_(
813*6777b538SAndroid Build Coastguard Worker           kDefaultTimeToBufferSmallWindowUpdates),
814*6777b538SAndroid Build Coastguard Worker       stream_initial_send_window_size_(kDefaultInitialWindowSize),
815*6777b538SAndroid Build Coastguard Worker       max_header_table_size_(
816*6777b538SAndroid Build Coastguard Worker           initial_settings.at(spdy::SETTINGS_HEADER_TABLE_SIZE)),
817*6777b538SAndroid Build Coastguard Worker       stream_max_recv_window_size_(
818*6777b538SAndroid Build Coastguard Worker           initial_settings.at(spdy::SETTINGS_INITIAL_WINDOW_SIZE)),
819*6777b538SAndroid Build Coastguard Worker       net_log_(
820*6777b538SAndroid Build Coastguard Worker           NetLogWithSource::Make(net_log, NetLogSourceType::HTTP2_SESSION)),
821*6777b538SAndroid Build Coastguard Worker       quic_supported_versions_(quic_supported_versions),
822*6777b538SAndroid Build Coastguard Worker       enable_sending_initial_data_(enable_sending_initial_data),
823*6777b538SAndroid Build Coastguard Worker       enable_ping_based_connection_checking_(
824*6777b538SAndroid Build Coastguard Worker           enable_ping_based_connection_checking),
825*6777b538SAndroid Build Coastguard Worker       is_http2_enabled_(is_http2_enabled),
826*6777b538SAndroid Build Coastguard Worker       is_quic_enabled_(is_quic_enabled),
827*6777b538SAndroid Build Coastguard Worker       connection_at_risk_of_loss_time_(
828*6777b538SAndroid Build Coastguard Worker           base::Seconds(kDefaultConnectionAtRiskOfLossSeconds)),
829*6777b538SAndroid Build Coastguard Worker       hung_interval_(base::Seconds(kHungIntervalSeconds)),
830*6777b538SAndroid Build Coastguard Worker       time_func_(time_func),
831*6777b538SAndroid Build Coastguard Worker       network_quality_estimator_(network_quality_estimator) {
832*6777b538SAndroid Build Coastguard Worker   net_log_.BeginEvent(NetLogEventType::HTTP2_SESSION, [&] {
833*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionParams(host_port_proxy_pair());
834*6777b538SAndroid Build Coastguard Worker   });
835*6777b538SAndroid Build Coastguard Worker 
836*6777b538SAndroid Build Coastguard Worker   DCHECK(base::Contains(initial_settings_, spdy::SETTINGS_HEADER_TABLE_SIZE));
837*6777b538SAndroid Build Coastguard Worker   DCHECK(base::Contains(initial_settings_, spdy::SETTINGS_INITIAL_WINDOW_SIZE));
838*6777b538SAndroid Build Coastguard Worker 
839*6777b538SAndroid Build Coastguard Worker   if (greased_http2_frame_) {
840*6777b538SAndroid Build Coastguard Worker     // See https://tools.ietf.org/html/draft-bishop-httpbis-grease-00
841*6777b538SAndroid Build Coastguard Worker     // for reserved frame types.
842*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(0x0b, greased_http2_frame_.value().type % 0x1f);
843*6777b538SAndroid Build Coastguard Worker   }
844*6777b538SAndroid Build Coastguard Worker 
845*6777b538SAndroid Build Coastguard Worker   // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
846*6777b538SAndroid Build Coastguard Worker }
847*6777b538SAndroid Build Coastguard Worker 
~SpdySession()848*6777b538SAndroid Build Coastguard Worker SpdySession::~SpdySession() {
849*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
850*6777b538SAndroid Build Coastguard Worker   DcheckDraining();
851*6777b538SAndroid Build Coastguard Worker 
852*6777b538SAndroid Build Coastguard Worker   DCHECK(waiting_for_confirmation_callbacks_.empty());
853*6777b538SAndroid Build Coastguard Worker 
854*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(broken_connection_detection_requests_, 0);
855*6777b538SAndroid Build Coastguard Worker 
856*6777b538SAndroid Build Coastguard Worker   // TODO(akalin): Check connection->is_initialized().
857*6777b538SAndroid Build Coastguard Worker   DCHECK(socket_);
858*6777b538SAndroid Build Coastguard Worker   // With SPDY we can't recycle sockets.
859*6777b538SAndroid Build Coastguard Worker   socket_->Disconnect();
860*6777b538SAndroid Build Coastguard Worker 
861*6777b538SAndroid Build Coastguard Worker   RecordHistograms();
862*6777b538SAndroid Build Coastguard Worker 
863*6777b538SAndroid Build Coastguard Worker   net_log_.EndEvent(NetLogEventType::HTTP2_SESSION);
864*6777b538SAndroid Build Coastguard Worker }
865*6777b538SAndroid Build Coastguard Worker 
InitializeWithSocketHandle(std::unique_ptr<ClientSocketHandle> client_socket_handle,SpdySessionPool * pool)866*6777b538SAndroid Build Coastguard Worker void SpdySession::InitializeWithSocketHandle(
867*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<ClientSocketHandle> client_socket_handle,
868*6777b538SAndroid Build Coastguard Worker     SpdySessionPool* pool) {
869*6777b538SAndroid Build Coastguard Worker   DCHECK(!client_socket_handle_);
870*6777b538SAndroid Build Coastguard Worker   DCHECK(!owned_stream_socket_);
871*6777b538SAndroid Build Coastguard Worker   DCHECK(!socket_);
872*6777b538SAndroid Build Coastguard Worker 
873*6777b538SAndroid Build Coastguard Worker   // TODO(akalin): Check connection->is_initialized() instead. This
874*6777b538SAndroid Build Coastguard Worker   // requires re-working CreateFakeSpdySession(), though.
875*6777b538SAndroid Build Coastguard Worker   DCHECK(client_socket_handle->socket());
876*6777b538SAndroid Build Coastguard Worker 
877*6777b538SAndroid Build Coastguard Worker   client_socket_handle_ = std::move(client_socket_handle);
878*6777b538SAndroid Build Coastguard Worker   socket_ = client_socket_handle_->socket();
879*6777b538SAndroid Build Coastguard Worker   client_socket_handle_->AddHigherLayeredPool(this);
880*6777b538SAndroid Build Coastguard Worker 
881*6777b538SAndroid Build Coastguard Worker   InitializeInternal(pool);
882*6777b538SAndroid Build Coastguard Worker }
883*6777b538SAndroid Build Coastguard Worker 
InitializeWithSocket(std::unique_ptr<StreamSocket> stream_socket,const LoadTimingInfo::ConnectTiming & connect_timing,SpdySessionPool * pool)884*6777b538SAndroid Build Coastguard Worker void SpdySession::InitializeWithSocket(
885*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<StreamSocket> stream_socket,
886*6777b538SAndroid Build Coastguard Worker     const LoadTimingInfo::ConnectTiming& connect_timing,
887*6777b538SAndroid Build Coastguard Worker     SpdySessionPool* pool) {
888*6777b538SAndroid Build Coastguard Worker   DCHECK(!client_socket_handle_);
889*6777b538SAndroid Build Coastguard Worker   DCHECK(!owned_stream_socket_);
890*6777b538SAndroid Build Coastguard Worker   DCHECK(!socket_);
891*6777b538SAndroid Build Coastguard Worker 
892*6777b538SAndroid Build Coastguard Worker   DCHECK(stream_socket);
893*6777b538SAndroid Build Coastguard Worker 
894*6777b538SAndroid Build Coastguard Worker   owned_stream_socket_ = std::move(stream_socket);
895*6777b538SAndroid Build Coastguard Worker   socket_ = owned_stream_socket_.get();
896*6777b538SAndroid Build Coastguard Worker   connect_timing_ =
897*6777b538SAndroid Build Coastguard Worker       std::make_unique<LoadTimingInfo::ConnectTiming>(connect_timing);
898*6777b538SAndroid Build Coastguard Worker 
899*6777b538SAndroid Build Coastguard Worker   InitializeInternal(pool);
900*6777b538SAndroid Build Coastguard Worker }
901*6777b538SAndroid Build Coastguard Worker 
ParseAlps()902*6777b538SAndroid Build Coastguard Worker int SpdySession::ParseAlps() {
903*6777b538SAndroid Build Coastguard Worker   auto alps_data = socket_->GetPeerApplicationSettings();
904*6777b538SAndroid Build Coastguard Worker   if (!alps_data) {
905*6777b538SAndroid Build Coastguard Worker     return OK;
906*6777b538SAndroid Build Coastguard Worker   }
907*6777b538SAndroid Build Coastguard Worker 
908*6777b538SAndroid Build Coastguard Worker   AlpsDecoder alps_decoder;
909*6777b538SAndroid Build Coastguard Worker   AlpsDecoder::Error error = alps_decoder.Decode(alps_data.value());
910*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramEnumeration("Net.SpdySession.AlpsDecoderStatus", error);
911*6777b538SAndroid Build Coastguard Worker   if (error != AlpsDecoder::Error::kNoError) {
912*6777b538SAndroid Build Coastguard Worker     DoDrainSession(
913*6777b538SAndroid Build Coastguard Worker         ERR_HTTP2_PROTOCOL_ERROR,
914*6777b538SAndroid Build Coastguard Worker         base::StrCat({"Error parsing ALPS: ",
915*6777b538SAndroid Build Coastguard Worker                       base::NumberToString(static_cast<int>(error))}));
916*6777b538SAndroid Build Coastguard Worker     return ERR_HTTP2_PROTOCOL_ERROR;
917*6777b538SAndroid Build Coastguard Worker   }
918*6777b538SAndroid Build Coastguard Worker 
919*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100("Net.SpdySession.AlpsSettingParameterCount",
920*6777b538SAndroid Build Coastguard Worker                               alps_decoder.GetSettings().size());
921*6777b538SAndroid Build Coastguard Worker   for (const auto& setting : alps_decoder.GetSettings()) {
922*6777b538SAndroid Build Coastguard Worker     spdy::SpdySettingsId identifier = setting.first;
923*6777b538SAndroid Build Coastguard Worker     uint32_t value = setting.second;
924*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTING, [&] {
925*6777b538SAndroid Build Coastguard Worker       return NetLogSpdyRecvSettingParams(identifier, value);
926*6777b538SAndroid Build Coastguard Worker     });
927*6777b538SAndroid Build Coastguard Worker     HandleSetting(identifier, value);
928*6777b538SAndroid Build Coastguard Worker   }
929*6777b538SAndroid Build Coastguard Worker 
930*6777b538SAndroid Build Coastguard Worker   bool has_valid_entry = false;
931*6777b538SAndroid Build Coastguard Worker   bool has_invalid_entry = false;
932*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : alps_decoder.GetAcceptCh()) {
933*6777b538SAndroid Build Coastguard Worker     const url::SchemeHostPort scheme_host_port(GURL(entry.origin));
934*6777b538SAndroid Build Coastguard Worker     // |entry.origin| must be a valid SchemeHostPort.
935*6777b538SAndroid Build Coastguard Worker     std::string serialized = scheme_host_port.Serialize();
936*6777b538SAndroid Build Coastguard Worker     if (serialized.empty() || entry.origin != serialized) {
937*6777b538SAndroid Build Coastguard Worker       has_invalid_entry = true;
938*6777b538SAndroid Build Coastguard Worker       continue;
939*6777b538SAndroid Build Coastguard Worker     }
940*6777b538SAndroid Build Coastguard Worker     has_valid_entry = true;
941*6777b538SAndroid Build Coastguard Worker     accept_ch_entries_received_via_alps_.emplace(std::move(scheme_host_port),
942*6777b538SAndroid Build Coastguard Worker                                                  entry.value);
943*6777b538SAndroid Build Coastguard Worker 
944*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_ACCEPT_CH,
945*6777b538SAndroid Build Coastguard Worker                       [&] { return NetLogSpdyRecvAcceptChParams(entry); });
946*6777b538SAndroid Build Coastguard Worker   }
947*6777b538SAndroid Build Coastguard Worker 
948*6777b538SAndroid Build Coastguard Worker   SpdyAcceptChEntries value;
949*6777b538SAndroid Build Coastguard Worker   if (has_valid_entry) {
950*6777b538SAndroid Build Coastguard Worker     if (has_invalid_entry) {
951*6777b538SAndroid Build Coastguard Worker       value = SpdyAcceptChEntries::kBothValidAndInvalidEntries;
952*6777b538SAndroid Build Coastguard Worker     } else {
953*6777b538SAndroid Build Coastguard Worker       value = SpdyAcceptChEntries::kOnlyValidEntries;
954*6777b538SAndroid Build Coastguard Worker     }
955*6777b538SAndroid Build Coastguard Worker   } else {
956*6777b538SAndroid Build Coastguard Worker     if (has_invalid_entry) {
957*6777b538SAndroid Build Coastguard Worker       value = SpdyAcceptChEntries::kOnlyInvalidEntries;
958*6777b538SAndroid Build Coastguard Worker     } else {
959*6777b538SAndroid Build Coastguard Worker       value = SpdyAcceptChEntries::kNoEntries;
960*6777b538SAndroid Build Coastguard Worker     }
961*6777b538SAndroid Build Coastguard Worker   }
962*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramEnumeration("Net.SpdySession.AlpsAcceptChEntries", value);
963*6777b538SAndroid Build Coastguard Worker 
964*6777b538SAndroid Build Coastguard Worker   return OK;
965*6777b538SAndroid Build Coastguard Worker }
966*6777b538SAndroid Build Coastguard Worker 
VerifyDomainAuthentication(std::string_view domain) const967*6777b538SAndroid Build Coastguard Worker bool SpdySession::VerifyDomainAuthentication(std::string_view domain) const {
968*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
969*6777b538SAndroid Build Coastguard Worker     return false;
970*6777b538SAndroid Build Coastguard Worker 
971*6777b538SAndroid Build Coastguard Worker   SSLInfo ssl_info;
972*6777b538SAndroid Build Coastguard Worker   if (!GetSSLInfo(&ssl_info))
973*6777b538SAndroid Build Coastguard Worker     return true;  // This is not a secure session, so all domains are okay.
974*6777b538SAndroid Build Coastguard Worker 
975*6777b538SAndroid Build Coastguard Worker   return CanPool(transport_security_state_, ssl_info, *ssl_config_service_,
976*6777b538SAndroid Build Coastguard Worker                  host_port_pair().host(), domain);
977*6777b538SAndroid Build Coastguard Worker }
978*6777b538SAndroid Build Coastguard Worker 
EnqueueStreamWrite(const base::WeakPtr<SpdyStream> & stream,spdy::SpdyFrameType frame_type,std::unique_ptr<SpdyBufferProducer> producer)979*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueueStreamWrite(
980*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStream>& stream,
981*6777b538SAndroid Build Coastguard Worker     spdy::SpdyFrameType frame_type,
982*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<SpdyBufferProducer> producer) {
983*6777b538SAndroid Build Coastguard Worker   DCHECK(frame_type == spdy::SpdyFrameType::HEADERS ||
984*6777b538SAndroid Build Coastguard Worker          frame_type == spdy::SpdyFrameType::DATA);
985*6777b538SAndroid Build Coastguard Worker   EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream,
986*6777b538SAndroid Build Coastguard Worker                stream->traffic_annotation());
987*6777b538SAndroid Build Coastguard Worker }
988*6777b538SAndroid Build Coastguard Worker 
GreasedFramesEnabled() const989*6777b538SAndroid Build Coastguard Worker bool SpdySession::GreasedFramesEnabled() const {
990*6777b538SAndroid Build Coastguard Worker   return greased_http2_frame_.has_value();
991*6777b538SAndroid Build Coastguard Worker }
992*6777b538SAndroid Build Coastguard Worker 
EnqueueGreasedFrame(const base::WeakPtr<SpdyStream> & stream)993*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueueGreasedFrame(const base::WeakPtr<SpdyStream>& stream) {
994*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
995*6777b538SAndroid Build Coastguard Worker     return;
996*6777b538SAndroid Build Coastguard Worker 
997*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_GREASED_FRAME, [&] {
998*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyGreasedFrameParams(
999*6777b538SAndroid Build Coastguard Worker         stream->stream_id(), greased_http2_frame_.value().type,
1000*6777b538SAndroid Build Coastguard Worker         greased_http2_frame_.value().flags,
1001*6777b538SAndroid Build Coastguard Worker         greased_http2_frame_.value().payload.length(), stream->priority());
1002*6777b538SAndroid Build Coastguard Worker   });
1003*6777b538SAndroid Build Coastguard Worker 
1004*6777b538SAndroid Build Coastguard Worker   EnqueueWrite(
1005*6777b538SAndroid Build Coastguard Worker       stream->priority(),
1006*6777b538SAndroid Build Coastguard Worker       static_cast<spdy::SpdyFrameType>(greased_http2_frame_.value().type),
1007*6777b538SAndroid Build Coastguard Worker       std::make_unique<GreasedBufferProducer>(
1008*6777b538SAndroid Build Coastguard Worker           stream, &greased_http2_frame_.value(), buffered_spdy_framer_.get()),
1009*6777b538SAndroid Build Coastguard Worker       stream, stream->traffic_annotation());
1010*6777b538SAndroid Build Coastguard Worker }
1011*6777b538SAndroid Build Coastguard Worker 
ShouldSendHttp2Priority() const1012*6777b538SAndroid Build Coastguard Worker bool SpdySession::ShouldSendHttp2Priority() const {
1013*6777b538SAndroid Build Coastguard Worker   return !enable_priority_update_ || !deprecate_http2_priorities_;
1014*6777b538SAndroid Build Coastguard Worker }
1015*6777b538SAndroid Build Coastguard Worker 
ShouldSendPriorityUpdate() const1016*6777b538SAndroid Build Coastguard Worker bool SpdySession::ShouldSendPriorityUpdate() const {
1017*6777b538SAndroid Build Coastguard Worker   if (!enable_priority_update_) {
1018*6777b538SAndroid Build Coastguard Worker     return false;
1019*6777b538SAndroid Build Coastguard Worker   }
1020*6777b538SAndroid Build Coastguard Worker 
1021*6777b538SAndroid Build Coastguard Worker   return settings_frame_received_ ? deprecate_http2_priorities_ : true;
1022*6777b538SAndroid Build Coastguard Worker }
1023*6777b538SAndroid Build Coastguard Worker 
ConfirmHandshake(CompletionOnceCallback callback)1024*6777b538SAndroid Build Coastguard Worker int SpdySession::ConfirmHandshake(CompletionOnceCallback callback) {
1025*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_GOING_AWAY)
1026*6777b538SAndroid Build Coastguard Worker     return ERR_FAILED;
1027*6777b538SAndroid Build Coastguard Worker 
1028*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
1029*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
1030*6777b538SAndroid Build Coastguard Worker 
1031*6777b538SAndroid Build Coastguard Worker   int rv = ERR_IO_PENDING;
1032*6777b538SAndroid Build Coastguard Worker   if (!in_confirm_handshake_) {
1033*6777b538SAndroid Build Coastguard Worker     rv = socket_->ConfirmHandshake(
1034*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&SpdySession::NotifyRequestsOfConfirmation,
1035*6777b538SAndroid Build Coastguard Worker                        weak_factory_.GetWeakPtr()));
1036*6777b538SAndroid Build Coastguard Worker   }
1037*6777b538SAndroid Build Coastguard Worker   if (rv == ERR_IO_PENDING) {
1038*6777b538SAndroid Build Coastguard Worker     in_confirm_handshake_ = true;
1039*6777b538SAndroid Build Coastguard Worker     waiting_for_confirmation_callbacks_.push_back(std::move(callback));
1040*6777b538SAndroid Build Coastguard Worker   }
1041*6777b538SAndroid Build Coastguard Worker   return rv;
1042*6777b538SAndroid Build Coastguard Worker }
1043*6777b538SAndroid Build Coastguard Worker 
CreateHeaders(spdy::SpdyStreamId stream_id,RequestPriority priority,spdy::SpdyControlFlags flags,spdy::Http2HeaderBlock block,NetLogSource source_dependency)1044*6777b538SAndroid Build Coastguard Worker std::unique_ptr<spdy::SpdySerializedFrame> SpdySession::CreateHeaders(
1045*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
1046*6777b538SAndroid Build Coastguard Worker     RequestPriority priority,
1047*6777b538SAndroid Build Coastguard Worker     spdy::SpdyControlFlags flags,
1048*6777b538SAndroid Build Coastguard Worker     spdy::Http2HeaderBlock block,
1049*6777b538SAndroid Build Coastguard Worker     NetLogSource source_dependency) {
1050*6777b538SAndroid Build Coastguard Worker   ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
1051*6777b538SAndroid Build Coastguard Worker   CHECK(it != active_streams_.end());
1052*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(it->second->stream_id(), stream_id);
1053*6777b538SAndroid Build Coastguard Worker 
1054*6777b538SAndroid Build Coastguard Worker   MaybeSendPrefacePing();
1055*6777b538SAndroid Build Coastguard Worker 
1056*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1057*6777b538SAndroid Build Coastguard Worker   spdy::SpdyPriority spdy_priority =
1058*6777b538SAndroid Build Coastguard Worker       ConvertRequestPriorityToSpdyPriority(priority);
1059*6777b538SAndroid Build Coastguard Worker 
1060*6777b538SAndroid Build Coastguard Worker   bool has_priority = true;
1061*6777b538SAndroid Build Coastguard Worker   int weight = 0;
1062*6777b538SAndroid Build Coastguard Worker   spdy::SpdyStreamId parent_stream_id = 0;
1063*6777b538SAndroid Build Coastguard Worker   bool exclusive = false;
1064*6777b538SAndroid Build Coastguard Worker 
1065*6777b538SAndroid Build Coastguard Worker   priority_dependency_state_.OnStreamCreation(
1066*6777b538SAndroid Build Coastguard Worker       stream_id, spdy_priority, &parent_stream_id, &weight, &exclusive);
1067*6777b538SAndroid Build Coastguard Worker 
1068*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
1069*6777b538SAndroid Build Coastguard Worker                     [&](NetLogCaptureMode capture_mode) {
1070*6777b538SAndroid Build Coastguard Worker                       return NetLogSpdyHeadersSentParams(
1071*6777b538SAndroid Build Coastguard Worker                           &block, (flags & spdy::CONTROL_FLAG_FIN) != 0,
1072*6777b538SAndroid Build Coastguard Worker                           stream_id, has_priority, weight, parent_stream_id,
1073*6777b538SAndroid Build Coastguard Worker                           exclusive, source_dependency, capture_mode);
1074*6777b538SAndroid Build Coastguard Worker                     });
1075*6777b538SAndroid Build Coastguard Worker 
1076*6777b538SAndroid Build Coastguard Worker   spdy::SpdyHeadersIR headers(stream_id, std::move(block));
1077*6777b538SAndroid Build Coastguard Worker   headers.set_has_priority(has_priority);
1078*6777b538SAndroid Build Coastguard Worker   headers.set_weight(weight);
1079*6777b538SAndroid Build Coastguard Worker   headers.set_parent_stream_id(parent_stream_id);
1080*6777b538SAndroid Build Coastguard Worker   headers.set_exclusive(exclusive);
1081*6777b538SAndroid Build Coastguard Worker   headers.set_fin((flags & spdy::CONTROL_FLAG_FIN) != 0);
1082*6777b538SAndroid Build Coastguard Worker 
1083*6777b538SAndroid Build Coastguard Worker   streams_initiated_count_++;
1084*6777b538SAndroid Build Coastguard Worker 
1085*6777b538SAndroid Build Coastguard Worker   return std::make_unique<spdy::SpdySerializedFrame>(
1086*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->SerializeFrame(headers));
1087*6777b538SAndroid Build Coastguard Worker }
1088*6777b538SAndroid Build Coastguard Worker 
CreateDataBuffer(spdy::SpdyStreamId stream_id,IOBuffer * data,int len,spdy::SpdyDataFlags flags,int * effective_len,bool * end_stream)1089*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
1090*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
1091*6777b538SAndroid Build Coastguard Worker     IOBuffer* data,
1092*6777b538SAndroid Build Coastguard Worker     int len,
1093*6777b538SAndroid Build Coastguard Worker     spdy::SpdyDataFlags flags,
1094*6777b538SAndroid Build Coastguard Worker     int* effective_len,
1095*6777b538SAndroid Build Coastguard Worker     bool* end_stream) {
1096*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING) {
1097*6777b538SAndroid Build Coastguard Worker     return nullptr;
1098*6777b538SAndroid Build Coastguard Worker   }
1099*6777b538SAndroid Build Coastguard Worker 
1100*6777b538SAndroid Build Coastguard Worker   ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
1101*6777b538SAndroid Build Coastguard Worker   CHECK(it != active_streams_.end());
1102*6777b538SAndroid Build Coastguard Worker   SpdyStream* stream = it->second;
1103*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), stream_id);
1104*6777b538SAndroid Build Coastguard Worker 
1105*6777b538SAndroid Build Coastguard Worker   if (len < 0) {
1106*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
1107*6777b538SAndroid Build Coastguard Worker     return nullptr;
1108*6777b538SAndroid Build Coastguard Worker   }
1109*6777b538SAndroid Build Coastguard Worker 
1110*6777b538SAndroid Build Coastguard Worker   *effective_len = std::min(len, kMaxSpdyFrameChunkSize);
1111*6777b538SAndroid Build Coastguard Worker 
1112*6777b538SAndroid Build Coastguard Worker   bool send_stalled_by_stream = (stream->send_window_size() <= 0);
1113*6777b538SAndroid Build Coastguard Worker   bool send_stalled_by_session = IsSendStalled();
1114*6777b538SAndroid Build Coastguard Worker 
1115*6777b538SAndroid Build Coastguard Worker   // NOTE: There's an enum of the same name in histograms.xml.
1116*6777b538SAndroid Build Coastguard Worker   enum SpdyFrameFlowControlState {
1117*6777b538SAndroid Build Coastguard Worker     SEND_NOT_STALLED,
1118*6777b538SAndroid Build Coastguard Worker     SEND_STALLED_BY_STREAM,
1119*6777b538SAndroid Build Coastguard Worker     SEND_STALLED_BY_SESSION,
1120*6777b538SAndroid Build Coastguard Worker     SEND_STALLED_BY_STREAM_AND_SESSION,
1121*6777b538SAndroid Build Coastguard Worker   };
1122*6777b538SAndroid Build Coastguard Worker 
1123*6777b538SAndroid Build Coastguard Worker   SpdyFrameFlowControlState frame_flow_control_state = SEND_NOT_STALLED;
1124*6777b538SAndroid Build Coastguard Worker   if (send_stalled_by_stream) {
1125*6777b538SAndroid Build Coastguard Worker     if (send_stalled_by_session) {
1126*6777b538SAndroid Build Coastguard Worker       frame_flow_control_state = SEND_STALLED_BY_STREAM_AND_SESSION;
1127*6777b538SAndroid Build Coastguard Worker     } else {
1128*6777b538SAndroid Build Coastguard Worker       frame_flow_control_state = SEND_STALLED_BY_STREAM;
1129*6777b538SAndroid Build Coastguard Worker     }
1130*6777b538SAndroid Build Coastguard Worker   } else if (send_stalled_by_session) {
1131*6777b538SAndroid Build Coastguard Worker     frame_flow_control_state = SEND_STALLED_BY_SESSION;
1132*6777b538SAndroid Build Coastguard Worker   }
1133*6777b538SAndroid Build Coastguard Worker 
1134*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_ENUMERATION("Net.SpdyFrameStreamAndSessionFlowControlState",
1135*6777b538SAndroid Build Coastguard Worker                             frame_flow_control_state,
1136*6777b538SAndroid Build Coastguard Worker                             SEND_STALLED_BY_STREAM_AND_SESSION + 1);
1137*6777b538SAndroid Build Coastguard Worker 
1138*6777b538SAndroid Build Coastguard Worker   // Obey send window size of the stream.
1139*6777b538SAndroid Build Coastguard Worker   if (send_stalled_by_stream) {
1140*6777b538SAndroid Build Coastguard Worker     stream->set_send_stalled_by_flow_control(true);
1141*6777b538SAndroid Build Coastguard Worker     // Even though we're currently stalled only by the stream, we
1142*6777b538SAndroid Build Coastguard Worker     // might end up being stalled by the session also.
1143*6777b538SAndroid Build Coastguard Worker     QueueSendStalledStream(*stream);
1144*6777b538SAndroid Build Coastguard Worker     net_log_.AddEventWithIntParams(
1145*6777b538SAndroid Build Coastguard Worker         NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
1146*6777b538SAndroid Build Coastguard Worker         "stream_id", stream_id);
1147*6777b538SAndroid Build Coastguard Worker     return nullptr;
1148*6777b538SAndroid Build Coastguard Worker   }
1149*6777b538SAndroid Build Coastguard Worker 
1150*6777b538SAndroid Build Coastguard Worker   *effective_len = std::min(*effective_len, stream->send_window_size());
1151*6777b538SAndroid Build Coastguard Worker 
1152*6777b538SAndroid Build Coastguard Worker   // Obey send window size of the session.
1153*6777b538SAndroid Build Coastguard Worker   if (send_stalled_by_session) {
1154*6777b538SAndroid Build Coastguard Worker     stream->set_send_stalled_by_flow_control(true);
1155*6777b538SAndroid Build Coastguard Worker     QueueSendStalledStream(*stream);
1156*6777b538SAndroid Build Coastguard Worker     net_log_.AddEventWithIntParams(
1157*6777b538SAndroid Build Coastguard Worker         NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
1158*6777b538SAndroid Build Coastguard Worker         "stream_id", stream_id);
1159*6777b538SAndroid Build Coastguard Worker     return nullptr;
1160*6777b538SAndroid Build Coastguard Worker   }
1161*6777b538SAndroid Build Coastguard Worker 
1162*6777b538SAndroid Build Coastguard Worker   *effective_len = std::min(*effective_len, session_send_window_size_);
1163*6777b538SAndroid Build Coastguard Worker 
1164*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(*effective_len, 0);
1165*6777b538SAndroid Build Coastguard Worker 
1166*6777b538SAndroid Build Coastguard Worker   // Clear FIN flag if only some of the data will be in the data
1167*6777b538SAndroid Build Coastguard Worker   // frame.
1168*6777b538SAndroid Build Coastguard Worker   if (*effective_len < len)
1169*6777b538SAndroid Build Coastguard Worker     flags = static_cast<spdy::SpdyDataFlags>(flags & ~spdy::DATA_FLAG_FIN);
1170*6777b538SAndroid Build Coastguard Worker 
1171*6777b538SAndroid Build Coastguard Worker 
1172*6777b538SAndroid Build Coastguard Worker   // Send PrefacePing for DATA_FRAMEs with nonzero payload size.
1173*6777b538SAndroid Build Coastguard Worker   if (*effective_len > 0)
1174*6777b538SAndroid Build Coastguard Worker     MaybeSendPrefacePing();
1175*6777b538SAndroid Build Coastguard Worker 
1176*6777b538SAndroid Build Coastguard Worker   // TODO(mbelshe): reduce memory copies here.
1177*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1178*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> frame(
1179*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreateDataFrame(
1180*6777b538SAndroid Build Coastguard Worker           stream_id, data->data(), static_cast<uint32_t>(*effective_len),
1181*6777b538SAndroid Build Coastguard Worker           flags));
1182*6777b538SAndroid Build Coastguard Worker 
1183*6777b538SAndroid Build Coastguard Worker   auto data_buffer = std::make_unique<SpdyBuffer>(std::move(frame));
1184*6777b538SAndroid Build Coastguard Worker 
1185*6777b538SAndroid Build Coastguard Worker   // Send window size is based on payload size, so nothing to do if this is
1186*6777b538SAndroid Build Coastguard Worker   // just a FIN with no payload.
1187*6777b538SAndroid Build Coastguard Worker   if (*effective_len != 0) {
1188*6777b538SAndroid Build Coastguard Worker     DecreaseSendWindowSize(static_cast<int32_t>(*effective_len));
1189*6777b538SAndroid Build Coastguard Worker     data_buffer->AddConsumeCallback(base::BindRepeating(
1190*6777b538SAndroid Build Coastguard Worker         &SpdySession::OnWriteBufferConsumed, weak_factory_.GetWeakPtr(),
1191*6777b538SAndroid Build Coastguard Worker         static_cast<size_t>(*effective_len)));
1192*6777b538SAndroid Build Coastguard Worker   }
1193*6777b538SAndroid Build Coastguard Worker 
1194*6777b538SAndroid Build Coastguard Worker   *end_stream = (flags & spdy::DATA_FLAG_FIN) == spdy::DATA_FLAG_FIN;
1195*6777b538SAndroid Build Coastguard Worker   return data_buffer;
1196*6777b538SAndroid Build Coastguard Worker }
1197*6777b538SAndroid Build Coastguard Worker 
UpdateStreamPriority(SpdyStream * stream,RequestPriority old_priority,RequestPriority new_priority)1198*6777b538SAndroid Build Coastguard Worker void SpdySession::UpdateStreamPriority(SpdyStream* stream,
1199*6777b538SAndroid Build Coastguard Worker                                        RequestPriority old_priority,
1200*6777b538SAndroid Build Coastguard Worker                                        RequestPriority new_priority) {
1201*6777b538SAndroid Build Coastguard Worker   // There might be write frames enqueued for |stream| regardless of whether it
1202*6777b538SAndroid Build Coastguard Worker   // is active (stream_id != 0) or inactive (no HEADERS frame has been sent out
1203*6777b538SAndroid Build Coastguard Worker   // yet and stream_id == 0).
1204*6777b538SAndroid Build Coastguard Worker   write_queue_.ChangePriorityOfWritesForStream(stream, old_priority,
1205*6777b538SAndroid Build Coastguard Worker                                                new_priority);
1206*6777b538SAndroid Build Coastguard Worker 
1207*6777b538SAndroid Build Coastguard Worker   // PRIORITY frames only need to be sent if |stream| is active.
1208*6777b538SAndroid Build Coastguard Worker   const spdy::SpdyStreamId stream_id = stream->stream_id();
1209*6777b538SAndroid Build Coastguard Worker   if (stream_id == 0)
1210*6777b538SAndroid Build Coastguard Worker     return;
1211*6777b538SAndroid Build Coastguard Worker 
1212*6777b538SAndroid Build Coastguard Worker   DCHECK(IsStreamActive(stream_id));
1213*6777b538SAndroid Build Coastguard Worker 
1214*6777b538SAndroid Build Coastguard Worker   if (base::FeatureList::IsEnabled(features::kAvoidH2Reprioritization))
1215*6777b538SAndroid Build Coastguard Worker     return;
1216*6777b538SAndroid Build Coastguard Worker 
1217*6777b538SAndroid Build Coastguard Worker   auto updates = priority_dependency_state_.OnStreamUpdate(
1218*6777b538SAndroid Build Coastguard Worker       stream_id, ConvertRequestPriorityToSpdyPriority(new_priority));
1219*6777b538SAndroid Build Coastguard Worker   for (auto u : updates) {
1220*6777b538SAndroid Build Coastguard Worker     DCHECK(IsStreamActive(u.id));
1221*6777b538SAndroid Build Coastguard Worker     EnqueuePriorityFrame(u.id, u.parent_stream_id, u.weight, u.exclusive);
1222*6777b538SAndroid Build Coastguard Worker   }
1223*6777b538SAndroid Build Coastguard Worker }
1224*6777b538SAndroid Build Coastguard Worker 
CloseActiveStream(spdy::SpdyStreamId stream_id,int status)1225*6777b538SAndroid Build Coastguard Worker void SpdySession::CloseActiveStream(spdy::SpdyStreamId stream_id, int status) {
1226*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(stream_id, 0u);
1227*6777b538SAndroid Build Coastguard Worker 
1228*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
1229*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end()) {
1230*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
1231*6777b538SAndroid Build Coastguard Worker     return;
1232*6777b538SAndroid Build Coastguard Worker   }
1233*6777b538SAndroid Build Coastguard Worker 
1234*6777b538SAndroid Build Coastguard Worker   CloseActiveStreamIterator(it, status);
1235*6777b538SAndroid Build Coastguard Worker }
1236*6777b538SAndroid Build Coastguard Worker 
CloseCreatedStream(const base::WeakPtr<SpdyStream> & stream,int status)1237*6777b538SAndroid Build Coastguard Worker void SpdySession::CloseCreatedStream(const base::WeakPtr<SpdyStream>& stream,
1238*6777b538SAndroid Build Coastguard Worker                                      int status) {
1239*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(stream->stream_id(), 0u);
1240*6777b538SAndroid Build Coastguard Worker 
1241*6777b538SAndroid Build Coastguard Worker   auto it = created_streams_.find(stream.get());
1242*6777b538SAndroid Build Coastguard Worker   if (it == created_streams_.end()) {
1243*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
1244*6777b538SAndroid Build Coastguard Worker     return;
1245*6777b538SAndroid Build Coastguard Worker   }
1246*6777b538SAndroid Build Coastguard Worker 
1247*6777b538SAndroid Build Coastguard Worker   CloseCreatedStreamIterator(it, status);
1248*6777b538SAndroid Build Coastguard Worker }
1249*6777b538SAndroid Build Coastguard Worker 
ResetStream(spdy::SpdyStreamId stream_id,int error,const std::string & description)1250*6777b538SAndroid Build Coastguard Worker void SpdySession::ResetStream(spdy::SpdyStreamId stream_id,
1251*6777b538SAndroid Build Coastguard Worker                               int error,
1252*6777b538SAndroid Build Coastguard Worker                               const std::string& description) {
1253*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(stream_id, 0u);
1254*6777b538SAndroid Build Coastguard Worker 
1255*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
1256*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end()) {
1257*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
1258*6777b538SAndroid Build Coastguard Worker     return;
1259*6777b538SAndroid Build Coastguard Worker   }
1260*6777b538SAndroid Build Coastguard Worker 
1261*6777b538SAndroid Build Coastguard Worker   ResetStreamIterator(it, error, description);
1262*6777b538SAndroid Build Coastguard Worker }
1263*6777b538SAndroid Build Coastguard Worker 
IsStreamActive(spdy::SpdyStreamId stream_id) const1264*6777b538SAndroid Build Coastguard Worker bool SpdySession::IsStreamActive(spdy::SpdyStreamId stream_id) const {
1265*6777b538SAndroid Build Coastguard Worker   return base::Contains(active_streams_, stream_id);
1266*6777b538SAndroid Build Coastguard Worker }
1267*6777b538SAndroid Build Coastguard Worker 
GetLoadState() const1268*6777b538SAndroid Build Coastguard Worker LoadState SpdySession::GetLoadState() const {
1269*6777b538SAndroid Build Coastguard Worker   // Just report that we're idle since the session could be doing
1270*6777b538SAndroid Build Coastguard Worker   // many things concurrently.
1271*6777b538SAndroid Build Coastguard Worker   return LOAD_STATE_IDLE;
1272*6777b538SAndroid Build Coastguard Worker }
1273*6777b538SAndroid Build Coastguard Worker 
GetRemoteEndpoint(IPEndPoint * endpoint)1274*6777b538SAndroid Build Coastguard Worker int SpdySession::GetRemoteEndpoint(IPEndPoint* endpoint) {
1275*6777b538SAndroid Build Coastguard Worker   return GetPeerAddress(endpoint);
1276*6777b538SAndroid Build Coastguard Worker }
1277*6777b538SAndroid Build Coastguard Worker 
GetSSLInfo(SSLInfo * ssl_info) const1278*6777b538SAndroid Build Coastguard Worker bool SpdySession::GetSSLInfo(SSLInfo* ssl_info) const {
1279*6777b538SAndroid Build Coastguard Worker   return socket_->GetSSLInfo(ssl_info);
1280*6777b538SAndroid Build Coastguard Worker }
1281*6777b538SAndroid Build Coastguard Worker 
GetAcceptChViaAlps(const url::SchemeHostPort & scheme_host_port) const1282*6777b538SAndroid Build Coastguard Worker std::string_view SpdySession::GetAcceptChViaAlps(
1283*6777b538SAndroid Build Coastguard Worker     const url::SchemeHostPort& scheme_host_port) const {
1284*6777b538SAndroid Build Coastguard Worker   auto it = accept_ch_entries_received_via_alps_.find(scheme_host_port);
1285*6777b538SAndroid Build Coastguard Worker   if (it == accept_ch_entries_received_via_alps_.end()) {
1286*6777b538SAndroid Build Coastguard Worker     LogSpdyAcceptChForOriginHistogram(false);
1287*6777b538SAndroid Build Coastguard Worker     return {};
1288*6777b538SAndroid Build Coastguard Worker   }
1289*6777b538SAndroid Build Coastguard Worker 
1290*6777b538SAndroid Build Coastguard Worker   LogSpdyAcceptChForOriginHistogram(true);
1291*6777b538SAndroid Build Coastguard Worker   return it->second;
1292*6777b538SAndroid Build Coastguard Worker }
1293*6777b538SAndroid Build Coastguard Worker 
GetNegotiatedProtocol() const1294*6777b538SAndroid Build Coastguard Worker NextProto SpdySession::GetNegotiatedProtocol() const {
1295*6777b538SAndroid Build Coastguard Worker   return socket_->GetNegotiatedProtocol();
1296*6777b538SAndroid Build Coastguard Worker }
1297*6777b538SAndroid Build Coastguard Worker 
SendStreamWindowUpdate(spdy::SpdyStreamId stream_id,uint32_t delta_window_size)1298*6777b538SAndroid Build Coastguard Worker void SpdySession::SendStreamWindowUpdate(spdy::SpdyStreamId stream_id,
1299*6777b538SAndroid Build Coastguard Worker                                          uint32_t delta_window_size) {
1300*6777b538SAndroid Build Coastguard Worker   ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
1301*6777b538SAndroid Build Coastguard Worker   CHECK(it != active_streams_.end());
1302*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(it->second->stream_id(), stream_id);
1303*6777b538SAndroid Build Coastguard Worker   SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority());
1304*6777b538SAndroid Build Coastguard Worker }
1305*6777b538SAndroid Build Coastguard Worker 
CloseSessionOnError(Error err,const std::string & description)1306*6777b538SAndroid Build Coastguard Worker void SpdySession::CloseSessionOnError(Error err,
1307*6777b538SAndroid Build Coastguard Worker                                       const std::string& description) {
1308*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(err, ERR_IO_PENDING);
1309*6777b538SAndroid Build Coastguard Worker   DoDrainSession(err, description);
1310*6777b538SAndroid Build Coastguard Worker }
1311*6777b538SAndroid Build Coastguard Worker 
MakeUnavailable()1312*6777b538SAndroid Build Coastguard Worker void SpdySession::MakeUnavailable() {
1313*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_AVAILABLE) {
1314*6777b538SAndroid Build Coastguard Worker     availability_state_ = STATE_GOING_AWAY;
1315*6777b538SAndroid Build Coastguard Worker     pool_->MakeSessionUnavailable(GetWeakPtr());
1316*6777b538SAndroid Build Coastguard Worker   }
1317*6777b538SAndroid Build Coastguard Worker }
1318*6777b538SAndroid Build Coastguard Worker 
StartGoingAway(spdy::SpdyStreamId last_good_stream_id,Error status)1319*6777b538SAndroid Build Coastguard Worker void SpdySession::StartGoingAway(spdy::SpdyStreamId last_good_stream_id,
1320*6777b538SAndroid Build Coastguard Worker                                  Error status) {
1321*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1322*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(OK, status);
1323*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(ERR_IO_PENDING, status);
1324*6777b538SAndroid Build Coastguard Worker 
1325*6777b538SAndroid Build Coastguard Worker   // The loops below are carefully written to avoid reentrancy problems.
1326*6777b538SAndroid Build Coastguard Worker 
1327*6777b538SAndroid Build Coastguard Worker   NotifyRequestsOfConfirmation(status);
1328*6777b538SAndroid Build Coastguard Worker 
1329*6777b538SAndroid Build Coastguard Worker   while (true) {
1330*6777b538SAndroid Build Coastguard Worker     size_t old_size = GetTotalSize(pending_create_stream_queues_);
1331*6777b538SAndroid Build Coastguard Worker     base::WeakPtr<SpdyStreamRequest> pending_request =
1332*6777b538SAndroid Build Coastguard Worker         GetNextPendingStreamRequest();
1333*6777b538SAndroid Build Coastguard Worker     if (!pending_request)
1334*6777b538SAndroid Build Coastguard Worker       break;
1335*6777b538SAndroid Build Coastguard Worker     // No new stream requests should be added while the session is
1336*6777b538SAndroid Build Coastguard Worker     // going away.
1337*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_));
1338*6777b538SAndroid Build Coastguard Worker     pending_request->OnRequestCompleteFailure(status);
1339*6777b538SAndroid Build Coastguard Worker   }
1340*6777b538SAndroid Build Coastguard Worker 
1341*6777b538SAndroid Build Coastguard Worker   while (true) {
1342*6777b538SAndroid Build Coastguard Worker     size_t old_size = active_streams_.size();
1343*6777b538SAndroid Build Coastguard Worker     auto it = active_streams_.lower_bound(last_good_stream_id + 1);
1344*6777b538SAndroid Build Coastguard Worker     if (it == active_streams_.end())
1345*6777b538SAndroid Build Coastguard Worker       break;
1346*6777b538SAndroid Build Coastguard Worker     LogAbandonedActiveStream(it, status);
1347*6777b538SAndroid Build Coastguard Worker     CloseActiveStreamIterator(it, status);
1348*6777b538SAndroid Build Coastguard Worker     // No new streams should be activated while the session is going
1349*6777b538SAndroid Build Coastguard Worker     // away.
1350*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(old_size, active_streams_.size());
1351*6777b538SAndroid Build Coastguard Worker   }
1352*6777b538SAndroid Build Coastguard Worker 
1353*6777b538SAndroid Build Coastguard Worker   while (!created_streams_.empty()) {
1354*6777b538SAndroid Build Coastguard Worker     size_t old_size = created_streams_.size();
1355*6777b538SAndroid Build Coastguard Worker     auto it = created_streams_.begin();
1356*6777b538SAndroid Build Coastguard Worker     LogAbandonedStream(*it, status);
1357*6777b538SAndroid Build Coastguard Worker     CloseCreatedStreamIterator(it, status);
1358*6777b538SAndroid Build Coastguard Worker     // No new streams should be created while the session is going
1359*6777b538SAndroid Build Coastguard Worker     // away.
1360*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(old_size, created_streams_.size());
1361*6777b538SAndroid Build Coastguard Worker   }
1362*6777b538SAndroid Build Coastguard Worker 
1363*6777b538SAndroid Build Coastguard Worker   write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id);
1364*6777b538SAndroid Build Coastguard Worker 
1365*6777b538SAndroid Build Coastguard Worker   DcheckGoingAway();
1366*6777b538SAndroid Build Coastguard Worker   MaybeFinishGoingAway();
1367*6777b538SAndroid Build Coastguard Worker }
1368*6777b538SAndroid Build Coastguard Worker 
MaybeFinishGoingAway()1369*6777b538SAndroid Build Coastguard Worker void SpdySession::MaybeFinishGoingAway() {
1370*6777b538SAndroid Build Coastguard Worker   if (active_streams_.empty() && created_streams_.empty() &&
1371*6777b538SAndroid Build Coastguard Worker       availability_state_ == STATE_GOING_AWAY) {
1372*6777b538SAndroid Build Coastguard Worker     DoDrainSession(OK, "Finished going away");
1373*6777b538SAndroid Build Coastguard Worker   }
1374*6777b538SAndroid Build Coastguard Worker }
1375*6777b538SAndroid Build Coastguard Worker 
GetInfoAsValue() const1376*6777b538SAndroid Build Coastguard Worker base::Value::Dict SpdySession::GetInfoAsValue() const {
1377*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1378*6777b538SAndroid Build Coastguard Worker 
1379*6777b538SAndroid Build Coastguard Worker   auto dict =
1380*6777b538SAndroid Build Coastguard Worker       base::Value::Dict()
1381*6777b538SAndroid Build Coastguard Worker           .Set("source_id", static_cast<int>(net_log_.source().id))
1382*6777b538SAndroid Build Coastguard Worker           .Set("host_port_pair", host_port_pair().ToString())
1383*6777b538SAndroid Build Coastguard Worker           .Set("proxy", host_port_proxy_pair().second.ToDebugString())
1384*6777b538SAndroid Build Coastguard Worker           .Set("network_anonymization_key",
1385*6777b538SAndroid Build Coastguard Worker                spdy_session_key_.network_anonymization_key().ToDebugString())
1386*6777b538SAndroid Build Coastguard Worker           .Set("active_streams", static_cast<int>(active_streams_.size()))
1387*6777b538SAndroid Build Coastguard Worker           .Set("negotiated_protocol",
1388*6777b538SAndroid Build Coastguard Worker                NextProtoToString(socket_->GetNegotiatedProtocol()))
1389*6777b538SAndroid Build Coastguard Worker           .Set("error", error_on_close_)
1390*6777b538SAndroid Build Coastguard Worker           .Set("max_concurrent_streams",
1391*6777b538SAndroid Build Coastguard Worker                static_cast<int>(max_concurrent_streams_))
1392*6777b538SAndroid Build Coastguard Worker           .Set("streams_initiated_count", streams_initiated_count_)
1393*6777b538SAndroid Build Coastguard Worker           .Set("streams_abandoned_count", streams_abandoned_count_)
1394*6777b538SAndroid Build Coastguard Worker           .Set("frames_received", buffered_spdy_framer_->frames_received())
1395*6777b538SAndroid Build Coastguard Worker           .Set("send_window_size", session_send_window_size_)
1396*6777b538SAndroid Build Coastguard Worker           .Set("recv_window_size", session_recv_window_size_)
1397*6777b538SAndroid Build Coastguard Worker           .Set("unacked_recv_window_bytes", session_unacked_recv_window_bytes_);
1398*6777b538SAndroid Build Coastguard Worker 
1399*6777b538SAndroid Build Coastguard Worker   if (!pooled_aliases_.empty()) {
1400*6777b538SAndroid Build Coastguard Worker     base::Value::List alias_list;
1401*6777b538SAndroid Build Coastguard Worker     for (const auto& alias : pooled_aliases_) {
1402*6777b538SAndroid Build Coastguard Worker       alias_list.Append(alias.host_port_pair().ToString());
1403*6777b538SAndroid Build Coastguard Worker     }
1404*6777b538SAndroid Build Coastguard Worker     dict.Set("aliases", std::move(alias_list));
1405*6777b538SAndroid Build Coastguard Worker   }
1406*6777b538SAndroid Build Coastguard Worker   return dict;
1407*6777b538SAndroid Build Coastguard Worker }
1408*6777b538SAndroid Build Coastguard Worker 
IsReused() const1409*6777b538SAndroid Build Coastguard Worker bool SpdySession::IsReused() const {
1410*6777b538SAndroid Build Coastguard Worker   if (buffered_spdy_framer_->frames_received() > 0)
1411*6777b538SAndroid Build Coastguard Worker     return true;
1412*6777b538SAndroid Build Coastguard Worker 
1413*6777b538SAndroid Build Coastguard Worker   // If there's no socket pool in use (i.e., |owned_stream_socket_| is
1414*6777b538SAndroid Build Coastguard Worker   // non-null), then the SpdySession could only have been created with freshly
1415*6777b538SAndroid Build Coastguard Worker   // connected socket, since canceling the H2 session request would have
1416*6777b538SAndroid Build Coastguard Worker   // destroyed the socket.
1417*6777b538SAndroid Build Coastguard Worker   return owned_stream_socket_ ||
1418*6777b538SAndroid Build Coastguard Worker          client_socket_handle_->reuse_type() == ClientSocketHandle::UNUSED_IDLE;
1419*6777b538SAndroid Build Coastguard Worker }
1420*6777b538SAndroid Build Coastguard Worker 
GetLoadTimingInfo(spdy::SpdyStreamId stream_id,LoadTimingInfo * load_timing_info) const1421*6777b538SAndroid Build Coastguard Worker bool SpdySession::GetLoadTimingInfo(spdy::SpdyStreamId stream_id,
1422*6777b538SAndroid Build Coastguard Worker                                     LoadTimingInfo* load_timing_info) const {
1423*6777b538SAndroid Build Coastguard Worker   if (client_socket_handle_) {
1424*6777b538SAndroid Build Coastguard Worker     DCHECK(!connect_timing_);
1425*6777b538SAndroid Build Coastguard Worker     return client_socket_handle_->GetLoadTimingInfo(stream_id != kFirstStreamId,
1426*6777b538SAndroid Build Coastguard Worker                                                     load_timing_info);
1427*6777b538SAndroid Build Coastguard Worker   }
1428*6777b538SAndroid Build Coastguard Worker 
1429*6777b538SAndroid Build Coastguard Worker   DCHECK(connect_timing_);
1430*6777b538SAndroid Build Coastguard Worker   DCHECK(socket_);
1431*6777b538SAndroid Build Coastguard Worker 
1432*6777b538SAndroid Build Coastguard Worker   // The socket is considered "fresh" (not reused) only for the first stream on
1433*6777b538SAndroid Build Coastguard Worker   // a SPDY session. All others consider it reused, and don't return connection
1434*6777b538SAndroid Build Coastguard Worker   // establishment timing information.
1435*6777b538SAndroid Build Coastguard Worker   load_timing_info->socket_reused = (stream_id != kFirstStreamId);
1436*6777b538SAndroid Build Coastguard Worker   if (!load_timing_info->socket_reused)
1437*6777b538SAndroid Build Coastguard Worker     load_timing_info->connect_timing = *connect_timing_;
1438*6777b538SAndroid Build Coastguard Worker 
1439*6777b538SAndroid Build Coastguard Worker   load_timing_info->socket_log_id = socket_->NetLog().source().id;
1440*6777b538SAndroid Build Coastguard Worker 
1441*6777b538SAndroid Build Coastguard Worker   return true;
1442*6777b538SAndroid Build Coastguard Worker }
1443*6777b538SAndroid Build Coastguard Worker 
GetPeerAddress(IPEndPoint * address) const1444*6777b538SAndroid Build Coastguard Worker int SpdySession::GetPeerAddress(IPEndPoint* address) const {
1445*6777b538SAndroid Build Coastguard Worker   if (socket_)
1446*6777b538SAndroid Build Coastguard Worker     return socket_->GetPeerAddress(address);
1447*6777b538SAndroid Build Coastguard Worker 
1448*6777b538SAndroid Build Coastguard Worker   return ERR_SOCKET_NOT_CONNECTED;
1449*6777b538SAndroid Build Coastguard Worker }
1450*6777b538SAndroid Build Coastguard Worker 
GetLocalAddress(IPEndPoint * address) const1451*6777b538SAndroid Build Coastguard Worker int SpdySession::GetLocalAddress(IPEndPoint* address) const {
1452*6777b538SAndroid Build Coastguard Worker   if (socket_)
1453*6777b538SAndroid Build Coastguard Worker     return socket_->GetLocalAddress(address);
1454*6777b538SAndroid Build Coastguard Worker 
1455*6777b538SAndroid Build Coastguard Worker   return ERR_SOCKET_NOT_CONNECTED;
1456*6777b538SAndroid Build Coastguard Worker }
1457*6777b538SAndroid Build Coastguard Worker 
AddPooledAlias(const SpdySessionKey & alias_key)1458*6777b538SAndroid Build Coastguard Worker void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
1459*6777b538SAndroid Build Coastguard Worker   pooled_aliases_.insert(alias_key);
1460*6777b538SAndroid Build Coastguard Worker }
1461*6777b538SAndroid Build Coastguard Worker 
RemovePooledAlias(const SpdySessionKey & alias_key)1462*6777b538SAndroid Build Coastguard Worker void SpdySession::RemovePooledAlias(const SpdySessionKey& alias_key) {
1463*6777b538SAndroid Build Coastguard Worker   pooled_aliases_.erase(alias_key);
1464*6777b538SAndroid Build Coastguard Worker }
1465*6777b538SAndroid Build Coastguard Worker 
HasAcceptableTransportSecurity() const1466*6777b538SAndroid Build Coastguard Worker bool SpdySession::HasAcceptableTransportSecurity() const {
1467*6777b538SAndroid Build Coastguard Worker   SSLInfo ssl_info;
1468*6777b538SAndroid Build Coastguard Worker   CHECK(GetSSLInfo(&ssl_info));
1469*6777b538SAndroid Build Coastguard Worker 
1470*6777b538SAndroid Build Coastguard Worker   // HTTP/2 requires TLS 1.2+
1471*6777b538SAndroid Build Coastguard Worker   if (SSLConnectionStatusToVersion(ssl_info.connection_status) <
1472*6777b538SAndroid Build Coastguard Worker       SSL_CONNECTION_VERSION_TLS1_2) {
1473*6777b538SAndroid Build Coastguard Worker     return false;
1474*6777b538SAndroid Build Coastguard Worker   }
1475*6777b538SAndroid Build Coastguard Worker 
1476*6777b538SAndroid Build Coastguard Worker   if (!IsTLSCipherSuiteAllowedByHTTP2(
1477*6777b538SAndroid Build Coastguard Worker           SSLConnectionStatusToCipherSuite(ssl_info.connection_status))) {
1478*6777b538SAndroid Build Coastguard Worker     return false;
1479*6777b538SAndroid Build Coastguard Worker   }
1480*6777b538SAndroid Build Coastguard Worker 
1481*6777b538SAndroid Build Coastguard Worker   return true;
1482*6777b538SAndroid Build Coastguard Worker }
1483*6777b538SAndroid Build Coastguard Worker 
GetWeakPtr()1484*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdySession> SpdySession::GetWeakPtr() {
1485*6777b538SAndroid Build Coastguard Worker   return weak_factory_.GetWeakPtr();
1486*6777b538SAndroid Build Coastguard Worker }
1487*6777b538SAndroid Build Coastguard Worker 
CloseOneIdleConnection()1488*6777b538SAndroid Build Coastguard Worker bool SpdySession::CloseOneIdleConnection() {
1489*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1490*6777b538SAndroid Build Coastguard Worker   DCHECK(pool_);
1491*6777b538SAndroid Build Coastguard Worker   if (active_streams_.empty()) {
1492*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1493*6777b538SAndroid Build Coastguard Worker   }
1494*6777b538SAndroid Build Coastguard Worker   // Return false as the socket wasn't immediately closed.
1495*6777b538SAndroid Build Coastguard Worker   return false;
1496*6777b538SAndroid Build Coastguard Worker }
1497*6777b538SAndroid Build Coastguard Worker 
ChangeSocketTag(const SocketTag & new_tag)1498*6777b538SAndroid Build Coastguard Worker bool SpdySession::ChangeSocketTag(const SocketTag& new_tag) {
1499*6777b538SAndroid Build Coastguard Worker   if (!IsAvailable() || !socket_)
1500*6777b538SAndroid Build Coastguard Worker     return false;
1501*6777b538SAndroid Build Coastguard Worker 
1502*6777b538SAndroid Build Coastguard Worker   // Changing the tag on the underlying socket will affect all streams,
1503*6777b538SAndroid Build Coastguard Worker   // so only allow changing the tag when there are no active streams.
1504*6777b538SAndroid Build Coastguard Worker   if (is_active())
1505*6777b538SAndroid Build Coastguard Worker     return false;
1506*6777b538SAndroid Build Coastguard Worker 
1507*6777b538SAndroid Build Coastguard Worker   socket_->ApplySocketTag(new_tag);
1508*6777b538SAndroid Build Coastguard Worker 
1509*6777b538SAndroid Build Coastguard Worker   SpdySessionKey new_key(
1510*6777b538SAndroid Build Coastguard Worker       spdy_session_key_.host_port_pair(), spdy_session_key_.privacy_mode(),
1511*6777b538SAndroid Build Coastguard Worker       spdy_session_key_.proxy_chain(), spdy_session_key_.session_usage(),
1512*6777b538SAndroid Build Coastguard Worker       new_tag, spdy_session_key_.network_anonymization_key(),
1513*6777b538SAndroid Build Coastguard Worker       spdy_session_key_.secure_dns_policy(),
1514*6777b538SAndroid Build Coastguard Worker       spdy_session_key_.disable_cert_verification_network_fetches());
1515*6777b538SAndroid Build Coastguard Worker   spdy_session_key_ = new_key;
1516*6777b538SAndroid Build Coastguard Worker 
1517*6777b538SAndroid Build Coastguard Worker   return true;
1518*6777b538SAndroid Build Coastguard Worker }
1519*6777b538SAndroid Build Coastguard Worker 
EnableBrokenConnectionDetection(base::TimeDelta heartbeat_interval)1520*6777b538SAndroid Build Coastguard Worker void SpdySession::EnableBrokenConnectionDetection(
1521*6777b538SAndroid Build Coastguard Worker     base::TimeDelta heartbeat_interval) {
1522*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(broken_connection_detection_requests_, 0);
1523*6777b538SAndroid Build Coastguard Worker   if (broken_connection_detection_requests_++ > 0)
1524*6777b538SAndroid Build Coastguard Worker     return;
1525*6777b538SAndroid Build Coastguard Worker 
1526*6777b538SAndroid Build Coastguard Worker   DCHECK(!IsBrokenConnectionDetectionEnabled());
1527*6777b538SAndroid Build Coastguard Worker   NetworkChangeNotifier::AddDefaultNetworkActiveObserver(this);
1528*6777b538SAndroid Build Coastguard Worker   heartbeat_interval_ = heartbeat_interval;
1529*6777b538SAndroid Build Coastguard Worker   heartbeat_timer_.Start(
1530*6777b538SAndroid Build Coastguard Worker       FROM_HERE, heartbeat_interval_,
1531*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::MaybeCheckConnectionStatus,
1532*6777b538SAndroid Build Coastguard Worker                      weak_factory_.GetWeakPtr()));
1533*6777b538SAndroid Build Coastguard Worker }
1534*6777b538SAndroid Build Coastguard Worker 
IsBrokenConnectionDetectionEnabled() const1535*6777b538SAndroid Build Coastguard Worker bool SpdySession::IsBrokenConnectionDetectionEnabled() const {
1536*6777b538SAndroid Build Coastguard Worker   return heartbeat_timer_.IsRunning();
1537*6777b538SAndroid Build Coastguard Worker }
1538*6777b538SAndroid Build Coastguard Worker 
InitializeInternal(SpdySessionPool * pool)1539*6777b538SAndroid Build Coastguard Worker void SpdySession::InitializeInternal(SpdySessionPool* pool) {
1540*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1541*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(availability_state_, STATE_AVAILABLE);
1542*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(read_state_, READ_STATE_DO_READ);
1543*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(write_state_, WRITE_STATE_IDLE);
1544*6777b538SAndroid Build Coastguard Worker 
1545*6777b538SAndroid Build Coastguard Worker   session_send_window_size_ = kDefaultInitialWindowSize;
1546*6777b538SAndroid Build Coastguard Worker   session_recv_window_size_ = kDefaultInitialWindowSize;
1547*6777b538SAndroid Build Coastguard Worker 
1548*6777b538SAndroid Build Coastguard Worker   buffered_spdy_framer_ = std::make_unique<BufferedSpdyFramer>(
1549*6777b538SAndroid Build Coastguard Worker       initial_settings_.find(spdy::SETTINGS_MAX_HEADER_LIST_SIZE)->second,
1550*6777b538SAndroid Build Coastguard Worker       net_log_, time_func_);
1551*6777b538SAndroid Build Coastguard Worker   buffered_spdy_framer_->set_visitor(this);
1552*6777b538SAndroid Build Coastguard Worker   buffered_spdy_framer_->set_debug_visitor(this);
1553*6777b538SAndroid Build Coastguard Worker   buffered_spdy_framer_->UpdateHeaderDecoderTableSize(max_header_table_size_);
1554*6777b538SAndroid Build Coastguard Worker 
1555*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_INITIALIZED, [&] {
1556*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyInitializedParams(socket_->NetLog().source());
1557*6777b538SAndroid Build Coastguard Worker   });
1558*6777b538SAndroid Build Coastguard Worker 
1559*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(availability_state_, STATE_AVAILABLE);
1560*6777b538SAndroid Build Coastguard Worker   if (enable_sending_initial_data_)
1561*6777b538SAndroid Build Coastguard Worker     SendInitialData();
1562*6777b538SAndroid Build Coastguard Worker   pool_ = pool;
1563*6777b538SAndroid Build Coastguard Worker 
1564*6777b538SAndroid Build Coastguard Worker   // Bootstrap the read loop.
1565*6777b538SAndroid Build Coastguard Worker   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1566*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
1567*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
1568*6777b538SAndroid Build Coastguard Worker                      READ_STATE_DO_READ, OK));
1569*6777b538SAndroid Build Coastguard Worker }
1570*6777b538SAndroid Build Coastguard Worker 
1571*6777b538SAndroid Build Coastguard Worker // {,Try}CreateStream() can be called with |in_io_loop_| set if a stream is
1572*6777b538SAndroid Build Coastguard Worker // being created in response to another being closed due to received data.
1573*6777b538SAndroid Build Coastguard Worker 
TryCreateStream(const base::WeakPtr<SpdyStreamRequest> & request,base::WeakPtr<SpdyStream> * stream)1574*6777b538SAndroid Build Coastguard Worker int SpdySession::TryCreateStream(
1575*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStreamRequest>& request,
1576*6777b538SAndroid Build Coastguard Worker     base::WeakPtr<SpdyStream>* stream) {
1577*6777b538SAndroid Build Coastguard Worker   DCHECK(request);
1578*6777b538SAndroid Build Coastguard Worker 
1579*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_GOING_AWAY)
1580*6777b538SAndroid Build Coastguard Worker     return ERR_FAILED;
1581*6777b538SAndroid Build Coastguard Worker 
1582*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
1583*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
1584*6777b538SAndroid Build Coastguard Worker 
1585*6777b538SAndroid Build Coastguard Worker   // Fail if ChangeSocketTag() has been called.
1586*6777b538SAndroid Build Coastguard Worker   if (request->socket_tag_ != spdy_session_key_.socket_tag())
1587*6777b538SAndroid Build Coastguard Worker     return ERR_FAILED;
1588*6777b538SAndroid Build Coastguard Worker 
1589*6777b538SAndroid Build Coastguard Worker   if ((active_streams_.size() + created_streams_.size() <
1590*6777b538SAndroid Build Coastguard Worker        max_concurrent_streams_)) {
1591*6777b538SAndroid Build Coastguard Worker     return CreateStream(*request, stream);
1592*6777b538SAndroid Build Coastguard Worker   }
1593*6777b538SAndroid Build Coastguard Worker 
1594*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, [&] {
1595*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionStalledParams(
1596*6777b538SAndroid Build Coastguard Worker         active_streams_.size(), created_streams_.size(),
1597*6777b538SAndroid Build Coastguard Worker         max_concurrent_streams_, request->url().spec());
1598*6777b538SAndroid Build Coastguard Worker   });
1599*6777b538SAndroid Build Coastguard Worker 
1600*6777b538SAndroid Build Coastguard Worker   RequestPriority priority = request->priority();
1601*6777b538SAndroid Build Coastguard Worker   CHECK_GE(priority, MINIMUM_PRIORITY);
1602*6777b538SAndroid Build Coastguard Worker   CHECK_LE(priority, MAXIMUM_PRIORITY);
1603*6777b538SAndroid Build Coastguard Worker   pending_create_stream_queues_[priority].push_back(request);
1604*6777b538SAndroid Build Coastguard Worker   return ERR_IO_PENDING;
1605*6777b538SAndroid Build Coastguard Worker }
1606*6777b538SAndroid Build Coastguard Worker 
CreateStream(const SpdyStreamRequest & request,base::WeakPtr<SpdyStream> * stream)1607*6777b538SAndroid Build Coastguard Worker int SpdySession::CreateStream(const SpdyStreamRequest& request,
1608*6777b538SAndroid Build Coastguard Worker                               base::WeakPtr<SpdyStream>* stream) {
1609*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
1610*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(request.priority(), MAXIMUM_PRIORITY);
1611*6777b538SAndroid Build Coastguard Worker 
1612*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_GOING_AWAY)
1613*6777b538SAndroid Build Coastguard Worker     return ERR_FAILED;
1614*6777b538SAndroid Build Coastguard Worker 
1615*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
1616*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
1617*6777b538SAndroid Build Coastguard Worker 
1618*6777b538SAndroid Build Coastguard Worker   DCHECK(socket_);
1619*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected",
1620*6777b538SAndroid Build Coastguard Worker                         socket_->IsConnected());
1621*6777b538SAndroid Build Coastguard Worker   if (!socket_->IsConnected()) {
1622*6777b538SAndroid Build Coastguard Worker     DoDrainSession(
1623*6777b538SAndroid Build Coastguard Worker         ERR_CONNECTION_CLOSED,
1624*6777b538SAndroid Build Coastguard Worker         "Tried to create SPDY stream for a closed socket connection.");
1625*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
1626*6777b538SAndroid Build Coastguard Worker   }
1627*6777b538SAndroid Build Coastguard Worker 
1628*6777b538SAndroid Build Coastguard Worker   auto new_stream = std::make_unique<SpdyStream>(
1629*6777b538SAndroid Build Coastguard Worker       request.type(), GetWeakPtr(), request.url(), request.priority(),
1630*6777b538SAndroid Build Coastguard Worker       stream_initial_send_window_size_, stream_max_recv_window_size_,
1631*6777b538SAndroid Build Coastguard Worker       request.net_log(), request.traffic_annotation(),
1632*6777b538SAndroid Build Coastguard Worker       request.detect_broken_connection_);
1633*6777b538SAndroid Build Coastguard Worker   *stream = new_stream->GetWeakPtr();
1634*6777b538SAndroid Build Coastguard Worker   InsertCreatedStream(std::move(new_stream));
1635*6777b538SAndroid Build Coastguard Worker   if (request.detect_broken_connection_)
1636*6777b538SAndroid Build Coastguard Worker     EnableBrokenConnectionDetection(request.heartbeat_interval_);
1637*6777b538SAndroid Build Coastguard Worker 
1638*6777b538SAndroid Build Coastguard Worker   return OK;
1639*6777b538SAndroid Build Coastguard Worker }
1640*6777b538SAndroid Build Coastguard Worker 
CancelStreamRequest(const base::WeakPtr<SpdyStreamRequest> & request)1641*6777b538SAndroid Build Coastguard Worker bool SpdySession::CancelStreamRequest(
1642*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStreamRequest>& request) {
1643*6777b538SAndroid Build Coastguard Worker   DCHECK(request);
1644*6777b538SAndroid Build Coastguard Worker   RequestPriority priority = request->priority();
1645*6777b538SAndroid Build Coastguard Worker   CHECK_GE(priority, MINIMUM_PRIORITY);
1646*6777b538SAndroid Build Coastguard Worker   CHECK_LE(priority, MAXIMUM_PRIORITY);
1647*6777b538SAndroid Build Coastguard Worker 
1648*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
1649*6777b538SAndroid Build Coastguard Worker   // |request| should not be in a queue not matching its priority.
1650*6777b538SAndroid Build Coastguard Worker   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
1651*6777b538SAndroid Build Coastguard Worker     if (priority == i)
1652*6777b538SAndroid Build Coastguard Worker       continue;
1653*6777b538SAndroid Build Coastguard Worker     DCHECK(!base::Contains(pending_create_stream_queues_[i], request.get(),
1654*6777b538SAndroid Build Coastguard Worker                            &base::WeakPtr<SpdyStreamRequest>::get));
1655*6777b538SAndroid Build Coastguard Worker   }
1656*6777b538SAndroid Build Coastguard Worker #endif
1657*6777b538SAndroid Build Coastguard Worker 
1658*6777b538SAndroid Build Coastguard Worker   PendingStreamRequestQueue* queue = &pending_create_stream_queues_[priority];
1659*6777b538SAndroid Build Coastguard Worker   // Remove |request| from |queue| while preserving the order of the
1660*6777b538SAndroid Build Coastguard Worker   // other elements.
1661*6777b538SAndroid Build Coastguard Worker   PendingStreamRequestQueue::iterator it = base::ranges::find(
1662*6777b538SAndroid Build Coastguard Worker       *queue, request.get(), &base::WeakPtr<SpdyStreamRequest>::get);
1663*6777b538SAndroid Build Coastguard Worker   // The request may already be removed if there's a
1664*6777b538SAndroid Build Coastguard Worker   // CompleteStreamRequest() in flight.
1665*6777b538SAndroid Build Coastguard Worker   if (it != queue->end()) {
1666*6777b538SAndroid Build Coastguard Worker     it = queue->erase(it);
1667*6777b538SAndroid Build Coastguard Worker     // |request| should be in the queue at most once, and if it is
1668*6777b538SAndroid Build Coastguard Worker     // present, should not be pending completion.
1669*6777b538SAndroid Build Coastguard Worker     DCHECK(base::ranges::find(it, queue->end(), request.get(),
1670*6777b538SAndroid Build Coastguard Worker                               &base::WeakPtr<SpdyStreamRequest>::get) ==
1671*6777b538SAndroid Build Coastguard Worker            queue->end());
1672*6777b538SAndroid Build Coastguard Worker     return true;
1673*6777b538SAndroid Build Coastguard Worker   }
1674*6777b538SAndroid Build Coastguard Worker   return false;
1675*6777b538SAndroid Build Coastguard Worker }
1676*6777b538SAndroid Build Coastguard Worker 
ChangeStreamRequestPriority(const base::WeakPtr<SpdyStreamRequest> & request,RequestPriority priority)1677*6777b538SAndroid Build Coastguard Worker void SpdySession::ChangeStreamRequestPriority(
1678*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStreamRequest>& request,
1679*6777b538SAndroid Build Coastguard Worker     RequestPriority priority) {
1680*6777b538SAndroid Build Coastguard Worker   // |request->priority()| is updated by the caller after this returns.
1681*6777b538SAndroid Build Coastguard Worker   // |request| needs to still have its old priority in order for
1682*6777b538SAndroid Build Coastguard Worker   // CancelStreamRequest() to find it in the correct queue.
1683*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(priority, request->priority());
1684*6777b538SAndroid Build Coastguard Worker   if (CancelStreamRequest(request)) {
1685*6777b538SAndroid Build Coastguard Worker     pending_create_stream_queues_[priority].push_back(request);
1686*6777b538SAndroid Build Coastguard Worker   }
1687*6777b538SAndroid Build Coastguard Worker }
1688*6777b538SAndroid Build Coastguard Worker 
GetNextPendingStreamRequest()1689*6777b538SAndroid Build Coastguard Worker base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() {
1690*6777b538SAndroid Build Coastguard Worker   for (int j = MAXIMUM_PRIORITY; j >= MINIMUM_PRIORITY; --j) {
1691*6777b538SAndroid Build Coastguard Worker     if (pending_create_stream_queues_[j].empty())
1692*6777b538SAndroid Build Coastguard Worker       continue;
1693*6777b538SAndroid Build Coastguard Worker 
1694*6777b538SAndroid Build Coastguard Worker     base::WeakPtr<SpdyStreamRequest> pending_request =
1695*6777b538SAndroid Build Coastguard Worker         pending_create_stream_queues_[j].front();
1696*6777b538SAndroid Build Coastguard Worker     DCHECK(pending_request);
1697*6777b538SAndroid Build Coastguard Worker     pending_create_stream_queues_[j].pop_front();
1698*6777b538SAndroid Build Coastguard Worker     return pending_request;
1699*6777b538SAndroid Build Coastguard Worker   }
1700*6777b538SAndroid Build Coastguard Worker   return base::WeakPtr<SpdyStreamRequest>();
1701*6777b538SAndroid Build Coastguard Worker }
1702*6777b538SAndroid Build Coastguard Worker 
ProcessPendingStreamRequests()1703*6777b538SAndroid Build Coastguard Worker void SpdySession::ProcessPendingStreamRequests() {
1704*6777b538SAndroid Build Coastguard Worker   size_t max_requests_to_process =
1705*6777b538SAndroid Build Coastguard Worker       max_concurrent_streams_ -
1706*6777b538SAndroid Build Coastguard Worker       (active_streams_.size() + created_streams_.size());
1707*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < max_requests_to_process; ++i) {
1708*6777b538SAndroid Build Coastguard Worker     base::WeakPtr<SpdyStreamRequest> pending_request =
1709*6777b538SAndroid Build Coastguard Worker         GetNextPendingStreamRequest();
1710*6777b538SAndroid Build Coastguard Worker     if (!pending_request)
1711*6777b538SAndroid Build Coastguard Worker       break;
1712*6777b538SAndroid Build Coastguard Worker 
1713*6777b538SAndroid Build Coastguard Worker     // Note that this post can race with other stream creations, and it's
1714*6777b538SAndroid Build Coastguard Worker     // possible that the un-stalled stream will be stalled again if it loses.
1715*6777b538SAndroid Build Coastguard Worker     // TODO(jgraettinger): Provide stronger ordering guarantees.
1716*6777b538SAndroid Build Coastguard Worker     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1717*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(&SpdySession::CompleteStreamRequest,
1718*6777b538SAndroid Build Coastguard Worker                                   weak_factory_.GetWeakPtr(), pending_request));
1719*6777b538SAndroid Build Coastguard Worker   }
1720*6777b538SAndroid Build Coastguard Worker }
1721*6777b538SAndroid Build Coastguard Worker 
CloseActiveStreamIterator(ActiveStreamMap::iterator it,int status)1722*6777b538SAndroid Build Coastguard Worker void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1723*6777b538SAndroid Build Coastguard Worker                                             int status) {
1724*6777b538SAndroid Build Coastguard Worker   // TODO(mbelshe): We should send a RST_STREAM control frame here
1725*6777b538SAndroid Build Coastguard Worker   //                so that the server can cancel a large send.
1726*6777b538SAndroid Build Coastguard Worker 
1727*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SpdyStream> owned_stream(it->second);
1728*6777b538SAndroid Build Coastguard Worker   active_streams_.erase(it);
1729*6777b538SAndroid Build Coastguard Worker   priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id());
1730*6777b538SAndroid Build Coastguard Worker 
1731*6777b538SAndroid Build Coastguard Worker   DeleteStream(std::move(owned_stream), status);
1732*6777b538SAndroid Build Coastguard Worker 
1733*6777b538SAndroid Build Coastguard Worker   if (active_streams_.empty() && created_streams_.empty()) {
1734*6777b538SAndroid Build Coastguard Worker     // If the socket belongs to a socket pool, and there are no active streams,
1735*6777b538SAndroid Build Coastguard Worker     // and the socket pool is stalled, then close the session to free up a
1736*6777b538SAndroid Build Coastguard Worker     // socket slot.
1737*6777b538SAndroid Build Coastguard Worker     if (client_socket_handle_ && client_socket_handle_->IsPoolStalled()) {
1738*6777b538SAndroid Build Coastguard Worker       DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1739*6777b538SAndroid Build Coastguard Worker     } else {
1740*6777b538SAndroid Build Coastguard Worker       MaybeFinishGoingAway();
1741*6777b538SAndroid Build Coastguard Worker     }
1742*6777b538SAndroid Build Coastguard Worker   }
1743*6777b538SAndroid Build Coastguard Worker }
1744*6777b538SAndroid Build Coastguard Worker 
CloseCreatedStreamIterator(CreatedStreamSet::iterator it,int status)1745*6777b538SAndroid Build Coastguard Worker void SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
1746*6777b538SAndroid Build Coastguard Worker                                              int status) {
1747*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SpdyStream> owned_stream(*it);
1748*6777b538SAndroid Build Coastguard Worker   created_streams_.erase(it);
1749*6777b538SAndroid Build Coastguard Worker   DeleteStream(std::move(owned_stream), status);
1750*6777b538SAndroid Build Coastguard Worker }
1751*6777b538SAndroid Build Coastguard Worker 
ResetStreamIterator(ActiveStreamMap::iterator it,int error,const std::string & description)1752*6777b538SAndroid Build Coastguard Worker void SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
1753*6777b538SAndroid Build Coastguard Worker                                       int error,
1754*6777b538SAndroid Build Coastguard Worker                                       const std::string& description) {
1755*6777b538SAndroid Build Coastguard Worker   // Send the RST_STREAM frame first as CloseActiveStreamIterator()
1756*6777b538SAndroid Build Coastguard Worker   // may close us.
1757*6777b538SAndroid Build Coastguard Worker   spdy::SpdyErrorCode error_code = spdy::ERROR_CODE_PROTOCOL_ERROR;
1758*6777b538SAndroid Build Coastguard Worker   if (error == ERR_FAILED) {
1759*6777b538SAndroid Build Coastguard Worker     error_code = spdy::ERROR_CODE_INTERNAL_ERROR;
1760*6777b538SAndroid Build Coastguard Worker   } else if (error == ERR_ABORTED) {
1761*6777b538SAndroid Build Coastguard Worker     error_code = spdy::ERROR_CODE_CANCEL;
1762*6777b538SAndroid Build Coastguard Worker   } else if (error == ERR_HTTP2_FLOW_CONTROL_ERROR) {
1763*6777b538SAndroid Build Coastguard Worker     error_code = spdy::ERROR_CODE_FLOW_CONTROL_ERROR;
1764*6777b538SAndroid Build Coastguard Worker   } else if (error == ERR_TIMED_OUT) {
1765*6777b538SAndroid Build Coastguard Worker     error_code = spdy::ERROR_CODE_REFUSED_STREAM;
1766*6777b538SAndroid Build Coastguard Worker   } else if (error == ERR_HTTP2_STREAM_CLOSED) {
1767*6777b538SAndroid Build Coastguard Worker     error_code = spdy::ERROR_CODE_STREAM_CLOSED;
1768*6777b538SAndroid Build Coastguard Worker   }
1769*6777b538SAndroid Build Coastguard Worker   spdy::SpdyStreamId stream_id = it->first;
1770*6777b538SAndroid Build Coastguard Worker   RequestPriority priority = it->second->priority();
1771*6777b538SAndroid Build Coastguard Worker   EnqueueResetStreamFrame(stream_id, priority, error_code, description);
1772*6777b538SAndroid Build Coastguard Worker 
1773*6777b538SAndroid Build Coastguard Worker   // Removes any pending writes for the stream except for possibly an
1774*6777b538SAndroid Build Coastguard Worker   // in-flight one.
1775*6777b538SAndroid Build Coastguard Worker   CloseActiveStreamIterator(it, error);
1776*6777b538SAndroid Build Coastguard Worker }
1777*6777b538SAndroid Build Coastguard Worker 
EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id,RequestPriority priority,spdy::SpdyErrorCode error_code,const std::string & description)1778*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id,
1779*6777b538SAndroid Build Coastguard Worker                                           RequestPriority priority,
1780*6777b538SAndroid Build Coastguard Worker                                           spdy::SpdyErrorCode error_code,
1781*6777b538SAndroid Build Coastguard Worker                                           const std::string& description) {
1782*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(stream_id, 0u);
1783*6777b538SAndroid Build Coastguard Worker 
1784*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM, [&] {
1785*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySendRstStreamParams(stream_id, error_code, description);
1786*6777b538SAndroid Build Coastguard Worker   });
1787*6777b538SAndroid Build Coastguard Worker 
1788*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1789*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> rst_frame(
1790*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreateRstStream(stream_id, error_code));
1791*6777b538SAndroid Build Coastguard Worker 
1792*6777b538SAndroid Build Coastguard Worker   EnqueueSessionWrite(priority, spdy::SpdyFrameType::RST_STREAM,
1793*6777b538SAndroid Build Coastguard Worker                       std::move(rst_frame));
1794*6777b538SAndroid Build Coastguard Worker   RecordProtocolErrorHistogram(MapRstStreamStatusToProtocolError(error_code));
1795*6777b538SAndroid Build Coastguard Worker }
1796*6777b538SAndroid Build Coastguard Worker 
EnqueuePriorityFrame(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId dependency_id,int weight,bool exclusive)1797*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueuePriorityFrame(spdy::SpdyStreamId stream_id,
1798*6777b538SAndroid Build Coastguard Worker                                        spdy::SpdyStreamId dependency_id,
1799*6777b538SAndroid Build Coastguard Worker                                        int weight,
1800*6777b538SAndroid Build Coastguard Worker                                        bool exclusive) {
1801*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_SEND_PRIORITY, [&] {
1802*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyPriorityParams(stream_id, dependency_id, weight,
1803*6777b538SAndroid Build Coastguard Worker                                     exclusive);
1804*6777b538SAndroid Build Coastguard Worker   });
1805*6777b538SAndroid Build Coastguard Worker 
1806*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1807*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> frame(
1808*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreatePriority(stream_id, dependency_id, weight,
1809*6777b538SAndroid Build Coastguard Worker                                             exclusive));
1810*6777b538SAndroid Build Coastguard Worker 
1811*6777b538SAndroid Build Coastguard Worker   // PRIORITY frames describe sequenced updates to the tree, so they must
1812*6777b538SAndroid Build Coastguard Worker   // be serialized. We do this by queueing all PRIORITY frames at HIGHEST
1813*6777b538SAndroid Build Coastguard Worker   // priority.
1814*6777b538SAndroid Build Coastguard Worker   EnqueueWrite(HIGHEST, spdy::SpdyFrameType::PRIORITY,
1815*6777b538SAndroid Build Coastguard Worker                std::make_unique<SimpleBufferProducer>(
1816*6777b538SAndroid Build Coastguard Worker                    std::make_unique<SpdyBuffer>(std::move(frame))),
1817*6777b538SAndroid Build Coastguard Worker                base::WeakPtr<SpdyStream>(),
1818*6777b538SAndroid Build Coastguard Worker                kSpdySessionCommandsTrafficAnnotation);
1819*6777b538SAndroid Build Coastguard Worker }
1820*6777b538SAndroid Build Coastguard Worker 
PumpReadLoop(ReadState expected_read_state,int result)1821*6777b538SAndroid Build Coastguard Worker void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
1822*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1823*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING) {
1824*6777b538SAndroid Build Coastguard Worker     return;
1825*6777b538SAndroid Build Coastguard Worker   }
1826*6777b538SAndroid Build Coastguard Worker   std::ignore = DoReadLoop(expected_read_state, result);
1827*6777b538SAndroid Build Coastguard Worker }
1828*6777b538SAndroid Build Coastguard Worker 
DoReadLoop(ReadState expected_read_state,int result)1829*6777b538SAndroid Build Coastguard Worker int SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
1830*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1831*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(read_state_, expected_read_state);
1832*6777b538SAndroid Build Coastguard Worker 
1833*6777b538SAndroid Build Coastguard Worker   in_io_loop_ = true;
1834*6777b538SAndroid Build Coastguard Worker 
1835*6777b538SAndroid Build Coastguard Worker   int bytes_read_without_yielding = 0;
1836*6777b538SAndroid Build Coastguard Worker   const base::TimeTicks yield_after_time =
1837*6777b538SAndroid Build Coastguard Worker       time_func_() + base::Milliseconds(kYieldAfterDurationMilliseconds);
1838*6777b538SAndroid Build Coastguard Worker 
1839*6777b538SAndroid Build Coastguard Worker   // Loop until the session is draining, the read becomes blocked, or
1840*6777b538SAndroid Build Coastguard Worker   // the read limit is exceeded.
1841*6777b538SAndroid Build Coastguard Worker   while (true) {
1842*6777b538SAndroid Build Coastguard Worker     switch (read_state_) {
1843*6777b538SAndroid Build Coastguard Worker       case READ_STATE_DO_READ:
1844*6777b538SAndroid Build Coastguard Worker         CHECK_EQ(result, OK);
1845*6777b538SAndroid Build Coastguard Worker         result = DoRead();
1846*6777b538SAndroid Build Coastguard Worker         break;
1847*6777b538SAndroid Build Coastguard Worker       case READ_STATE_DO_READ_COMPLETE:
1848*6777b538SAndroid Build Coastguard Worker         if (result > 0)
1849*6777b538SAndroid Build Coastguard Worker           bytes_read_without_yielding += result;
1850*6777b538SAndroid Build Coastguard Worker         result = DoReadComplete(result);
1851*6777b538SAndroid Build Coastguard Worker         break;
1852*6777b538SAndroid Build Coastguard Worker       default:
1853*6777b538SAndroid Build Coastguard Worker         NOTREACHED() << "read_state_: " << read_state_;
1854*6777b538SAndroid Build Coastguard Worker         break;
1855*6777b538SAndroid Build Coastguard Worker     }
1856*6777b538SAndroid Build Coastguard Worker 
1857*6777b538SAndroid Build Coastguard Worker     if (availability_state_ == STATE_DRAINING)
1858*6777b538SAndroid Build Coastguard Worker       break;
1859*6777b538SAndroid Build Coastguard Worker 
1860*6777b538SAndroid Build Coastguard Worker     if (result == ERR_IO_PENDING)
1861*6777b538SAndroid Build Coastguard Worker       break;
1862*6777b538SAndroid Build Coastguard Worker 
1863*6777b538SAndroid Build Coastguard Worker     if (read_state_ == READ_STATE_DO_READ &&
1864*6777b538SAndroid Build Coastguard Worker         (bytes_read_without_yielding > kYieldAfterBytesRead ||
1865*6777b538SAndroid Build Coastguard Worker          time_func_() > yield_after_time)) {
1866*6777b538SAndroid Build Coastguard Worker       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1867*6777b538SAndroid Build Coastguard Worker           FROM_HERE,
1868*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
1869*6777b538SAndroid Build Coastguard Worker                          READ_STATE_DO_READ, OK));
1870*6777b538SAndroid Build Coastguard Worker       result = ERR_IO_PENDING;
1871*6777b538SAndroid Build Coastguard Worker       break;
1872*6777b538SAndroid Build Coastguard Worker     }
1873*6777b538SAndroid Build Coastguard Worker   }
1874*6777b538SAndroid Build Coastguard Worker 
1875*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
1876*6777b538SAndroid Build Coastguard Worker   in_io_loop_ = false;
1877*6777b538SAndroid Build Coastguard Worker 
1878*6777b538SAndroid Build Coastguard Worker   return result;
1879*6777b538SAndroid Build Coastguard Worker }
1880*6777b538SAndroid Build Coastguard Worker 
DoRead()1881*6777b538SAndroid Build Coastguard Worker int SpdySession::DoRead() {
1882*6777b538SAndroid Build Coastguard Worker   DCHECK(!read_buffer_);
1883*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
1884*6777b538SAndroid Build Coastguard Worker 
1885*6777b538SAndroid Build Coastguard Worker   CHECK(socket_);
1886*6777b538SAndroid Build Coastguard Worker   read_state_ = READ_STATE_DO_READ_COMPLETE;
1887*6777b538SAndroid Build Coastguard Worker   read_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize);
1888*6777b538SAndroid Build Coastguard Worker   int rv = socket_->ReadIfReady(
1889*6777b538SAndroid Build Coastguard Worker       read_buffer_.get(), kReadBufferSize,
1890*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
1891*6777b538SAndroid Build Coastguard Worker                      READ_STATE_DO_READ));
1892*6777b538SAndroid Build Coastguard Worker   if (rv == ERR_IO_PENDING) {
1893*6777b538SAndroid Build Coastguard Worker     read_buffer_ = nullptr;
1894*6777b538SAndroid Build Coastguard Worker     read_state_ = READ_STATE_DO_READ;
1895*6777b538SAndroid Build Coastguard Worker     return rv;
1896*6777b538SAndroid Build Coastguard Worker   }
1897*6777b538SAndroid Build Coastguard Worker   if (rv == ERR_READ_IF_READY_NOT_IMPLEMENTED) {
1898*6777b538SAndroid Build Coastguard Worker     // Fallback to regular Read().
1899*6777b538SAndroid Build Coastguard Worker     return socket_->Read(
1900*6777b538SAndroid Build Coastguard Worker         read_buffer_.get(), kReadBufferSize,
1901*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
1902*6777b538SAndroid Build Coastguard Worker                        READ_STATE_DO_READ_COMPLETE));
1903*6777b538SAndroid Build Coastguard Worker   }
1904*6777b538SAndroid Build Coastguard Worker   return rv;
1905*6777b538SAndroid Build Coastguard Worker }
1906*6777b538SAndroid Build Coastguard Worker 
DoReadComplete(int result)1907*6777b538SAndroid Build Coastguard Worker int SpdySession::DoReadComplete(int result) {
1908*6777b538SAndroid Build Coastguard Worker   DCHECK(read_buffer_);
1909*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
1910*6777b538SAndroid Build Coastguard Worker 
1911*6777b538SAndroid Build Coastguard Worker   // Parse a frame.  For now this code requires that the frame fit into our
1912*6777b538SAndroid Build Coastguard Worker   // buffer (kReadBufferSize).
1913*6777b538SAndroid Build Coastguard Worker   // TODO(mbelshe): support arbitrarily large frames!
1914*6777b538SAndroid Build Coastguard Worker 
1915*6777b538SAndroid Build Coastguard Worker   if (result == 0) {
1916*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_CONNECTION_CLOSED, "Connection closed");
1917*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
1918*6777b538SAndroid Build Coastguard Worker   }
1919*6777b538SAndroid Build Coastguard Worker 
1920*6777b538SAndroid Build Coastguard Worker   if (result < 0) {
1921*6777b538SAndroid Build Coastguard Worker     DoDrainSession(
1922*6777b538SAndroid Build Coastguard Worker         static_cast<Error>(result),
1923*6777b538SAndroid Build Coastguard Worker         base::StringPrintf("Error %d reading from socket.", -result));
1924*6777b538SAndroid Build Coastguard Worker     return result;
1925*6777b538SAndroid Build Coastguard Worker   }
1926*6777b538SAndroid Build Coastguard Worker   CHECK_LE(result, kReadBufferSize);
1927*6777b538SAndroid Build Coastguard Worker 
1928*6777b538SAndroid Build Coastguard Worker   last_read_time_ = time_func_();
1929*6777b538SAndroid Build Coastguard Worker 
1930*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
1931*6777b538SAndroid Build Coastguard Worker   char* data = read_buffer_->data();
1932*6777b538SAndroid Build Coastguard Worker   while (result > 0) {
1933*6777b538SAndroid Build Coastguard Worker     uint32_t bytes_processed =
1934*6777b538SAndroid Build Coastguard Worker         buffered_spdy_framer_->ProcessInput(data, result);
1935*6777b538SAndroid Build Coastguard Worker     result -= bytes_processed;
1936*6777b538SAndroid Build Coastguard Worker     data += bytes_processed;
1937*6777b538SAndroid Build Coastguard Worker 
1938*6777b538SAndroid Build Coastguard Worker     if (availability_state_ == STATE_DRAINING) {
1939*6777b538SAndroid Build Coastguard Worker       return ERR_CONNECTION_CLOSED;
1940*6777b538SAndroid Build Coastguard Worker     }
1941*6777b538SAndroid Build Coastguard Worker 
1942*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(buffered_spdy_framer_->spdy_framer_error(),
1943*6777b538SAndroid Build Coastguard Worker               http2::Http2DecoderAdapter::SPDY_NO_ERROR);
1944*6777b538SAndroid Build Coastguard Worker   }
1945*6777b538SAndroid Build Coastguard Worker 
1946*6777b538SAndroid Build Coastguard Worker   read_buffer_ = nullptr;
1947*6777b538SAndroid Build Coastguard Worker   read_state_ = READ_STATE_DO_READ;
1948*6777b538SAndroid Build Coastguard Worker   return OK;
1949*6777b538SAndroid Build Coastguard Worker }
1950*6777b538SAndroid Build Coastguard Worker 
PumpWriteLoop(WriteState expected_write_state,int result)1951*6777b538SAndroid Build Coastguard Worker void SpdySession::PumpWriteLoop(WriteState expected_write_state, int result) {
1952*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1953*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(write_state_, expected_write_state);
1954*6777b538SAndroid Build Coastguard Worker 
1955*6777b538SAndroid Build Coastguard Worker   DoWriteLoop(expected_write_state, result);
1956*6777b538SAndroid Build Coastguard Worker 
1957*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING && !in_flight_write_ &&
1958*6777b538SAndroid Build Coastguard Worker       write_queue_.IsEmpty()) {
1959*6777b538SAndroid Build Coastguard Worker     pool_->RemoveUnavailableSession(GetWeakPtr());  // Destroys |this|.
1960*6777b538SAndroid Build Coastguard Worker     return;
1961*6777b538SAndroid Build Coastguard Worker   }
1962*6777b538SAndroid Build Coastguard Worker }
1963*6777b538SAndroid Build Coastguard Worker 
MaybePostWriteLoop()1964*6777b538SAndroid Build Coastguard Worker void SpdySession::MaybePostWriteLoop() {
1965*6777b538SAndroid Build Coastguard Worker   if (write_state_ == WRITE_STATE_IDLE) {
1966*6777b538SAndroid Build Coastguard Worker     CHECK(!in_flight_write_);
1967*6777b538SAndroid Build Coastguard Worker     write_state_ = WRITE_STATE_DO_WRITE;
1968*6777b538SAndroid Build Coastguard Worker     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1969*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
1970*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(),
1971*6777b538SAndroid Build Coastguard Worker                        WRITE_STATE_DO_WRITE, OK));
1972*6777b538SAndroid Build Coastguard Worker   }
1973*6777b538SAndroid Build Coastguard Worker }
1974*6777b538SAndroid Build Coastguard Worker 
DoWriteLoop(WriteState expected_write_state,int result)1975*6777b538SAndroid Build Coastguard Worker int SpdySession::DoWriteLoop(WriteState expected_write_state, int result) {
1976*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
1977*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(write_state_, WRITE_STATE_IDLE);
1978*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(write_state_, expected_write_state);
1979*6777b538SAndroid Build Coastguard Worker 
1980*6777b538SAndroid Build Coastguard Worker   in_io_loop_ = true;
1981*6777b538SAndroid Build Coastguard Worker 
1982*6777b538SAndroid Build Coastguard Worker   // Loop until the session is closed or the write becomes blocked.
1983*6777b538SAndroid Build Coastguard Worker   while (true) {
1984*6777b538SAndroid Build Coastguard Worker     switch (write_state_) {
1985*6777b538SAndroid Build Coastguard Worker       case WRITE_STATE_DO_WRITE:
1986*6777b538SAndroid Build Coastguard Worker         DCHECK_EQ(result, OK);
1987*6777b538SAndroid Build Coastguard Worker         result = DoWrite();
1988*6777b538SAndroid Build Coastguard Worker         break;
1989*6777b538SAndroid Build Coastguard Worker       case WRITE_STATE_DO_WRITE_COMPLETE:
1990*6777b538SAndroid Build Coastguard Worker         result = DoWriteComplete(result);
1991*6777b538SAndroid Build Coastguard Worker         break;
1992*6777b538SAndroid Build Coastguard Worker       case WRITE_STATE_IDLE:
1993*6777b538SAndroid Build Coastguard Worker       default:
1994*6777b538SAndroid Build Coastguard Worker         NOTREACHED() << "write_state_: " << write_state_;
1995*6777b538SAndroid Build Coastguard Worker         break;
1996*6777b538SAndroid Build Coastguard Worker     }
1997*6777b538SAndroid Build Coastguard Worker 
1998*6777b538SAndroid Build Coastguard Worker     if (write_state_ == WRITE_STATE_IDLE) {
1999*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(result, ERR_IO_PENDING);
2000*6777b538SAndroid Build Coastguard Worker       break;
2001*6777b538SAndroid Build Coastguard Worker     }
2002*6777b538SAndroid Build Coastguard Worker 
2003*6777b538SAndroid Build Coastguard Worker     if (result == ERR_IO_PENDING)
2004*6777b538SAndroid Build Coastguard Worker       break;
2005*6777b538SAndroid Build Coastguard Worker   }
2006*6777b538SAndroid Build Coastguard Worker 
2007*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2008*6777b538SAndroid Build Coastguard Worker   in_io_loop_ = false;
2009*6777b538SAndroid Build Coastguard Worker 
2010*6777b538SAndroid Build Coastguard Worker   return result;
2011*6777b538SAndroid Build Coastguard Worker }
2012*6777b538SAndroid Build Coastguard Worker 
DoWrite()2013*6777b538SAndroid Build Coastguard Worker int SpdySession::DoWrite() {
2014*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2015*6777b538SAndroid Build Coastguard Worker 
2016*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_);
2017*6777b538SAndroid Build Coastguard Worker   if (in_flight_write_) {
2018*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
2019*6777b538SAndroid Build Coastguard Worker   } else {
2020*6777b538SAndroid Build Coastguard Worker     // Grab the next frame to send.
2021*6777b538SAndroid Build Coastguard Worker     spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
2022*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<SpdyBufferProducer> producer;
2023*6777b538SAndroid Build Coastguard Worker     base::WeakPtr<SpdyStream> stream;
2024*6777b538SAndroid Build Coastguard Worker     if (!write_queue_.Dequeue(&frame_type, &producer, &stream,
2025*6777b538SAndroid Build Coastguard Worker                               &in_flight_write_traffic_annotation_)) {
2026*6777b538SAndroid Build Coastguard Worker       write_state_ = WRITE_STATE_IDLE;
2027*6777b538SAndroid Build Coastguard Worker       return ERR_IO_PENDING;
2028*6777b538SAndroid Build Coastguard Worker     }
2029*6777b538SAndroid Build Coastguard Worker 
2030*6777b538SAndroid Build Coastguard Worker     if (stream.get())
2031*6777b538SAndroid Build Coastguard Worker       CHECK(!stream->IsClosed());
2032*6777b538SAndroid Build Coastguard Worker 
2033*6777b538SAndroid Build Coastguard Worker     // Activate the stream only when sending the HEADERS frame to
2034*6777b538SAndroid Build Coastguard Worker     // guarantee monotonically-increasing stream IDs.
2035*6777b538SAndroid Build Coastguard Worker     if (frame_type == spdy::SpdyFrameType::HEADERS) {
2036*6777b538SAndroid Build Coastguard Worker       CHECK(stream.get());
2037*6777b538SAndroid Build Coastguard Worker       CHECK_EQ(stream->stream_id(), 0u);
2038*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<SpdyStream> owned_stream =
2039*6777b538SAndroid Build Coastguard Worker           ActivateCreatedStream(stream.get());
2040*6777b538SAndroid Build Coastguard Worker       InsertActivatedStream(std::move(owned_stream));
2041*6777b538SAndroid Build Coastguard Worker 
2042*6777b538SAndroid Build Coastguard Worker       if (stream_hi_water_mark_ > kLastStreamId) {
2043*6777b538SAndroid Build Coastguard Worker         CHECK_EQ(stream->stream_id(), kLastStreamId);
2044*6777b538SAndroid Build Coastguard Worker         // We've exhausted the stream ID space, and no new streams may be
2045*6777b538SAndroid Build Coastguard Worker         // created after this one.
2046*6777b538SAndroid Build Coastguard Worker         MakeUnavailable();
2047*6777b538SAndroid Build Coastguard Worker         StartGoingAway(kLastStreamId, ERR_HTTP2_PROTOCOL_ERROR);
2048*6777b538SAndroid Build Coastguard Worker       }
2049*6777b538SAndroid Build Coastguard Worker     }
2050*6777b538SAndroid Build Coastguard Worker 
2051*6777b538SAndroid Build Coastguard Worker     in_flight_write_ = producer->ProduceBuffer();
2052*6777b538SAndroid Build Coastguard Worker     if (!in_flight_write_) {
2053*6777b538SAndroid Build Coastguard Worker       NOTREACHED();
2054*6777b538SAndroid Build Coastguard Worker       return ERR_UNEXPECTED;
2055*6777b538SAndroid Build Coastguard Worker     }
2056*6777b538SAndroid Build Coastguard Worker     in_flight_write_frame_type_ = frame_type;
2057*6777b538SAndroid Build Coastguard Worker     in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
2058*6777b538SAndroid Build Coastguard Worker     DCHECK_GE(in_flight_write_frame_size_, spdy::kFrameMinimumSize);
2059*6777b538SAndroid Build Coastguard Worker     in_flight_write_stream_ = stream;
2060*6777b538SAndroid Build Coastguard Worker   }
2061*6777b538SAndroid Build Coastguard Worker 
2062*6777b538SAndroid Build Coastguard Worker   write_state_ = WRITE_STATE_DO_WRITE_COMPLETE;
2063*6777b538SAndroid Build Coastguard Worker 
2064*6777b538SAndroid Build Coastguard Worker   scoped_refptr<IOBuffer> write_io_buffer =
2065*6777b538SAndroid Build Coastguard Worker       in_flight_write_->GetIOBufferForRemainingData();
2066*6777b538SAndroid Build Coastguard Worker   return socket_->Write(
2067*6777b538SAndroid Build Coastguard Worker       write_io_buffer.get(), in_flight_write_->GetRemainingSize(),
2068*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(),
2069*6777b538SAndroid Build Coastguard Worker                      WRITE_STATE_DO_WRITE_COMPLETE),
2070*6777b538SAndroid Build Coastguard Worker       NetworkTrafficAnnotationTag(in_flight_write_traffic_annotation_));
2071*6777b538SAndroid Build Coastguard Worker }
2072*6777b538SAndroid Build Coastguard Worker 
DoWriteComplete(int result)2073*6777b538SAndroid Build Coastguard Worker int SpdySession::DoWriteComplete(int result) {
2074*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2075*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(result, ERR_IO_PENDING);
2076*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
2077*6777b538SAndroid Build Coastguard Worker 
2078*6777b538SAndroid Build Coastguard Worker   if (result < 0) {
2079*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(result, ERR_IO_PENDING);
2080*6777b538SAndroid Build Coastguard Worker     in_flight_write_.reset();
2081*6777b538SAndroid Build Coastguard Worker     in_flight_write_frame_type_ = spdy::SpdyFrameType::DATA;
2082*6777b538SAndroid Build Coastguard Worker     in_flight_write_frame_size_ = 0;
2083*6777b538SAndroid Build Coastguard Worker     in_flight_write_stream_.reset();
2084*6777b538SAndroid Build Coastguard Worker     in_flight_write_traffic_annotation_.reset();
2085*6777b538SAndroid Build Coastguard Worker     write_state_ = WRITE_STATE_DO_WRITE;
2086*6777b538SAndroid Build Coastguard Worker     DoDrainSession(static_cast<Error>(result), "Write error");
2087*6777b538SAndroid Build Coastguard Worker     return OK;
2088*6777b538SAndroid Build Coastguard Worker   }
2089*6777b538SAndroid Build Coastguard Worker 
2090*6777b538SAndroid Build Coastguard Worker   // It should not be possible to have written more bytes than our
2091*6777b538SAndroid Build Coastguard Worker   // in_flight_write_.
2092*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(static_cast<size_t>(result), in_flight_write_->GetRemainingSize());
2093*6777b538SAndroid Build Coastguard Worker 
2094*6777b538SAndroid Build Coastguard Worker   if (result > 0) {
2095*6777b538SAndroid Build Coastguard Worker     in_flight_write_->Consume(static_cast<size_t>(result));
2096*6777b538SAndroid Build Coastguard Worker     if (in_flight_write_stream_.get())
2097*6777b538SAndroid Build Coastguard Worker       in_flight_write_stream_->AddRawSentBytes(static_cast<size_t>(result));
2098*6777b538SAndroid Build Coastguard Worker 
2099*6777b538SAndroid Build Coastguard Worker     // We only notify the stream when we've fully written the pending frame.
2100*6777b538SAndroid Build Coastguard Worker     if (in_flight_write_->GetRemainingSize() == 0) {
2101*6777b538SAndroid Build Coastguard Worker       // It is possible that the stream was cancelled while we were
2102*6777b538SAndroid Build Coastguard Worker       // writing to the socket.
2103*6777b538SAndroid Build Coastguard Worker       if (in_flight_write_stream_.get()) {
2104*6777b538SAndroid Build Coastguard Worker         DCHECK_GT(in_flight_write_frame_size_, 0u);
2105*6777b538SAndroid Build Coastguard Worker         in_flight_write_stream_->OnFrameWriteComplete(
2106*6777b538SAndroid Build Coastguard Worker             in_flight_write_frame_type_, in_flight_write_frame_size_);
2107*6777b538SAndroid Build Coastguard Worker       }
2108*6777b538SAndroid Build Coastguard Worker 
2109*6777b538SAndroid Build Coastguard Worker       // Cleanup the write which just completed.
2110*6777b538SAndroid Build Coastguard Worker       in_flight_write_.reset();
2111*6777b538SAndroid Build Coastguard Worker       in_flight_write_frame_type_ = spdy::SpdyFrameType::DATA;
2112*6777b538SAndroid Build Coastguard Worker       in_flight_write_frame_size_ = 0;
2113*6777b538SAndroid Build Coastguard Worker       in_flight_write_stream_.reset();
2114*6777b538SAndroid Build Coastguard Worker     }
2115*6777b538SAndroid Build Coastguard Worker   }
2116*6777b538SAndroid Build Coastguard Worker 
2117*6777b538SAndroid Build Coastguard Worker   write_state_ = WRITE_STATE_DO_WRITE;
2118*6777b538SAndroid Build Coastguard Worker   return OK;
2119*6777b538SAndroid Build Coastguard Worker }
2120*6777b538SAndroid Build Coastguard Worker 
NotifyRequestsOfConfirmation(int rv)2121*6777b538SAndroid Build Coastguard Worker void SpdySession::NotifyRequestsOfConfirmation(int rv) {
2122*6777b538SAndroid Build Coastguard Worker   for (auto& callback : waiting_for_confirmation_callbacks_) {
2123*6777b538SAndroid Build Coastguard Worker     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
2124*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(std::move(callback), rv));
2125*6777b538SAndroid Build Coastguard Worker   }
2126*6777b538SAndroid Build Coastguard Worker   waiting_for_confirmation_callbacks_.clear();
2127*6777b538SAndroid Build Coastguard Worker   in_confirm_handshake_ = false;
2128*6777b538SAndroid Build Coastguard Worker }
2129*6777b538SAndroid Build Coastguard Worker 
SendInitialData()2130*6777b538SAndroid Build Coastguard Worker void SpdySession::SendInitialData() {
2131*6777b538SAndroid Build Coastguard Worker   DCHECK(enable_sending_initial_data_);
2132*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
2133*6777b538SAndroid Build Coastguard Worker 
2134*6777b538SAndroid Build Coastguard Worker   // Prepare initial SETTINGS frame.  Only send settings that have a value
2135*6777b538SAndroid Build Coastguard Worker   // different from the protocol default value.
2136*6777b538SAndroid Build Coastguard Worker   spdy::SettingsMap settings_map;
2137*6777b538SAndroid Build Coastguard Worker   for (auto setting : initial_settings_) {
2138*6777b538SAndroid Build Coastguard Worker     if (!IsSpdySettingAtDefaultInitialValue(setting.first, setting.second)) {
2139*6777b538SAndroid Build Coastguard Worker       settings_map.insert(setting);
2140*6777b538SAndroid Build Coastguard Worker     }
2141*6777b538SAndroid Build Coastguard Worker   }
2142*6777b538SAndroid Build Coastguard Worker   if (enable_http2_settings_grease_) {
2143*6777b538SAndroid Build Coastguard Worker     spdy::SpdySettingsId greased_id = 0x0a0a +
2144*6777b538SAndroid Build Coastguard Worker                                       0x1000 * base::RandGenerator(0xf + 1) +
2145*6777b538SAndroid Build Coastguard Worker                                       0x0010 * base::RandGenerator(0xf + 1);
2146*6777b538SAndroid Build Coastguard Worker     uint32_t greased_value = base::RandGenerator(
2147*6777b538SAndroid Build Coastguard Worker         static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1);
2148*6777b538SAndroid Build Coastguard Worker     // Let insertion silently fail if `settings_map` already contains
2149*6777b538SAndroid Build Coastguard Worker     // `greased_id`.
2150*6777b538SAndroid Build Coastguard Worker     settings_map.emplace(greased_id, greased_value);
2151*6777b538SAndroid Build Coastguard Worker   }
2152*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS, [&] {
2153*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySendSettingsParams(&settings_map);
2154*6777b538SAndroid Build Coastguard Worker   });
2155*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> settings_frame(
2156*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreateSettings(settings_map));
2157*6777b538SAndroid Build Coastguard Worker 
2158*6777b538SAndroid Build Coastguard Worker   // Prepare initial WINDOW_UPDATE frame.
2159*6777b538SAndroid Build Coastguard Worker   // Make sure |session_max_recv_window_size_ - session_recv_window_size_|
2160*6777b538SAndroid Build Coastguard Worker   // does not underflow.
2161*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(session_max_recv_window_size_, session_recv_window_size_);
2162*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(session_recv_window_size_, 0);
2163*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(0, session_unacked_recv_window_bytes_);
2164*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> window_update_frame;
2165*6777b538SAndroid Build Coastguard Worker   const bool send_window_update =
2166*6777b538SAndroid Build Coastguard Worker       session_max_recv_window_size_ > session_recv_window_size_;
2167*6777b538SAndroid Build Coastguard Worker   if (send_window_update) {
2168*6777b538SAndroid Build Coastguard Worker     const int32_t delta_window_size =
2169*6777b538SAndroid Build Coastguard Worker         session_max_recv_window_size_ - session_recv_window_size_;
2170*6777b538SAndroid Build Coastguard Worker     session_recv_window_size_ += delta_window_size;
2171*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_RECV_WINDOW, [&] {
2172*6777b538SAndroid Build Coastguard Worker       return NetLogSpdySessionWindowUpdateParams(delta_window_size,
2173*6777b538SAndroid Build Coastguard Worker                                                  session_recv_window_size_);
2174*6777b538SAndroid Build Coastguard Worker     });
2175*6777b538SAndroid Build Coastguard Worker 
2176*6777b538SAndroid Build Coastguard Worker     last_recv_window_update_ = base::TimeTicks::Now();
2177*6777b538SAndroid Build Coastguard Worker     session_unacked_recv_window_bytes_ += delta_window_size;
2178*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_WINDOW_UPDATE, [&] {
2179*6777b538SAndroid Build Coastguard Worker       return NetLogSpdyWindowUpdateFrameParams(
2180*6777b538SAndroid Build Coastguard Worker           spdy::kSessionFlowControlStreamId,
2181*6777b538SAndroid Build Coastguard Worker           session_unacked_recv_window_bytes_);
2182*6777b538SAndroid Build Coastguard Worker     });
2183*6777b538SAndroid Build Coastguard Worker     window_update_frame = buffered_spdy_framer_->CreateWindowUpdate(
2184*6777b538SAndroid Build Coastguard Worker         spdy::kSessionFlowControlStreamId, session_unacked_recv_window_bytes_);
2185*6777b538SAndroid Build Coastguard Worker     session_unacked_recv_window_bytes_ = 0;
2186*6777b538SAndroid Build Coastguard Worker   }
2187*6777b538SAndroid Build Coastguard Worker 
2188*6777b538SAndroid Build Coastguard Worker   // Create a single frame to hold connection prefix, initial SETTINGS frame,
2189*6777b538SAndroid Build Coastguard Worker   // and optional initial WINDOW_UPDATE frame, so that they are sent on the wire
2190*6777b538SAndroid Build Coastguard Worker   // in a single packet.
2191*6777b538SAndroid Build Coastguard Worker   size_t initial_frame_size =
2192*6777b538SAndroid Build Coastguard Worker       spdy::kHttp2ConnectionHeaderPrefixSize + settings_frame->size();
2193*6777b538SAndroid Build Coastguard Worker   if (send_window_update)
2194*6777b538SAndroid Build Coastguard Worker     initial_frame_size += window_update_frame->size();
2195*6777b538SAndroid Build Coastguard Worker   auto initial_frame_data = std::make_unique<char[]>(initial_frame_size);
2196*6777b538SAndroid Build Coastguard Worker   size_t offset = 0;
2197*6777b538SAndroid Build Coastguard Worker 
2198*6777b538SAndroid Build Coastguard Worker   memcpy(initial_frame_data.get() + offset, spdy::kHttp2ConnectionHeaderPrefix,
2199*6777b538SAndroid Build Coastguard Worker          spdy::kHttp2ConnectionHeaderPrefixSize);
2200*6777b538SAndroid Build Coastguard Worker   offset += spdy::kHttp2ConnectionHeaderPrefixSize;
2201*6777b538SAndroid Build Coastguard Worker 
2202*6777b538SAndroid Build Coastguard Worker   memcpy(initial_frame_data.get() + offset, settings_frame->data(),
2203*6777b538SAndroid Build Coastguard Worker          settings_frame->size());
2204*6777b538SAndroid Build Coastguard Worker   offset += settings_frame->size();
2205*6777b538SAndroid Build Coastguard Worker 
2206*6777b538SAndroid Build Coastguard Worker   if (send_window_update) {
2207*6777b538SAndroid Build Coastguard Worker     memcpy(initial_frame_data.get() + offset, window_update_frame->data(),
2208*6777b538SAndroid Build Coastguard Worker            window_update_frame->size());
2209*6777b538SAndroid Build Coastguard Worker   }
2210*6777b538SAndroid Build Coastguard Worker 
2211*6777b538SAndroid Build Coastguard Worker   auto initial_frame = std::make_unique<spdy::SpdySerializedFrame>(
2212*6777b538SAndroid Build Coastguard Worker       std::move(initial_frame_data), initial_frame_size);
2213*6777b538SAndroid Build Coastguard Worker   EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::SETTINGS,
2214*6777b538SAndroid Build Coastguard Worker                       std::move(initial_frame));
2215*6777b538SAndroid Build Coastguard Worker }
2216*6777b538SAndroid Build Coastguard Worker 
HandleSetting(uint32_t id,uint32_t value)2217*6777b538SAndroid Build Coastguard Worker void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
2218*6777b538SAndroid Build Coastguard Worker   switch (id) {
2219*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_HEADER_TABLE_SIZE:
2220*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->UpdateHeaderEncoderTableSize(value);
2221*6777b538SAndroid Build Coastguard Worker       break;
2222*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
2223*6777b538SAndroid Build Coastguard Worker       max_concurrent_streams_ =
2224*6777b538SAndroid Build Coastguard Worker           std::min(static_cast<size_t>(value), kMaxConcurrentStreamLimit);
2225*6777b538SAndroid Build Coastguard Worker       ProcessPendingStreamRequests();
2226*6777b538SAndroid Build Coastguard Worker       break;
2227*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_INITIAL_WINDOW_SIZE: {
2228*6777b538SAndroid Build Coastguard Worker       if (value > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
2229*6777b538SAndroid Build Coastguard Worker         net_log_.AddEventWithIntParams(
2230*6777b538SAndroid Build Coastguard Worker             NetLogEventType::HTTP2_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
2231*6777b538SAndroid Build Coastguard Worker             "initial_window_size", value);
2232*6777b538SAndroid Build Coastguard Worker         return;
2233*6777b538SAndroid Build Coastguard Worker       }
2234*6777b538SAndroid Build Coastguard Worker 
2235*6777b538SAndroid Build Coastguard Worker       // spdy::SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_
2236*6777b538SAndroid Build Coastguard Worker       // only.
2237*6777b538SAndroid Build Coastguard Worker       int32_t delta_window_size =
2238*6777b538SAndroid Build Coastguard Worker           static_cast<int32_t>(value) - stream_initial_send_window_size_;
2239*6777b538SAndroid Build Coastguard Worker       stream_initial_send_window_size_ = static_cast<int32_t>(value);
2240*6777b538SAndroid Build Coastguard Worker       UpdateStreamsSendWindowSize(delta_window_size);
2241*6777b538SAndroid Build Coastguard Worker       net_log_.AddEventWithIntParams(
2242*6777b538SAndroid Build Coastguard Worker           NetLogEventType::HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
2243*6777b538SAndroid Build Coastguard Worker           "delta_window_size", delta_window_size);
2244*6777b538SAndroid Build Coastguard Worker       break;
2245*6777b538SAndroid Build Coastguard Worker     }
2246*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL:
2247*6777b538SAndroid Build Coastguard Worker       if ((value != 0 && value != 1) || (support_websocket_ && value == 0)) {
2248*6777b538SAndroid Build Coastguard Worker         DoDrainSession(
2249*6777b538SAndroid Build Coastguard Worker             ERR_HTTP2_PROTOCOL_ERROR,
2250*6777b538SAndroid Build Coastguard Worker             "Invalid value for spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL.");
2251*6777b538SAndroid Build Coastguard Worker         return;
2252*6777b538SAndroid Build Coastguard Worker       }
2253*6777b538SAndroid Build Coastguard Worker       if (value == 1) {
2254*6777b538SAndroid Build Coastguard Worker         support_websocket_ = true;
2255*6777b538SAndroid Build Coastguard Worker       }
2256*6777b538SAndroid Build Coastguard Worker       break;
2257*6777b538SAndroid Build Coastguard Worker     case spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES:
2258*6777b538SAndroid Build Coastguard Worker       if (value != 0 && value != 1) {
2259*6777b538SAndroid Build Coastguard Worker         DoDrainSession(
2260*6777b538SAndroid Build Coastguard Worker             ERR_HTTP2_PROTOCOL_ERROR,
2261*6777b538SAndroid Build Coastguard Worker             "Invalid value for spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES.");
2262*6777b538SAndroid Build Coastguard Worker         return;
2263*6777b538SAndroid Build Coastguard Worker       }
2264*6777b538SAndroid Build Coastguard Worker       if (settings_frame_received_) {
2265*6777b538SAndroid Build Coastguard Worker         if (value != (deprecate_http2_priorities_ ? 1 : 0)) {
2266*6777b538SAndroid Build Coastguard Worker           DoDrainSession(ERR_HTTP2_PROTOCOL_ERROR,
2267*6777b538SAndroid Build Coastguard Worker                          "spdy::SETTINGS_DEPRECATE_HTTP2_PRIORITIES value "
2268*6777b538SAndroid Build Coastguard Worker                          "changed after first SETTINGS frame.");
2269*6777b538SAndroid Build Coastguard Worker           return;
2270*6777b538SAndroid Build Coastguard Worker         }
2271*6777b538SAndroid Build Coastguard Worker       } else {
2272*6777b538SAndroid Build Coastguard Worker         if (value == 1) {
2273*6777b538SAndroid Build Coastguard Worker           deprecate_http2_priorities_ = true;
2274*6777b538SAndroid Build Coastguard Worker         }
2275*6777b538SAndroid Build Coastguard Worker       }
2276*6777b538SAndroid Build Coastguard Worker       break;
2277*6777b538SAndroid Build Coastguard Worker   }
2278*6777b538SAndroid Build Coastguard Worker }
2279*6777b538SAndroid Build Coastguard Worker 
UpdateStreamsSendWindowSize(int32_t delta_window_size)2280*6777b538SAndroid Build Coastguard Worker void SpdySession::UpdateStreamsSendWindowSize(int32_t delta_window_size) {
2281*6777b538SAndroid Build Coastguard Worker   for (const auto& value : active_streams_) {
2282*6777b538SAndroid Build Coastguard Worker     if (!value.second->AdjustSendWindowSize(delta_window_size)) {
2283*6777b538SAndroid Build Coastguard Worker       DoDrainSession(
2284*6777b538SAndroid Build Coastguard Worker           ERR_HTTP2_FLOW_CONTROL_ERROR,
2285*6777b538SAndroid Build Coastguard Worker           base::StringPrintf(
2286*6777b538SAndroid Build Coastguard Worker               "New spdy::SETTINGS_INITIAL_WINDOW_SIZE value overflows "
2287*6777b538SAndroid Build Coastguard Worker               "flow control window of stream %d.",
2288*6777b538SAndroid Build Coastguard Worker               value.second->stream_id()));
2289*6777b538SAndroid Build Coastguard Worker       return;
2290*6777b538SAndroid Build Coastguard Worker     }
2291*6777b538SAndroid Build Coastguard Worker   }
2292*6777b538SAndroid Build Coastguard Worker 
2293*6777b538SAndroid Build Coastguard Worker   for (SpdyStream* const stream : created_streams_) {
2294*6777b538SAndroid Build Coastguard Worker     if (!stream->AdjustSendWindowSize(delta_window_size)) {
2295*6777b538SAndroid Build Coastguard Worker       DoDrainSession(
2296*6777b538SAndroid Build Coastguard Worker           ERR_HTTP2_FLOW_CONTROL_ERROR,
2297*6777b538SAndroid Build Coastguard Worker           base::StringPrintf(
2298*6777b538SAndroid Build Coastguard Worker               "New spdy::SETTINGS_INITIAL_WINDOW_SIZE value overflows "
2299*6777b538SAndroid Build Coastguard Worker               "flow control window of stream %d.",
2300*6777b538SAndroid Build Coastguard Worker               stream->stream_id()));
2301*6777b538SAndroid Build Coastguard Worker       return;
2302*6777b538SAndroid Build Coastguard Worker     }
2303*6777b538SAndroid Build Coastguard Worker   }
2304*6777b538SAndroid Build Coastguard Worker }
2305*6777b538SAndroid Build Coastguard Worker 
MaybeCheckConnectionStatus()2306*6777b538SAndroid Build Coastguard Worker void SpdySession::MaybeCheckConnectionStatus() {
2307*6777b538SAndroid Build Coastguard Worker   if (NetworkChangeNotifier::IsDefaultNetworkActive())
2308*6777b538SAndroid Build Coastguard Worker     CheckConnectionStatus();
2309*6777b538SAndroid Build Coastguard Worker   else
2310*6777b538SAndroid Build Coastguard Worker     check_connection_on_radio_wakeup_ = true;
2311*6777b538SAndroid Build Coastguard Worker }
2312*6777b538SAndroid Build Coastguard Worker 
MaybeSendPrefacePing()2313*6777b538SAndroid Build Coastguard Worker void SpdySession::MaybeSendPrefacePing() {
2314*6777b538SAndroid Build Coastguard Worker   if (ping_in_flight_ || check_ping_status_pending_ ||
2315*6777b538SAndroid Build Coastguard Worker       !enable_ping_based_connection_checking_) {
2316*6777b538SAndroid Build Coastguard Worker     return;
2317*6777b538SAndroid Build Coastguard Worker   }
2318*6777b538SAndroid Build Coastguard Worker 
2319*6777b538SAndroid Build Coastguard Worker   // If there has been no read activity in the session for some time,
2320*6777b538SAndroid Build Coastguard Worker   // then send a preface-PING.
2321*6777b538SAndroid Build Coastguard Worker   if (time_func_() > last_read_time_ + connection_at_risk_of_loss_time_)
2322*6777b538SAndroid Build Coastguard Worker     WritePingFrame(next_ping_id_, false);
2323*6777b538SAndroid Build Coastguard Worker }
2324*6777b538SAndroid Build Coastguard Worker 
SendWindowUpdateFrame(spdy::SpdyStreamId stream_id,uint32_t delta_window_size,RequestPriority priority)2325*6777b538SAndroid Build Coastguard Worker void SpdySession::SendWindowUpdateFrame(spdy::SpdyStreamId stream_id,
2326*6777b538SAndroid Build Coastguard Worker                                         uint32_t delta_window_size,
2327*6777b538SAndroid Build Coastguard Worker                                         RequestPriority priority) {
2328*6777b538SAndroid Build Coastguard Worker   ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2329*6777b538SAndroid Build Coastguard Worker   if (it != active_streams_.end()) {
2330*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(it->second->stream_id(), stream_id);
2331*6777b538SAndroid Build Coastguard Worker   } else {
2332*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(stream_id, spdy::kSessionFlowControlStreamId);
2333*6777b538SAndroid Build Coastguard Worker   }
2334*6777b538SAndroid Build Coastguard Worker 
2335*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_WINDOW_UPDATE, [&] {
2336*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyWindowUpdateFrameParams(stream_id, delta_window_size);
2337*6777b538SAndroid Build Coastguard Worker   });
2338*6777b538SAndroid Build Coastguard Worker 
2339*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
2340*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> window_update_frame(
2341*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreateWindowUpdate(stream_id, delta_window_size));
2342*6777b538SAndroid Build Coastguard Worker   EnqueueSessionWrite(priority, spdy::SpdyFrameType::WINDOW_UPDATE,
2343*6777b538SAndroid Build Coastguard Worker                       std::move(window_update_frame));
2344*6777b538SAndroid Build Coastguard Worker }
2345*6777b538SAndroid Build Coastguard Worker 
WritePingFrame(spdy::SpdyPingId unique_id,bool is_ack)2346*6777b538SAndroid Build Coastguard Worker void SpdySession::WritePingFrame(spdy::SpdyPingId unique_id, bool is_ack) {
2347*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
2348*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<spdy::SpdySerializedFrame> ping_frame(
2349*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->CreatePingFrame(unique_id, is_ack));
2350*6777b538SAndroid Build Coastguard Worker   EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::PING,
2351*6777b538SAndroid Build Coastguard Worker                       std::move(ping_frame));
2352*6777b538SAndroid Build Coastguard Worker 
2353*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] {
2354*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyPingParams(unique_id, is_ack, "sent");
2355*6777b538SAndroid Build Coastguard Worker   });
2356*6777b538SAndroid Build Coastguard Worker 
2357*6777b538SAndroid Build Coastguard Worker   if (!is_ack) {
2358*6777b538SAndroid Build Coastguard Worker     DCHECK(!ping_in_flight_);
2359*6777b538SAndroid Build Coastguard Worker 
2360*6777b538SAndroid Build Coastguard Worker     ping_in_flight_ = true;
2361*6777b538SAndroid Build Coastguard Worker     ++next_ping_id_;
2362*6777b538SAndroid Build Coastguard Worker     PlanToCheckPingStatus();
2363*6777b538SAndroid Build Coastguard Worker     last_ping_sent_time_ = time_func_();
2364*6777b538SAndroid Build Coastguard Worker   }
2365*6777b538SAndroid Build Coastguard Worker }
2366*6777b538SAndroid Build Coastguard Worker 
PlanToCheckPingStatus()2367*6777b538SAndroid Build Coastguard Worker void SpdySession::PlanToCheckPingStatus() {
2368*6777b538SAndroid Build Coastguard Worker   if (check_ping_status_pending_)
2369*6777b538SAndroid Build Coastguard Worker     return;
2370*6777b538SAndroid Build Coastguard Worker 
2371*6777b538SAndroid Build Coastguard Worker   check_ping_status_pending_ = true;
2372*6777b538SAndroid Build Coastguard Worker   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
2373*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
2374*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
2375*6777b538SAndroid Build Coastguard Worker                      time_func_()),
2376*6777b538SAndroid Build Coastguard Worker       hung_interval_);
2377*6777b538SAndroid Build Coastguard Worker }
2378*6777b538SAndroid Build Coastguard Worker 
CheckPingStatus(base::TimeTicks last_check_time)2379*6777b538SAndroid Build Coastguard Worker void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) {
2380*6777b538SAndroid Build Coastguard Worker   CHECK(!in_io_loop_);
2381*6777b538SAndroid Build Coastguard Worker   DCHECK(check_ping_status_pending_);
2382*6777b538SAndroid Build Coastguard Worker 
2383*6777b538SAndroid Build Coastguard Worker   if (!ping_in_flight_) {
2384*6777b538SAndroid Build Coastguard Worker     // A response has been received for the ping we had sent.
2385*6777b538SAndroid Build Coastguard Worker     check_ping_status_pending_ = false;
2386*6777b538SAndroid Build Coastguard Worker     return;
2387*6777b538SAndroid Build Coastguard Worker   }
2388*6777b538SAndroid Build Coastguard Worker 
2389*6777b538SAndroid Build Coastguard Worker   const base::TimeTicks now = time_func_();
2390*6777b538SAndroid Build Coastguard Worker   if (now > last_read_time_ + hung_interval_ ||
2391*6777b538SAndroid Build Coastguard Worker       last_read_time_ < last_check_time) {
2392*6777b538SAndroid Build Coastguard Worker     check_ping_status_pending_ = false;
2393*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_HTTP2_PING_FAILED, "Failed ping.");
2394*6777b538SAndroid Build Coastguard Worker     return;
2395*6777b538SAndroid Build Coastguard Worker   }
2396*6777b538SAndroid Build Coastguard Worker 
2397*6777b538SAndroid Build Coastguard Worker   // Check the status of connection after a delay.
2398*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta delay = last_read_time_ + hung_interval_ - now;
2399*6777b538SAndroid Build Coastguard Worker   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
2400*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
2401*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
2402*6777b538SAndroid Build Coastguard Worker                      now),
2403*6777b538SAndroid Build Coastguard Worker       delay);
2404*6777b538SAndroid Build Coastguard Worker }
2405*6777b538SAndroid Build Coastguard Worker 
GetNewStreamId()2406*6777b538SAndroid Build Coastguard Worker spdy::SpdyStreamId SpdySession::GetNewStreamId() {
2407*6777b538SAndroid Build Coastguard Worker   CHECK_LE(stream_hi_water_mark_, kLastStreamId);
2408*6777b538SAndroid Build Coastguard Worker   spdy::SpdyStreamId id = stream_hi_water_mark_;
2409*6777b538SAndroid Build Coastguard Worker   stream_hi_water_mark_ += 2;
2410*6777b538SAndroid Build Coastguard Worker   return id;
2411*6777b538SAndroid Build Coastguard Worker }
2412*6777b538SAndroid Build Coastguard Worker 
EnqueueSessionWrite(RequestPriority priority,spdy::SpdyFrameType frame_type,std::unique_ptr<spdy::SpdySerializedFrame> frame)2413*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueueSessionWrite(
2414*6777b538SAndroid Build Coastguard Worker     RequestPriority priority,
2415*6777b538SAndroid Build Coastguard Worker     spdy::SpdyFrameType frame_type,
2416*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<spdy::SpdySerializedFrame> frame) {
2417*6777b538SAndroid Build Coastguard Worker   DCHECK(frame_type == spdy::SpdyFrameType::RST_STREAM ||
2418*6777b538SAndroid Build Coastguard Worker          frame_type == spdy::SpdyFrameType::SETTINGS ||
2419*6777b538SAndroid Build Coastguard Worker          frame_type == spdy::SpdyFrameType::WINDOW_UPDATE ||
2420*6777b538SAndroid Build Coastguard Worker          frame_type == spdy::SpdyFrameType::PING ||
2421*6777b538SAndroid Build Coastguard Worker          frame_type == spdy::SpdyFrameType::GOAWAY);
2422*6777b538SAndroid Build Coastguard Worker   DCHECK(IsSpdyFrameTypeWriteCapped(frame_type));
2423*6777b538SAndroid Build Coastguard Worker   if (write_queue_.num_queued_capped_frames() >
2424*6777b538SAndroid Build Coastguard Worker       session_max_queued_capped_frames_) {
2425*6777b538SAndroid Build Coastguard Worker     LOG(WARNING)
2426*6777b538SAndroid Build Coastguard Worker         << "Draining session due to exceeding max queued capped frames";
2427*6777b538SAndroid Build Coastguard Worker     // Use ERR_CONNECTION_CLOSED to avoid sending a GOAWAY frame since that
2428*6777b538SAndroid Build Coastguard Worker     // frame would also exceed the cap.
2429*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_CONNECTION_CLOSED, "Exceeded max queued capped frames");
2430*6777b538SAndroid Build Coastguard Worker     return;
2431*6777b538SAndroid Build Coastguard Worker   }
2432*6777b538SAndroid Build Coastguard Worker   auto buffer = std::make_unique<SpdyBuffer>(std::move(frame));
2433*6777b538SAndroid Build Coastguard Worker   EnqueueWrite(priority, frame_type,
2434*6777b538SAndroid Build Coastguard Worker                std::make_unique<SimpleBufferProducer>(std::move(buffer)),
2435*6777b538SAndroid Build Coastguard Worker                base::WeakPtr<SpdyStream>(),
2436*6777b538SAndroid Build Coastguard Worker                kSpdySessionCommandsTrafficAnnotation);
2437*6777b538SAndroid Build Coastguard Worker   if (greased_http2_frame_ && frame_type == spdy::SpdyFrameType::SETTINGS) {
2438*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_GREASED_FRAME, [&] {
2439*6777b538SAndroid Build Coastguard Worker       return NetLogSpdyGreasedFrameParams(
2440*6777b538SAndroid Build Coastguard Worker           /* stream_id = */ 0, greased_http2_frame_.value().type,
2441*6777b538SAndroid Build Coastguard Worker           greased_http2_frame_.value().flags,
2442*6777b538SAndroid Build Coastguard Worker           greased_http2_frame_.value().payload.length(), priority);
2443*6777b538SAndroid Build Coastguard Worker     });
2444*6777b538SAndroid Build Coastguard Worker 
2445*6777b538SAndroid Build Coastguard Worker     EnqueueWrite(
2446*6777b538SAndroid Build Coastguard Worker         priority,
2447*6777b538SAndroid Build Coastguard Worker         static_cast<spdy::SpdyFrameType>(greased_http2_frame_.value().type),
2448*6777b538SAndroid Build Coastguard Worker         std::make_unique<GreasedBufferProducer>(base::WeakPtr<SpdyStream>(),
2449*6777b538SAndroid Build Coastguard Worker                                                 &greased_http2_frame_.value(),
2450*6777b538SAndroid Build Coastguard Worker                                                 buffered_spdy_framer_.get()),
2451*6777b538SAndroid Build Coastguard Worker         base::WeakPtr<SpdyStream>(), kSpdySessionCommandsTrafficAnnotation);
2452*6777b538SAndroid Build Coastguard Worker   }
2453*6777b538SAndroid Build Coastguard Worker }
2454*6777b538SAndroid Build Coastguard Worker 
EnqueueWrite(RequestPriority priority,spdy::SpdyFrameType frame_type,std::unique_ptr<SpdyBufferProducer> producer,const base::WeakPtr<SpdyStream> & stream,const NetworkTrafficAnnotationTag & traffic_annotation)2455*6777b538SAndroid Build Coastguard Worker void SpdySession::EnqueueWrite(
2456*6777b538SAndroid Build Coastguard Worker     RequestPriority priority,
2457*6777b538SAndroid Build Coastguard Worker     spdy::SpdyFrameType frame_type,
2458*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<SpdyBufferProducer> producer,
2459*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStream>& stream,
2460*6777b538SAndroid Build Coastguard Worker     const NetworkTrafficAnnotationTag& traffic_annotation) {
2461*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING)
2462*6777b538SAndroid Build Coastguard Worker     return;
2463*6777b538SAndroid Build Coastguard Worker 
2464*6777b538SAndroid Build Coastguard Worker   write_queue_.Enqueue(priority, frame_type, std::move(producer), stream,
2465*6777b538SAndroid Build Coastguard Worker                        traffic_annotation);
2466*6777b538SAndroid Build Coastguard Worker   MaybePostWriteLoop();
2467*6777b538SAndroid Build Coastguard Worker }
2468*6777b538SAndroid Build Coastguard Worker 
InsertCreatedStream(std::unique_ptr<SpdyStream> stream)2469*6777b538SAndroid Build Coastguard Worker void SpdySession::InsertCreatedStream(std::unique_ptr<SpdyStream> stream) {
2470*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), 0u);
2471*6777b538SAndroid Build Coastguard Worker   auto it = created_streams_.lower_bound(stream.get());
2472*6777b538SAndroid Build Coastguard Worker   CHECK(it == created_streams_.end() || *it != stream.get());
2473*6777b538SAndroid Build Coastguard Worker   created_streams_.insert(it, stream.release());
2474*6777b538SAndroid Build Coastguard Worker }
2475*6777b538SAndroid Build Coastguard Worker 
ActivateCreatedStream(SpdyStream * stream)2476*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SpdyStream> SpdySession::ActivateCreatedStream(
2477*6777b538SAndroid Build Coastguard Worker     SpdyStream* stream) {
2478*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), 0u);
2479*6777b538SAndroid Build Coastguard Worker   auto it = created_streams_.find(stream);
2480*6777b538SAndroid Build Coastguard Worker   CHECK(it != created_streams_.end());
2481*6777b538SAndroid Build Coastguard Worker   stream->set_stream_id(GetNewStreamId());
2482*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SpdyStream> owned_stream(stream);
2483*6777b538SAndroid Build Coastguard Worker   created_streams_.erase(it);
2484*6777b538SAndroid Build Coastguard Worker   return owned_stream;
2485*6777b538SAndroid Build Coastguard Worker }
2486*6777b538SAndroid Build Coastguard Worker 
InsertActivatedStream(std::unique_ptr<SpdyStream> stream)2487*6777b538SAndroid Build Coastguard Worker void SpdySession::InsertActivatedStream(std::unique_ptr<SpdyStream> stream) {
2488*6777b538SAndroid Build Coastguard Worker   spdy::SpdyStreamId stream_id = stream->stream_id();
2489*6777b538SAndroid Build Coastguard Worker   CHECK_NE(stream_id, 0u);
2490*6777b538SAndroid Build Coastguard Worker   std::pair<ActiveStreamMap::iterator, bool> result =
2491*6777b538SAndroid Build Coastguard Worker       active_streams_.emplace(stream_id, stream.get());
2492*6777b538SAndroid Build Coastguard Worker   CHECK(result.second);
2493*6777b538SAndroid Build Coastguard Worker   std::ignore = stream.release();
2494*6777b538SAndroid Build Coastguard Worker }
2495*6777b538SAndroid Build Coastguard Worker 
DeleteStream(std::unique_ptr<SpdyStream> stream,int status)2496*6777b538SAndroid Build Coastguard Worker void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) {
2497*6777b538SAndroid Build Coastguard Worker   if (in_flight_write_stream_.get() == stream.get()) {
2498*6777b538SAndroid Build Coastguard Worker     // If we're deleting the stream for the in-flight write, we still
2499*6777b538SAndroid Build Coastguard Worker     // need to let the write complete, so we clear
2500*6777b538SAndroid Build Coastguard Worker     // |in_flight_write_stream_| and let the write finish on its own
2501*6777b538SAndroid Build Coastguard Worker     // without notifying |in_flight_write_stream_|.
2502*6777b538SAndroid Build Coastguard Worker     in_flight_write_stream_.reset();
2503*6777b538SAndroid Build Coastguard Worker   }
2504*6777b538SAndroid Build Coastguard Worker 
2505*6777b538SAndroid Build Coastguard Worker   write_queue_.RemovePendingWritesForStream(stream.get());
2506*6777b538SAndroid Build Coastguard Worker   if (stream->detect_broken_connection())
2507*6777b538SAndroid Build Coastguard Worker     MaybeDisableBrokenConnectionDetection();
2508*6777b538SAndroid Build Coastguard Worker   stream->OnClose(status);
2509*6777b538SAndroid Build Coastguard Worker 
2510*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_AVAILABLE) {
2511*6777b538SAndroid Build Coastguard Worker     ProcessPendingStreamRequests();
2512*6777b538SAndroid Build Coastguard Worker   }
2513*6777b538SAndroid Build Coastguard Worker }
2514*6777b538SAndroid Build Coastguard Worker 
RecordHistograms()2515*6777b538SAndroid Build Coastguard Worker void SpdySession::RecordHistograms() {
2516*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
2517*6777b538SAndroid Build Coastguard Worker                               streams_initiated_count_, 1, 300, 50);
2518*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
2519*6777b538SAndroid Build Coastguard Worker                               streams_abandoned_count_, 1, 300, 50);
2520*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.ServerSupportsWebSocket",
2521*6777b538SAndroid Build Coastguard Worker                         support_websocket_);
2522*6777b538SAndroid Build Coastguard Worker }
2523*6777b538SAndroid Build Coastguard Worker 
RecordProtocolErrorHistogram(SpdyProtocolErrorDetails details)2524*6777b538SAndroid Build Coastguard Worker void SpdySession::RecordProtocolErrorHistogram(
2525*6777b538SAndroid Build Coastguard Worker     SpdyProtocolErrorDetails details) {
2526*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details,
2527*6777b538SAndroid Build Coastguard Worker                             NUM_SPDY_PROTOCOL_ERROR_DETAILS);
2528*6777b538SAndroid Build Coastguard Worker   if (base::EndsWith(host_port_pair().host(), "google.com",
2529*6777b538SAndroid Build Coastguard Worker                      base::CompareCase::INSENSITIVE_ASCII)) {
2530*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details,
2531*6777b538SAndroid Build Coastguard Worker                               NUM_SPDY_PROTOCOL_ERROR_DETAILS);
2532*6777b538SAndroid Build Coastguard Worker   }
2533*6777b538SAndroid Build Coastguard Worker }
2534*6777b538SAndroid Build Coastguard Worker 
DcheckGoingAway() const2535*6777b538SAndroid Build Coastguard Worker void SpdySession::DcheckGoingAway() const {
2536*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
2537*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(availability_state_, STATE_GOING_AWAY);
2538*6777b538SAndroid Build Coastguard Worker   for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
2539*6777b538SAndroid Build Coastguard Worker     DCHECK(pending_create_stream_queues_[i].empty());
2540*6777b538SAndroid Build Coastguard Worker   }
2541*6777b538SAndroid Build Coastguard Worker   DCHECK(created_streams_.empty());
2542*6777b538SAndroid Build Coastguard Worker #endif
2543*6777b538SAndroid Build Coastguard Worker }
2544*6777b538SAndroid Build Coastguard Worker 
DcheckDraining() const2545*6777b538SAndroid Build Coastguard Worker void SpdySession::DcheckDraining() const {
2546*6777b538SAndroid Build Coastguard Worker   DcheckGoingAway();
2547*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(availability_state_, STATE_DRAINING);
2548*6777b538SAndroid Build Coastguard Worker   DCHECK(active_streams_.empty());
2549*6777b538SAndroid Build Coastguard Worker }
2550*6777b538SAndroid Build Coastguard Worker 
DoDrainSession(Error err,const std::string & description)2551*6777b538SAndroid Build Coastguard Worker void SpdySession::DoDrainSession(Error err, const std::string& description) {
2552*6777b538SAndroid Build Coastguard Worker   if (availability_state_ == STATE_DRAINING) {
2553*6777b538SAndroid Build Coastguard Worker     return;
2554*6777b538SAndroid Build Coastguard Worker   }
2555*6777b538SAndroid Build Coastguard Worker   MakeUnavailable();
2556*6777b538SAndroid Build Coastguard Worker 
2557*6777b538SAndroid Build Coastguard Worker   // Mark host_port_pair requiring HTTP/1.1 for subsequent connections.
2558*6777b538SAndroid Build Coastguard Worker   if (err == ERR_HTTP_1_1_REQUIRED) {
2559*6777b538SAndroid Build Coastguard Worker     http_server_properties_->SetHTTP11Required(
2560*6777b538SAndroid Build Coastguard Worker         url::SchemeHostPort(url::kHttpsScheme, host_port_pair().host(),
2561*6777b538SAndroid Build Coastguard Worker                             host_port_pair().port()),
2562*6777b538SAndroid Build Coastguard Worker         spdy_session_key_.network_anonymization_key());
2563*6777b538SAndroid Build Coastguard Worker   }
2564*6777b538SAndroid Build Coastguard Worker 
2565*6777b538SAndroid Build Coastguard Worker   // If |err| indicates an error occurred, inform the peer that we're closing
2566*6777b538SAndroid Build Coastguard Worker   // and why. Don't GOAWAY on a graceful or idle close, as that may
2567*6777b538SAndroid Build Coastguard Worker   // unnecessarily wake the radio. We could technically GOAWAY on network errors
2568*6777b538SAndroid Build Coastguard Worker   // (we'll probably fail to actually write it, but that's okay), however many
2569*6777b538SAndroid Build Coastguard Worker   // unit-tests would need to be updated.
2570*6777b538SAndroid Build Coastguard Worker   if (err != OK &&
2571*6777b538SAndroid Build Coastguard Worker       err != ERR_ABORTED &&  // Used by SpdySessionPool to close idle sessions.
2572*6777b538SAndroid Build Coastguard Worker       err != ERR_NETWORK_CHANGED &&  // Used to deprecate sessions on IP change.
2573*6777b538SAndroid Build Coastguard Worker       err != ERR_SOCKET_NOT_CONNECTED && err != ERR_HTTP_1_1_REQUIRED &&
2574*6777b538SAndroid Build Coastguard Worker       err != ERR_CONNECTION_CLOSED && err != ERR_CONNECTION_RESET) {
2575*6777b538SAndroid Build Coastguard Worker     // Enqueue a GOAWAY to inform the peer of why we're closing the connection.
2576*6777b538SAndroid Build Coastguard Worker     spdy::SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 0,
2577*6777b538SAndroid Build Coastguard Worker                                  MapNetErrorToGoAwayStatus(err), description);
2578*6777b538SAndroid Build Coastguard Worker     auto frame = std::make_unique<spdy::SpdySerializedFrame>(
2579*6777b538SAndroid Build Coastguard Worker         buffered_spdy_framer_->SerializeFrame(goaway_ir));
2580*6777b538SAndroid Build Coastguard Worker     EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::GOAWAY, std::move(frame));
2581*6777b538SAndroid Build Coastguard Worker   }
2582*6777b538SAndroid Build Coastguard Worker 
2583*6777b538SAndroid Build Coastguard Worker   availability_state_ = STATE_DRAINING;
2584*6777b538SAndroid Build Coastguard Worker   error_on_close_ = err;
2585*6777b538SAndroid Build Coastguard Worker 
2586*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_CLOSE, [&] {
2587*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionCloseParams(err, description);
2588*6777b538SAndroid Build Coastguard Worker   });
2589*6777b538SAndroid Build Coastguard Worker 
2590*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramSparse("Net.SpdySession.ClosedOnError", -err);
2591*6777b538SAndroid Build Coastguard Worker 
2592*6777b538SAndroid Build Coastguard Worker   if (err == OK) {
2593*6777b538SAndroid Build Coastguard Worker     // We ought to be going away already, as this is a graceful close.
2594*6777b538SAndroid Build Coastguard Worker     DcheckGoingAway();
2595*6777b538SAndroid Build Coastguard Worker   } else {
2596*6777b538SAndroid Build Coastguard Worker     StartGoingAway(0, err);
2597*6777b538SAndroid Build Coastguard Worker   }
2598*6777b538SAndroid Build Coastguard Worker   DcheckDraining();
2599*6777b538SAndroid Build Coastguard Worker   MaybePostWriteLoop();
2600*6777b538SAndroid Build Coastguard Worker }
2601*6777b538SAndroid Build Coastguard Worker 
LogAbandonedStream(SpdyStream * stream,Error status)2602*6777b538SAndroid Build Coastguard Worker void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) {
2603*6777b538SAndroid Build Coastguard Worker   DCHECK(stream);
2604*6777b538SAndroid Build Coastguard Worker   stream->LogStreamError(status, "Abandoned.");
2605*6777b538SAndroid Build Coastguard Worker   // We don't increment the streams abandoned counter here. If the
2606*6777b538SAndroid Build Coastguard Worker   // stream isn't active (i.e., it hasn't written anything to the wire
2607*6777b538SAndroid Build Coastguard Worker   // yet) then it's as if it never existed. If it is active, then
2608*6777b538SAndroid Build Coastguard Worker   // LogAbandonedActiveStream() will increment the counters.
2609*6777b538SAndroid Build Coastguard Worker }
2610*6777b538SAndroid Build Coastguard Worker 
LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,Error status)2611*6777b538SAndroid Build Coastguard Worker void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
2612*6777b538SAndroid Build Coastguard Worker                                            Error status) {
2613*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(it->first, 0u);
2614*6777b538SAndroid Build Coastguard Worker   LogAbandonedStream(it->second, status);
2615*6777b538SAndroid Build Coastguard Worker   ++streams_abandoned_count_;
2616*6777b538SAndroid Build Coastguard Worker }
2617*6777b538SAndroid Build Coastguard Worker 
CompleteStreamRequest(const base::WeakPtr<SpdyStreamRequest> & pending_request)2618*6777b538SAndroid Build Coastguard Worker void SpdySession::CompleteStreamRequest(
2619*6777b538SAndroid Build Coastguard Worker     const base::WeakPtr<SpdyStreamRequest>& pending_request) {
2620*6777b538SAndroid Build Coastguard Worker   // Abort if the request has already been cancelled.
2621*6777b538SAndroid Build Coastguard Worker   if (!pending_request)
2622*6777b538SAndroid Build Coastguard Worker     return;
2623*6777b538SAndroid Build Coastguard Worker 
2624*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<SpdyStream> stream;
2625*6777b538SAndroid Build Coastguard Worker   int rv = TryCreateStream(pending_request, &stream);
2626*6777b538SAndroid Build Coastguard Worker 
2627*6777b538SAndroid Build Coastguard Worker   if (rv == OK) {
2628*6777b538SAndroid Build Coastguard Worker     DCHECK(stream);
2629*6777b538SAndroid Build Coastguard Worker     pending_request->OnRequestCompleteSuccess(stream);
2630*6777b538SAndroid Build Coastguard Worker     return;
2631*6777b538SAndroid Build Coastguard Worker   }
2632*6777b538SAndroid Build Coastguard Worker   DCHECK(!stream);
2633*6777b538SAndroid Build Coastguard Worker 
2634*6777b538SAndroid Build Coastguard Worker   if (rv != ERR_IO_PENDING) {
2635*6777b538SAndroid Build Coastguard Worker     pending_request->OnRequestCompleteFailure(rv);
2636*6777b538SAndroid Build Coastguard Worker   }
2637*6777b538SAndroid Build Coastguard Worker }
2638*6777b538SAndroid Build Coastguard Worker 
OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error)2639*6777b538SAndroid Build Coastguard Worker void SpdySession::OnError(
2640*6777b538SAndroid Build Coastguard Worker     http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) {
2641*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2642*6777b538SAndroid Build Coastguard Worker 
2643*6777b538SAndroid Build Coastguard Worker   RecordProtocolErrorHistogram(
2644*6777b538SAndroid Build Coastguard Worker       MapFramerErrorToProtocolError(spdy_framer_error));
2645*6777b538SAndroid Build Coastguard Worker   std::string description = base::StringPrintf(
2646*6777b538SAndroid Build Coastguard Worker       "Framer error: %d (%s).", spdy_framer_error,
2647*6777b538SAndroid Build Coastguard Worker       http2::Http2DecoderAdapter::SpdyFramerErrorToString(spdy_framer_error));
2648*6777b538SAndroid Build Coastguard Worker   DoDrainSession(MapFramerErrorToNetError(spdy_framer_error), description);
2649*6777b538SAndroid Build Coastguard Worker }
2650*6777b538SAndroid Build Coastguard Worker 
OnStreamError(spdy::SpdyStreamId stream_id,const std::string & description)2651*6777b538SAndroid Build Coastguard Worker void SpdySession::OnStreamError(spdy::SpdyStreamId stream_id,
2652*6777b538SAndroid Build Coastguard Worker                                 const std::string& description) {
2653*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2654*6777b538SAndroid Build Coastguard Worker 
2655*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2656*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end()) {
2657*6777b538SAndroid Build Coastguard Worker     // We still want to send a frame to reset the stream even if we
2658*6777b538SAndroid Build Coastguard Worker     // don't know anything about it.
2659*6777b538SAndroid Build Coastguard Worker     EnqueueResetStreamFrame(stream_id, IDLE, spdy::ERROR_CODE_PROTOCOL_ERROR,
2660*6777b538SAndroid Build Coastguard Worker                             description);
2661*6777b538SAndroid Build Coastguard Worker     return;
2662*6777b538SAndroid Build Coastguard Worker   }
2663*6777b538SAndroid Build Coastguard Worker 
2664*6777b538SAndroid Build Coastguard Worker   ResetStreamIterator(it, ERR_HTTP2_PROTOCOL_ERROR, description);
2665*6777b538SAndroid Build Coastguard Worker }
2666*6777b538SAndroid Build Coastguard Worker 
OnPing(spdy::SpdyPingId unique_id,bool is_ack)2667*6777b538SAndroid Build Coastguard Worker void SpdySession::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
2668*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2669*6777b538SAndroid Build Coastguard Worker 
2670*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] {
2671*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyPingParams(unique_id, is_ack, "received");
2672*6777b538SAndroid Build Coastguard Worker   });
2673*6777b538SAndroid Build Coastguard Worker 
2674*6777b538SAndroid Build Coastguard Worker   // Send response to a PING from server.
2675*6777b538SAndroid Build Coastguard Worker   if (!is_ack) {
2676*6777b538SAndroid Build Coastguard Worker     WritePingFrame(unique_id, true);
2677*6777b538SAndroid Build Coastguard Worker     return;
2678*6777b538SAndroid Build Coastguard Worker   }
2679*6777b538SAndroid Build Coastguard Worker 
2680*6777b538SAndroid Build Coastguard Worker   if (!ping_in_flight_) {
2681*6777b538SAndroid Build Coastguard Worker     RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING);
2682*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_HTTP2_PROTOCOL_ERROR, "Unexpected PING ACK.");
2683*6777b538SAndroid Build Coastguard Worker     return;
2684*6777b538SAndroid Build Coastguard Worker   }
2685*6777b538SAndroid Build Coastguard Worker 
2686*6777b538SAndroid Build Coastguard Worker   ping_in_flight_ = false;
2687*6777b538SAndroid Build Coastguard Worker 
2688*6777b538SAndroid Build Coastguard Worker   // Record RTT in histogram when there are no more pings in flight.
2689*6777b538SAndroid Build Coastguard Worker   base::TimeDelta ping_duration = time_func_() - last_ping_sent_time_;
2690*6777b538SAndroid Build Coastguard Worker   if (network_quality_estimator_) {
2691*6777b538SAndroid Build Coastguard Worker     network_quality_estimator_->RecordSpdyPingLatency(host_port_pair(),
2692*6777b538SAndroid Build Coastguard Worker                                                       ping_duration);
2693*6777b538SAndroid Build Coastguard Worker   }
2694*6777b538SAndroid Build Coastguard Worker }
2695*6777b538SAndroid Build Coastguard Worker 
OnRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)2696*6777b538SAndroid Build Coastguard Worker void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id,
2697*6777b538SAndroid Build Coastguard Worker                               spdy::SpdyErrorCode error_code) {
2698*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2699*6777b538SAndroid Build Coastguard Worker 
2700*6777b538SAndroid Build Coastguard Worker   // Use sparse histogram to record the unlikely case that a server sends
2701*6777b538SAndroid Build Coastguard Worker   // an unknown error code.
2702*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramSparse("Net.SpdySession.RstStreamReceived", error_code);
2703*6777b538SAndroid Build Coastguard Worker 
2704*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, [&] {
2705*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyRecvRstStreamParams(stream_id, error_code);
2706*6777b538SAndroid Build Coastguard Worker   });
2707*6777b538SAndroid Build Coastguard Worker 
2708*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2709*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end()) {
2710*6777b538SAndroid Build Coastguard Worker     // NOTE:  it may just be that the stream was cancelled.
2711*6777b538SAndroid Build Coastguard Worker     LOG(WARNING) << "Received RST for invalid stream" << stream_id;
2712*6777b538SAndroid Build Coastguard Worker     return;
2713*6777b538SAndroid Build Coastguard Worker   }
2714*6777b538SAndroid Build Coastguard Worker 
2715*6777b538SAndroid Build Coastguard Worker   DCHECK(it->second);
2716*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(it->second->stream_id(), stream_id);
2717*6777b538SAndroid Build Coastguard Worker 
2718*6777b538SAndroid Build Coastguard Worker   if (error_code == spdy::ERROR_CODE_NO_ERROR) {
2719*6777b538SAndroid Build Coastguard Worker     CloseActiveStreamIterator(it, ERR_HTTP2_RST_STREAM_NO_ERROR_RECEIVED);
2720*6777b538SAndroid Build Coastguard Worker   } else if (error_code == spdy::ERROR_CODE_REFUSED_STREAM) {
2721*6777b538SAndroid Build Coastguard Worker     CloseActiveStreamIterator(it, ERR_HTTP2_SERVER_REFUSED_STREAM);
2722*6777b538SAndroid Build Coastguard Worker   } else if (error_code == spdy::ERROR_CODE_HTTP_1_1_REQUIRED) {
2723*6777b538SAndroid Build Coastguard Worker     // TODO(bnc): Record histogram with number of open streams capped at 50.
2724*6777b538SAndroid Build Coastguard Worker     it->second->LogStreamError(ERR_HTTP_1_1_REQUIRED,
2725*6777b538SAndroid Build Coastguard Worker                                "Closing session because server reset stream "
2726*6777b538SAndroid Build Coastguard Worker                                "with ERR_HTTP_1_1_REQUIRED.");
2727*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream.");
2728*6777b538SAndroid Build Coastguard Worker   } else {
2729*6777b538SAndroid Build Coastguard Worker     RecordProtocolErrorHistogram(
2730*6777b538SAndroid Build Coastguard Worker         PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM);
2731*6777b538SAndroid Build Coastguard Worker     it->second->LogStreamError(ERR_HTTP2_PROTOCOL_ERROR,
2732*6777b538SAndroid Build Coastguard Worker                                "Server reset stream.");
2733*6777b538SAndroid Build Coastguard Worker     // TODO(mbelshe): Map from Spdy-protocol errors to something sensical.
2734*6777b538SAndroid Build Coastguard Worker     //                For now, it doesn't matter much - it is a protocol error.
2735*6777b538SAndroid Build Coastguard Worker     CloseActiveStreamIterator(it, ERR_HTTP2_PROTOCOL_ERROR);
2736*6777b538SAndroid Build Coastguard Worker   }
2737*6777b538SAndroid Build Coastguard Worker }
2738*6777b538SAndroid Build Coastguard Worker 
OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,spdy::SpdyErrorCode error_code,std::string_view debug_data)2739*6777b538SAndroid Build Coastguard Worker void SpdySession::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
2740*6777b538SAndroid Build Coastguard Worker                            spdy::SpdyErrorCode error_code,
2741*6777b538SAndroid Build Coastguard Worker                            std::string_view debug_data) {
2742*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2743*6777b538SAndroid Build Coastguard Worker 
2744*6777b538SAndroid Build Coastguard Worker   // Use sparse histogram to record the unlikely case that a server sends
2745*6777b538SAndroid Build Coastguard Worker   // an unknown error code.
2746*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramSparse("Net.SpdySession.GoAwayReceived", error_code);
2747*6777b538SAndroid Build Coastguard Worker 
2748*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_GOAWAY,
2749*6777b538SAndroid Build Coastguard Worker                     [&](NetLogCaptureMode capture_mode) {
2750*6777b538SAndroid Build Coastguard Worker                       return NetLogSpdyRecvGoAwayParams(
2751*6777b538SAndroid Build Coastguard Worker                           last_accepted_stream_id, active_streams_.size(),
2752*6777b538SAndroid Build Coastguard Worker                           error_code, debug_data, capture_mode);
2753*6777b538SAndroid Build Coastguard Worker                     });
2754*6777b538SAndroid Build Coastguard Worker   MakeUnavailable();
2755*6777b538SAndroid Build Coastguard Worker   if (error_code == spdy::ERROR_CODE_HTTP_1_1_REQUIRED) {
2756*6777b538SAndroid Build Coastguard Worker     // TODO(bnc): Record histogram with number of open streams capped at 50.
2757*6777b538SAndroid Build Coastguard Worker     DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream.");
2758*6777b538SAndroid Build Coastguard Worker   } else if (error_code == spdy::ERROR_CODE_NO_ERROR) {
2759*6777b538SAndroid Build Coastguard Worker     StartGoingAway(last_accepted_stream_id, ERR_HTTP2_SERVER_REFUSED_STREAM);
2760*6777b538SAndroid Build Coastguard Worker   } else {
2761*6777b538SAndroid Build Coastguard Worker     StartGoingAway(last_accepted_stream_id, ERR_HTTP2_PROTOCOL_ERROR);
2762*6777b538SAndroid Build Coastguard Worker   }
2763*6777b538SAndroid Build Coastguard Worker   // This is to handle the case when we already don't have any active
2764*6777b538SAndroid Build Coastguard Worker   // streams (i.e., StartGoingAway() did nothing). Otherwise, we have
2765*6777b538SAndroid Build Coastguard Worker   // active streams and so the last one being closed will finish the
2766*6777b538SAndroid Build Coastguard Worker   // going away process (see DeleteStream()).
2767*6777b538SAndroid Build Coastguard Worker   MaybeFinishGoingAway();
2768*6777b538SAndroid Build Coastguard Worker }
2769*6777b538SAndroid Build Coastguard Worker 
OnDataFrameHeader(spdy::SpdyStreamId stream_id,size_t length,bool fin)2770*6777b538SAndroid Build Coastguard Worker void SpdySession::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
2771*6777b538SAndroid Build Coastguard Worker                                     size_t length,
2772*6777b538SAndroid Build Coastguard Worker                                     bool fin) {
2773*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2774*6777b538SAndroid Build Coastguard Worker 
2775*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] {
2776*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyDataParams(stream_id, length, fin);
2777*6777b538SAndroid Build Coastguard Worker   });
2778*6777b538SAndroid Build Coastguard Worker 
2779*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2780*6777b538SAndroid Build Coastguard Worker 
2781*6777b538SAndroid Build Coastguard Worker   // By the time data comes in, the stream may already be inactive.
2782*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end())
2783*6777b538SAndroid Build Coastguard Worker     return;
2784*6777b538SAndroid Build Coastguard Worker 
2785*6777b538SAndroid Build Coastguard Worker   SpdyStream* stream = it->second;
2786*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), stream_id);
2787*6777b538SAndroid Build Coastguard Worker 
2788*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_);
2789*6777b538SAndroid Build Coastguard Worker   stream->AddRawReceivedBytes(spdy::kDataFrameMinimumSize);
2790*6777b538SAndroid Build Coastguard Worker }
2791*6777b538SAndroid Build Coastguard Worker 
OnStreamFrameData(spdy::SpdyStreamId stream_id,const char * data,size_t len)2792*6777b538SAndroid Build Coastguard Worker void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id,
2793*6777b538SAndroid Build Coastguard Worker                                     const char* data,
2794*6777b538SAndroid Build Coastguard Worker                                     size_t len) {
2795*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2796*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(len, 1u << 24);
2797*6777b538SAndroid Build Coastguard Worker 
2798*6777b538SAndroid Build Coastguard Worker   // Build the buffer as early as possible so that we go through the
2799*6777b538SAndroid Build Coastguard Worker   // session flow control checks and update
2800*6777b538SAndroid Build Coastguard Worker   // |unacked_recv_window_bytes_| properly even when the stream is
2801*6777b538SAndroid Build Coastguard Worker   // inactive (since the other side has still reduced its session send
2802*6777b538SAndroid Build Coastguard Worker   // window).
2803*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<SpdyBuffer> buffer;
2804*6777b538SAndroid Build Coastguard Worker   if (data) {
2805*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(len, 0u);
2806*6777b538SAndroid Build Coastguard Worker     CHECK_LE(len, static_cast<size_t>(kReadBufferSize));
2807*6777b538SAndroid Build Coastguard Worker     buffer = std::make_unique<SpdyBuffer>(data, len);
2808*6777b538SAndroid Build Coastguard Worker 
2809*6777b538SAndroid Build Coastguard Worker     DecreaseRecvWindowSize(static_cast<int32_t>(len));
2810*6777b538SAndroid Build Coastguard Worker     buffer->AddConsumeCallback(base::BindRepeating(
2811*6777b538SAndroid Build Coastguard Worker         &SpdySession::OnReadBufferConsumed, weak_factory_.GetWeakPtr()));
2812*6777b538SAndroid Build Coastguard Worker   } else {
2813*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(len, 0u);
2814*6777b538SAndroid Build Coastguard Worker   }
2815*6777b538SAndroid Build Coastguard Worker 
2816*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2817*6777b538SAndroid Build Coastguard Worker 
2818*6777b538SAndroid Build Coastguard Worker   // By the time data comes in, the stream may already be inactive.
2819*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end())
2820*6777b538SAndroid Build Coastguard Worker     return;
2821*6777b538SAndroid Build Coastguard Worker 
2822*6777b538SAndroid Build Coastguard Worker   SpdyStream* stream = it->second;
2823*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), stream_id);
2824*6777b538SAndroid Build Coastguard Worker 
2825*6777b538SAndroid Build Coastguard Worker   stream->AddRawReceivedBytes(len);
2826*6777b538SAndroid Build Coastguard Worker   stream->OnDataReceived(std::move(buffer));
2827*6777b538SAndroid Build Coastguard Worker }
2828*6777b538SAndroid Build Coastguard Worker 
OnStreamEnd(spdy::SpdyStreamId stream_id)2829*6777b538SAndroid Build Coastguard Worker void SpdySession::OnStreamEnd(spdy::SpdyStreamId stream_id) {
2830*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2831*6777b538SAndroid Build Coastguard Worker 
2832*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2833*6777b538SAndroid Build Coastguard Worker   // By the time data comes in, the stream may already be inactive.
2834*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end())
2835*6777b538SAndroid Build Coastguard Worker     return;
2836*6777b538SAndroid Build Coastguard Worker 
2837*6777b538SAndroid Build Coastguard Worker   SpdyStream* stream = it->second;
2838*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), stream_id);
2839*6777b538SAndroid Build Coastguard Worker 
2840*6777b538SAndroid Build Coastguard Worker   stream->OnDataReceived(std::unique_ptr<SpdyBuffer>());
2841*6777b538SAndroid Build Coastguard Worker }
2842*6777b538SAndroid Build Coastguard Worker 
OnStreamPadding(spdy::SpdyStreamId stream_id,size_t len)2843*6777b538SAndroid Build Coastguard Worker void SpdySession::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) {
2844*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2845*6777b538SAndroid Build Coastguard Worker 
2846*6777b538SAndroid Build Coastguard Worker   // Decrease window size because padding bytes are received.
2847*6777b538SAndroid Build Coastguard Worker   // Increase window size because padding bytes are consumed (by discarding).
2848*6777b538SAndroid Build Coastguard Worker   // Net result: |session_unacked_recv_window_bytes_| increases by |len|,
2849*6777b538SAndroid Build Coastguard Worker   // |session_recv_window_size_| does not change.
2850*6777b538SAndroid Build Coastguard Worker   DecreaseRecvWindowSize(static_cast<int32_t>(len));
2851*6777b538SAndroid Build Coastguard Worker   IncreaseRecvWindowSize(static_cast<int32_t>(len));
2852*6777b538SAndroid Build Coastguard Worker 
2853*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2854*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end())
2855*6777b538SAndroid Build Coastguard Worker     return;
2856*6777b538SAndroid Build Coastguard Worker   it->second->OnPaddingConsumed(len);
2857*6777b538SAndroid Build Coastguard Worker }
2858*6777b538SAndroid Build Coastguard Worker 
OnSettings()2859*6777b538SAndroid Build Coastguard Worker void SpdySession::OnSettings() {
2860*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2861*6777b538SAndroid Build Coastguard Worker 
2862*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS);
2863*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK);
2864*6777b538SAndroid Build Coastguard Worker 
2865*6777b538SAndroid Build Coastguard Worker   if (!settings_frame_received_) {
2866*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts1000(
2867*6777b538SAndroid Build Coastguard Worker         "Net.SpdySession.OnSettings.CreatedStreamCount2",
2868*6777b538SAndroid Build Coastguard Worker         created_streams_.size());
2869*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts1000(
2870*6777b538SAndroid Build Coastguard Worker         "Net.SpdySession.OnSettings.ActiveStreamCount2",
2871*6777b538SAndroid Build Coastguard Worker         active_streams_.size());
2872*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts1000(
2873*6777b538SAndroid Build Coastguard Worker         "Net.SpdySession.OnSettings.CreatedAndActiveStreamCount2",
2874*6777b538SAndroid Build Coastguard Worker         created_streams_.size() + active_streams_.size());
2875*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts1000(
2876*6777b538SAndroid Build Coastguard Worker         "Net.SpdySession.OnSettings.PendingStreamCount2",
2877*6777b538SAndroid Build Coastguard Worker         GetTotalSize(pending_create_stream_queues_));
2878*6777b538SAndroid Build Coastguard Worker   }
2879*6777b538SAndroid Build Coastguard Worker 
2880*6777b538SAndroid Build Coastguard Worker   // Send an acknowledgment of the setting.
2881*6777b538SAndroid Build Coastguard Worker   spdy::SpdySettingsIR settings_ir;
2882*6777b538SAndroid Build Coastguard Worker   settings_ir.set_is_ack(true);
2883*6777b538SAndroid Build Coastguard Worker   auto frame = std::make_unique<spdy::SpdySerializedFrame>(
2884*6777b538SAndroid Build Coastguard Worker       buffered_spdy_framer_->SerializeFrame(settings_ir));
2885*6777b538SAndroid Build Coastguard Worker   EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::SETTINGS, std::move(frame));
2886*6777b538SAndroid Build Coastguard Worker }
2887*6777b538SAndroid Build Coastguard Worker 
OnSettingsAck()2888*6777b538SAndroid Build Coastguard Worker void SpdySession::OnSettingsAck() {
2889*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2890*6777b538SAndroid Build Coastguard Worker 
2891*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK);
2892*6777b538SAndroid Build Coastguard Worker }
2893*6777b538SAndroid Build Coastguard Worker 
OnSetting(spdy::SpdySettingsId id,uint32_t value)2894*6777b538SAndroid Build Coastguard Worker void SpdySession::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
2895*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2896*6777b538SAndroid Build Coastguard Worker 
2897*6777b538SAndroid Build Coastguard Worker   HandleSetting(id, value);
2898*6777b538SAndroid Build Coastguard Worker 
2899*6777b538SAndroid Build Coastguard Worker   // Log the setting.
2900*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTING,
2901*6777b538SAndroid Build Coastguard Worker                     [&] { return NetLogSpdyRecvSettingParams(id, value); });
2902*6777b538SAndroid Build Coastguard Worker }
2903*6777b538SAndroid Build Coastguard Worker 
OnSettingsEnd()2904*6777b538SAndroid Build Coastguard Worker void SpdySession::OnSettingsEnd() {
2905*6777b538SAndroid Build Coastguard Worker   settings_frame_received_ = true;
2906*6777b538SAndroid Build Coastguard Worker }
2907*6777b538SAndroid Build Coastguard Worker 
OnWindowUpdate(spdy::SpdyStreamId stream_id,int delta_window_size)2908*6777b538SAndroid Build Coastguard Worker void SpdySession::OnWindowUpdate(spdy::SpdyStreamId stream_id,
2909*6777b538SAndroid Build Coastguard Worker                                  int delta_window_size) {
2910*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2911*6777b538SAndroid Build Coastguard Worker 
2912*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_WINDOW_UPDATE, [&] {
2913*6777b538SAndroid Build Coastguard Worker     return NetLogSpdyWindowUpdateFrameParams(stream_id, delta_window_size);
2914*6777b538SAndroid Build Coastguard Worker   });
2915*6777b538SAndroid Build Coastguard Worker 
2916*6777b538SAndroid Build Coastguard Worker   if (stream_id == spdy::kSessionFlowControlStreamId) {
2917*6777b538SAndroid Build Coastguard Worker     // WINDOW_UPDATE for the session.
2918*6777b538SAndroid Build Coastguard Worker     if (delta_window_size < 1) {
2919*6777b538SAndroid Build Coastguard Worker       RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
2920*6777b538SAndroid Build Coastguard Worker       DoDrainSession(
2921*6777b538SAndroid Build Coastguard Worker           ERR_HTTP2_PROTOCOL_ERROR,
2922*6777b538SAndroid Build Coastguard Worker           "Received WINDOW_UPDATE with an invalid delta_window_size " +
2923*6777b538SAndroid Build Coastguard Worker               base::NumberToString(delta_window_size));
2924*6777b538SAndroid Build Coastguard Worker       return;
2925*6777b538SAndroid Build Coastguard Worker     }
2926*6777b538SAndroid Build Coastguard Worker 
2927*6777b538SAndroid Build Coastguard Worker     IncreaseSendWindowSize(delta_window_size);
2928*6777b538SAndroid Build Coastguard Worker   } else {
2929*6777b538SAndroid Build Coastguard Worker     // WINDOW_UPDATE for a stream.
2930*6777b538SAndroid Build Coastguard Worker     auto it = active_streams_.find(stream_id);
2931*6777b538SAndroid Build Coastguard Worker 
2932*6777b538SAndroid Build Coastguard Worker     if (it == active_streams_.end()) {
2933*6777b538SAndroid Build Coastguard Worker       // NOTE:  it may just be that the stream was cancelled.
2934*6777b538SAndroid Build Coastguard Worker       LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
2935*6777b538SAndroid Build Coastguard Worker       return;
2936*6777b538SAndroid Build Coastguard Worker     }
2937*6777b538SAndroid Build Coastguard Worker 
2938*6777b538SAndroid Build Coastguard Worker     SpdyStream* stream = it->second;
2939*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(stream->stream_id(), stream_id);
2940*6777b538SAndroid Build Coastguard Worker 
2941*6777b538SAndroid Build Coastguard Worker     if (delta_window_size < 1) {
2942*6777b538SAndroid Build Coastguard Worker       ResetStreamIterator(
2943*6777b538SAndroid Build Coastguard Worker           it, ERR_HTTP2_FLOW_CONTROL_ERROR,
2944*6777b538SAndroid Build Coastguard Worker           "Received WINDOW_UPDATE with an invalid delta_window_size.");
2945*6777b538SAndroid Build Coastguard Worker       return;
2946*6777b538SAndroid Build Coastguard Worker     }
2947*6777b538SAndroid Build Coastguard Worker 
2948*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(it->second->stream_id(), stream_id);
2949*6777b538SAndroid Build Coastguard Worker     it->second->IncreaseSendWindowSize(delta_window_size);
2950*6777b538SAndroid Build Coastguard Worker   }
2951*6777b538SAndroid Build Coastguard Worker }
2952*6777b538SAndroid Build Coastguard Worker 
OnPushPromise(spdy::SpdyStreamId,spdy::SpdyStreamId,spdy::Http2HeaderBlock)2953*6777b538SAndroid Build Coastguard Worker void SpdySession::OnPushPromise(spdy::SpdyStreamId /*stream_id*/,
2954*6777b538SAndroid Build Coastguard Worker                                 spdy::SpdyStreamId /*promised_stream_id*/,
2955*6777b538SAndroid Build Coastguard Worker                                 spdy::Http2HeaderBlock /*headers*/) {
2956*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2957*6777b538SAndroid Build Coastguard Worker   DoDrainSession(ERR_HTTP2_PROTOCOL_ERROR, "PUSH_PROMISE received");
2958*6777b538SAndroid Build Coastguard Worker }
2959*6777b538SAndroid Build Coastguard Worker 
OnHeaders(spdy::SpdyStreamId stream_id,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,bool fin,spdy::Http2HeaderBlock headers,base::TimeTicks recv_first_byte_time)2960*6777b538SAndroid Build Coastguard Worker void SpdySession::OnHeaders(spdy::SpdyStreamId stream_id,
2961*6777b538SAndroid Build Coastguard Worker                             bool has_priority,
2962*6777b538SAndroid Build Coastguard Worker                             int weight,
2963*6777b538SAndroid Build Coastguard Worker                             spdy::SpdyStreamId parent_stream_id,
2964*6777b538SAndroid Build Coastguard Worker                             bool exclusive,
2965*6777b538SAndroid Build Coastguard Worker                             bool fin,
2966*6777b538SAndroid Build Coastguard Worker                             spdy::Http2HeaderBlock headers,
2967*6777b538SAndroid Build Coastguard Worker                             base::TimeTicks recv_first_byte_time) {
2968*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
2969*6777b538SAndroid Build Coastguard Worker 
2970*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS,
2971*6777b538SAndroid Build Coastguard Worker                     [&](NetLogCaptureMode capture_mode) {
2972*6777b538SAndroid Build Coastguard Worker                       return NetLogSpdyHeadersReceivedParams(
2973*6777b538SAndroid Build Coastguard Worker                           &headers, fin, stream_id, capture_mode);
2974*6777b538SAndroid Build Coastguard Worker                     });
2975*6777b538SAndroid Build Coastguard Worker 
2976*6777b538SAndroid Build Coastguard Worker   auto it = active_streams_.find(stream_id);
2977*6777b538SAndroid Build Coastguard Worker   if (it == active_streams_.end()) {
2978*6777b538SAndroid Build Coastguard Worker     // NOTE:  it may just be that the stream was cancelled.
2979*6777b538SAndroid Build Coastguard Worker     LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id;
2980*6777b538SAndroid Build Coastguard Worker     return;
2981*6777b538SAndroid Build Coastguard Worker   }
2982*6777b538SAndroid Build Coastguard Worker 
2983*6777b538SAndroid Build Coastguard Worker   SpdyStream* stream = it->second;
2984*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(stream->stream_id(), stream_id);
2985*6777b538SAndroid Build Coastguard Worker 
2986*6777b538SAndroid Build Coastguard Worker   stream->AddRawReceivedBytes(last_compressed_frame_len_);
2987*6777b538SAndroid Build Coastguard Worker   last_compressed_frame_len_ = 0;
2988*6777b538SAndroid Build Coastguard Worker 
2989*6777b538SAndroid Build Coastguard Worker   base::Time response_time = base::Time::Now();
2990*6777b538SAndroid Build Coastguard Worker   // May invalidate |stream|.
2991*6777b538SAndroid Build Coastguard Worker   stream->OnHeadersReceived(headers, response_time, recv_first_byte_time);
2992*6777b538SAndroid Build Coastguard Worker }
2993*6777b538SAndroid Build Coastguard Worker 
OnAltSvc(spdy::SpdyStreamId stream_id,std::string_view origin,const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & altsvc_vector)2994*6777b538SAndroid Build Coastguard Worker void SpdySession::OnAltSvc(
2995*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id,
2996*6777b538SAndroid Build Coastguard Worker     std::string_view origin,
2997*6777b538SAndroid Build Coastguard Worker     const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
2998*6777b538SAndroid Build Coastguard Worker   url::SchemeHostPort scheme_host_port;
2999*6777b538SAndroid Build Coastguard Worker   if (stream_id == 0) {
3000*6777b538SAndroid Build Coastguard Worker     if (origin.empty())
3001*6777b538SAndroid Build Coastguard Worker       return;
3002*6777b538SAndroid Build Coastguard Worker     const GURL gurl(origin);
3003*6777b538SAndroid Build Coastguard Worker     if (!gurl.is_valid() || gurl.host().empty())
3004*6777b538SAndroid Build Coastguard Worker       return;
3005*6777b538SAndroid Build Coastguard Worker     if (!gurl.SchemeIs(url::kHttpsScheme))
3006*6777b538SAndroid Build Coastguard Worker       return;
3007*6777b538SAndroid Build Coastguard Worker     SSLInfo ssl_info;
3008*6777b538SAndroid Build Coastguard Worker     if (!GetSSLInfo(&ssl_info)) {
3009*6777b538SAndroid Build Coastguard Worker       return;
3010*6777b538SAndroid Build Coastguard Worker     }
3011*6777b538SAndroid Build Coastguard Worker     if (!CanPool(transport_security_state_, ssl_info, *ssl_config_service_,
3012*6777b538SAndroid Build Coastguard Worker                  host_port_pair().host(), gurl.host_piece())) {
3013*6777b538SAndroid Build Coastguard Worker       return;
3014*6777b538SAndroid Build Coastguard Worker     }
3015*6777b538SAndroid Build Coastguard Worker     scheme_host_port = url::SchemeHostPort(gurl);
3016*6777b538SAndroid Build Coastguard Worker   } else {
3017*6777b538SAndroid Build Coastguard Worker     if (!origin.empty())
3018*6777b538SAndroid Build Coastguard Worker       return;
3019*6777b538SAndroid Build Coastguard Worker     const ActiveStreamMap::iterator it = active_streams_.find(stream_id);
3020*6777b538SAndroid Build Coastguard Worker     if (it == active_streams_.end())
3021*6777b538SAndroid Build Coastguard Worker       return;
3022*6777b538SAndroid Build Coastguard Worker     const GURL& gurl(it->second->url());
3023*6777b538SAndroid Build Coastguard Worker     if (!gurl.SchemeIs(url::kHttpsScheme))
3024*6777b538SAndroid Build Coastguard Worker       return;
3025*6777b538SAndroid Build Coastguard Worker     scheme_host_port = url::SchemeHostPort(gurl);
3026*6777b538SAndroid Build Coastguard Worker   }
3027*6777b538SAndroid Build Coastguard Worker 
3028*6777b538SAndroid Build Coastguard Worker   http_server_properties_->SetAlternativeServices(
3029*6777b538SAndroid Build Coastguard Worker       scheme_host_port, spdy_session_key_.network_anonymization_key(),
3030*6777b538SAndroid Build Coastguard Worker       ProcessAlternativeServices(altsvc_vector, is_http2_enabled_,
3031*6777b538SAndroid Build Coastguard Worker                                  is_quic_enabled_, quic_supported_versions_));
3032*6777b538SAndroid Build Coastguard Worker }
3033*6777b538SAndroid Build Coastguard Worker 
OnUnknownFrame(spdy::SpdyStreamId stream_id,uint8_t frame_type)3034*6777b538SAndroid Build Coastguard Worker bool SpdySession::OnUnknownFrame(spdy::SpdyStreamId stream_id,
3035*6777b538SAndroid Build Coastguard Worker                                  uint8_t frame_type) {
3036*6777b538SAndroid Build Coastguard Worker   if (stream_id % 2 == 1) {
3037*6777b538SAndroid Build Coastguard Worker     return stream_id <= stream_hi_water_mark_;
3038*6777b538SAndroid Build Coastguard Worker   } else {
3039*6777b538SAndroid Build Coastguard Worker     // Reject frames on push streams, but not on the control stream.
3040*6777b538SAndroid Build Coastguard Worker     return stream_id == 0;
3041*6777b538SAndroid Build Coastguard Worker   }
3042*6777b538SAndroid Build Coastguard Worker }
3043*6777b538SAndroid Build Coastguard Worker 
OnSendCompressedFrame(spdy::SpdyStreamId stream_id,spdy::SpdyFrameType type,size_t payload_len,size_t frame_len)3044*6777b538SAndroid Build Coastguard Worker void SpdySession::OnSendCompressedFrame(spdy::SpdyStreamId stream_id,
3045*6777b538SAndroid Build Coastguard Worker                                         spdy::SpdyFrameType type,
3046*6777b538SAndroid Build Coastguard Worker                                         size_t payload_len,
3047*6777b538SAndroid Build Coastguard Worker                                         size_t frame_len) {
3048*6777b538SAndroid Build Coastguard Worker   if (type != spdy::SpdyFrameType::HEADERS) {
3049*6777b538SAndroid Build Coastguard Worker     return;
3050*6777b538SAndroid Build Coastguard Worker   }
3051*6777b538SAndroid Build Coastguard Worker 
3052*6777b538SAndroid Build Coastguard Worker   DCHECK(buffered_spdy_framer_.get());
3053*6777b538SAndroid Build Coastguard Worker   size_t compressed_len = frame_len - spdy::kFrameMinimumSize;
3054*6777b538SAndroid Build Coastguard Worker 
3055*6777b538SAndroid Build Coastguard Worker   if (payload_len) {
3056*6777b538SAndroid Build Coastguard Worker     // Make sure we avoid early decimal truncation.
3057*6777b538SAndroid Build Coastguard Worker     int compression_pct = 100 - (100 * compressed_len) / payload_len;
3058*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_PERCENTAGE("Net.SpdyHeadersCompressionPercentage",
3059*6777b538SAndroid Build Coastguard Worker                              compression_pct);
3060*6777b538SAndroid Build Coastguard Worker   }
3061*6777b538SAndroid Build Coastguard Worker }
3062*6777b538SAndroid Build Coastguard Worker 
OnReceiveCompressedFrame(spdy::SpdyStreamId stream_id,spdy::SpdyFrameType type,size_t frame_len)3063*6777b538SAndroid Build Coastguard Worker void SpdySession::OnReceiveCompressedFrame(spdy::SpdyStreamId stream_id,
3064*6777b538SAndroid Build Coastguard Worker                                            spdy::SpdyFrameType type,
3065*6777b538SAndroid Build Coastguard Worker                                            size_t frame_len) {
3066*6777b538SAndroid Build Coastguard Worker   last_compressed_frame_len_ = frame_len;
3067*6777b538SAndroid Build Coastguard Worker }
3068*6777b538SAndroid Build Coastguard Worker 
OnWriteBufferConsumed(size_t frame_payload_size,size_t consume_size,SpdyBuffer::ConsumeSource consume_source)3069*6777b538SAndroid Build Coastguard Worker void SpdySession::OnWriteBufferConsumed(
3070*6777b538SAndroid Build Coastguard Worker     size_t frame_payload_size,
3071*6777b538SAndroid Build Coastguard Worker     size_t consume_size,
3072*6777b538SAndroid Build Coastguard Worker     SpdyBuffer::ConsumeSource consume_source) {
3073*6777b538SAndroid Build Coastguard Worker   // We can be called with |in_io_loop_| set if a write SpdyBuffer is
3074*6777b538SAndroid Build Coastguard Worker   // deleted (e.g., a stream is closed due to incoming data).
3075*6777b538SAndroid Build Coastguard Worker   if (consume_source == SpdyBuffer::DISCARD) {
3076*6777b538SAndroid Build Coastguard Worker     // If we're discarding a frame or part of it, increase the send
3077*6777b538SAndroid Build Coastguard Worker     // window by the number of discarded bytes. (Although if we're
3078*6777b538SAndroid Build Coastguard Worker     // discarding part of a frame, it's probably because of a write
3079*6777b538SAndroid Build Coastguard Worker     // error and we'll be tearing down the session soon.)
3080*6777b538SAndroid Build Coastguard Worker     int remaining_payload_bytes = std::min(consume_size, frame_payload_size);
3081*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(remaining_payload_bytes, 0);
3082*6777b538SAndroid Build Coastguard Worker     IncreaseSendWindowSize(remaining_payload_bytes);
3083*6777b538SAndroid Build Coastguard Worker   }
3084*6777b538SAndroid Build Coastguard Worker   // For consumed bytes, the send window is increased when we receive
3085*6777b538SAndroid Build Coastguard Worker   // a WINDOW_UPDATE frame.
3086*6777b538SAndroid Build Coastguard Worker }
3087*6777b538SAndroid Build Coastguard Worker 
IncreaseSendWindowSize(int delta_window_size)3088*6777b538SAndroid Build Coastguard Worker void SpdySession::IncreaseSendWindowSize(int delta_window_size) {
3089*6777b538SAndroid Build Coastguard Worker   // We can be called with |in_io_loop_| set if a SpdyBuffer is
3090*6777b538SAndroid Build Coastguard Worker   // deleted (e.g., a stream is closed due to incoming data).
3091*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(delta_window_size, 1);
3092*6777b538SAndroid Build Coastguard Worker 
3093*6777b538SAndroid Build Coastguard Worker   // Check for overflow.
3094*6777b538SAndroid Build Coastguard Worker   int32_t max_delta_window_size =
3095*6777b538SAndroid Build Coastguard Worker       std::numeric_limits<int32_t>::max() - session_send_window_size_;
3096*6777b538SAndroid Build Coastguard Worker   if (delta_window_size > max_delta_window_size) {
3097*6777b538SAndroid Build Coastguard Worker     RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
3098*6777b538SAndroid Build Coastguard Worker     DoDrainSession(
3099*6777b538SAndroid Build Coastguard Worker         ERR_HTTP2_PROTOCOL_ERROR,
3100*6777b538SAndroid Build Coastguard Worker         "Received WINDOW_UPDATE [delta: " +
3101*6777b538SAndroid Build Coastguard Worker             base::NumberToString(delta_window_size) +
3102*6777b538SAndroid Build Coastguard Worker             "] for session overflows session_send_window_size_ [current: " +
3103*6777b538SAndroid Build Coastguard Worker             base::NumberToString(session_send_window_size_) + "]");
3104*6777b538SAndroid Build Coastguard Worker     return;
3105*6777b538SAndroid Build Coastguard Worker   }
3106*6777b538SAndroid Build Coastguard Worker 
3107*6777b538SAndroid Build Coastguard Worker   session_send_window_size_ += delta_window_size;
3108*6777b538SAndroid Build Coastguard Worker 
3109*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_SEND_WINDOW, [&] {
3110*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionWindowUpdateParams(delta_window_size,
3111*6777b538SAndroid Build Coastguard Worker                                                session_send_window_size_);
3112*6777b538SAndroid Build Coastguard Worker   });
3113*6777b538SAndroid Build Coastguard Worker 
3114*6777b538SAndroid Build Coastguard Worker   DCHECK(!IsSendStalled());
3115*6777b538SAndroid Build Coastguard Worker   ResumeSendStalledStreams();
3116*6777b538SAndroid Build Coastguard Worker }
3117*6777b538SAndroid Build Coastguard Worker 
DecreaseSendWindowSize(int32_t delta_window_size)3118*6777b538SAndroid Build Coastguard Worker void SpdySession::DecreaseSendWindowSize(int32_t delta_window_size) {
3119*6777b538SAndroid Build Coastguard Worker   // We only call this method when sending a frame. Therefore,
3120*6777b538SAndroid Build Coastguard Worker   // |delta_window_size| should be within the valid frame size range.
3121*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(delta_window_size, 1);
3122*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
3123*6777b538SAndroid Build Coastguard Worker 
3124*6777b538SAndroid Build Coastguard Worker   // |send_window_size_| should have been at least |delta_window_size| for
3125*6777b538SAndroid Build Coastguard Worker   // this call to happen.
3126*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(session_send_window_size_, delta_window_size);
3127*6777b538SAndroid Build Coastguard Worker 
3128*6777b538SAndroid Build Coastguard Worker   session_send_window_size_ -= delta_window_size;
3129*6777b538SAndroid Build Coastguard Worker 
3130*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_SEND_WINDOW, [&] {
3131*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionWindowUpdateParams(-delta_window_size,
3132*6777b538SAndroid Build Coastguard Worker                                                session_send_window_size_);
3133*6777b538SAndroid Build Coastguard Worker   });
3134*6777b538SAndroid Build Coastguard Worker }
3135*6777b538SAndroid Build Coastguard Worker 
OnReadBufferConsumed(size_t consume_size,SpdyBuffer::ConsumeSource consume_source)3136*6777b538SAndroid Build Coastguard Worker void SpdySession::OnReadBufferConsumed(
3137*6777b538SAndroid Build Coastguard Worker     size_t consume_size,
3138*6777b538SAndroid Build Coastguard Worker     SpdyBuffer::ConsumeSource consume_source) {
3139*6777b538SAndroid Build Coastguard Worker   // We can be called with |in_io_loop_| set if a read SpdyBuffer is
3140*6777b538SAndroid Build Coastguard Worker   // deleted (e.g., discarded by a SpdyReadQueue).
3141*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(consume_size, 1u);
3142*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(consume_size,
3143*6777b538SAndroid Build Coastguard Worker             static_cast<size_t>(std::numeric_limits<int32_t>::max()));
3144*6777b538SAndroid Build Coastguard Worker 
3145*6777b538SAndroid Build Coastguard Worker   IncreaseRecvWindowSize(static_cast<int32_t>(consume_size));
3146*6777b538SAndroid Build Coastguard Worker }
3147*6777b538SAndroid Build Coastguard Worker 
IncreaseRecvWindowSize(int32_t delta_window_size)3148*6777b538SAndroid Build Coastguard Worker void SpdySession::IncreaseRecvWindowSize(int32_t delta_window_size) {
3149*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(session_unacked_recv_window_bytes_, 0);
3150*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(session_recv_window_size_, session_unacked_recv_window_bytes_);
3151*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(delta_window_size, 1);
3152*6777b538SAndroid Build Coastguard Worker   // Check for overflow.
3153*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(delta_window_size,
3154*6777b538SAndroid Build Coastguard Worker             std::numeric_limits<int32_t>::max() - session_recv_window_size_);
3155*6777b538SAndroid Build Coastguard Worker 
3156*6777b538SAndroid Build Coastguard Worker   session_recv_window_size_ += delta_window_size;
3157*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_RECV_WINDOW, [&] {
3158*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionWindowUpdateParams(delta_window_size,
3159*6777b538SAndroid Build Coastguard Worker                                                session_recv_window_size_);
3160*6777b538SAndroid Build Coastguard Worker   });
3161*6777b538SAndroid Build Coastguard Worker 
3162*6777b538SAndroid Build Coastguard Worker   // Update the receive window once half of the buffer is ready to be acked
3163*6777b538SAndroid Build Coastguard Worker   // to prevent excessive window updates on fast downloads. Also send an update
3164*6777b538SAndroid Build Coastguard Worker   // if too much time has elapsed since the last update to deal with
3165*6777b538SAndroid Build Coastguard Worker   // slow-reading clients so the server doesn't think the session is idle.
3166*6777b538SAndroid Build Coastguard Worker   session_unacked_recv_window_bytes_ += delta_window_size;
3167*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta elapsed =
3168*6777b538SAndroid Build Coastguard Worker       base::TimeTicks::Now() - last_recv_window_update_;
3169*6777b538SAndroid Build Coastguard Worker   if (session_unacked_recv_window_bytes_ > session_max_recv_window_size_ / 2 ||
3170*6777b538SAndroid Build Coastguard Worker       elapsed >= time_to_buffer_small_window_updates_) {
3171*6777b538SAndroid Build Coastguard Worker     last_recv_window_update_ = base::TimeTicks::Now();
3172*6777b538SAndroid Build Coastguard Worker     SendWindowUpdateFrame(spdy::kSessionFlowControlStreamId,
3173*6777b538SAndroid Build Coastguard Worker                           session_unacked_recv_window_bytes_, HIGHEST);
3174*6777b538SAndroid Build Coastguard Worker     session_unacked_recv_window_bytes_ = 0;
3175*6777b538SAndroid Build Coastguard Worker   }
3176*6777b538SAndroid Build Coastguard Worker }
3177*6777b538SAndroid Build Coastguard Worker 
DecreaseRecvWindowSize(int32_t delta_window_size)3178*6777b538SAndroid Build Coastguard Worker void SpdySession::DecreaseRecvWindowSize(int32_t delta_window_size) {
3179*6777b538SAndroid Build Coastguard Worker   CHECK(in_io_loop_);
3180*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(delta_window_size, 1);
3181*6777b538SAndroid Build Coastguard Worker 
3182*6777b538SAndroid Build Coastguard Worker   // The receiving window size as the peer knows it is
3183*6777b538SAndroid Build Coastguard Worker   // |session_recv_window_size_ - session_unacked_recv_window_bytes_|, if more
3184*6777b538SAndroid Build Coastguard Worker   // data are sent by the peer, that means that the receive window is not being
3185*6777b538SAndroid Build Coastguard Worker   // respected.
3186*6777b538SAndroid Build Coastguard Worker   int32_t receiving_window_size =
3187*6777b538SAndroid Build Coastguard Worker       session_recv_window_size_ - session_unacked_recv_window_bytes_;
3188*6777b538SAndroid Build Coastguard Worker   if (delta_window_size > receiving_window_size) {
3189*6777b538SAndroid Build Coastguard Worker     RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION);
3190*6777b538SAndroid Build Coastguard Worker     DoDrainSession(
3191*6777b538SAndroid Build Coastguard Worker         ERR_HTTP2_FLOW_CONTROL_ERROR,
3192*6777b538SAndroid Build Coastguard Worker         "delta_window_size is " + base::NumberToString(delta_window_size) +
3193*6777b538SAndroid Build Coastguard Worker             " in DecreaseRecvWindowSize, which is larger than the receive " +
3194*6777b538SAndroid Build Coastguard Worker             "window size of " + base::NumberToString(receiving_window_size));
3195*6777b538SAndroid Build Coastguard Worker     return;
3196*6777b538SAndroid Build Coastguard Worker   }
3197*6777b538SAndroid Build Coastguard Worker 
3198*6777b538SAndroid Build Coastguard Worker   session_recv_window_size_ -= delta_window_size;
3199*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_RECV_WINDOW, [&] {
3200*6777b538SAndroid Build Coastguard Worker     return NetLogSpdySessionWindowUpdateParams(-delta_window_size,
3201*6777b538SAndroid Build Coastguard Worker                                                session_recv_window_size_);
3202*6777b538SAndroid Build Coastguard Worker   });
3203*6777b538SAndroid Build Coastguard Worker }
3204*6777b538SAndroid Build Coastguard Worker 
QueueSendStalledStream(const SpdyStream & stream)3205*6777b538SAndroid Build Coastguard Worker void SpdySession::QueueSendStalledStream(const SpdyStream& stream) {
3206*6777b538SAndroid Build Coastguard Worker   DCHECK(stream.send_stalled_by_flow_control() || IsSendStalled());
3207*6777b538SAndroid Build Coastguard Worker   RequestPriority priority = stream.priority();
3208*6777b538SAndroid Build Coastguard Worker   CHECK_GE(priority, MINIMUM_PRIORITY);
3209*6777b538SAndroid Build Coastguard Worker   CHECK_LE(priority, MAXIMUM_PRIORITY);
3210*6777b538SAndroid Build Coastguard Worker   stream_send_unstall_queue_[priority].push_back(stream.stream_id());
3211*6777b538SAndroid Build Coastguard Worker }
3212*6777b538SAndroid Build Coastguard Worker 
ResumeSendStalledStreams()3213*6777b538SAndroid Build Coastguard Worker void SpdySession::ResumeSendStalledStreams() {
3214*6777b538SAndroid Build Coastguard Worker   // We don't have to worry about new streams being queued, since
3215*6777b538SAndroid Build Coastguard Worker   // doing so would cause IsSendStalled() to return true. But we do
3216*6777b538SAndroid Build Coastguard Worker   // have to worry about streams being closed, as well as ourselves
3217*6777b538SAndroid Build Coastguard Worker   // being closed.
3218*6777b538SAndroid Build Coastguard Worker 
3219*6777b538SAndroid Build Coastguard Worker   base::circular_deque<SpdyStream*> streams_to_requeue;
3220*6777b538SAndroid Build Coastguard Worker 
3221*6777b538SAndroid Build Coastguard Worker   while (!IsSendStalled()) {
3222*6777b538SAndroid Build Coastguard Worker     size_t old_size = 0;
3223*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
3224*6777b538SAndroid Build Coastguard Worker     old_size = GetTotalSize(stream_send_unstall_queue_);
3225*6777b538SAndroid Build Coastguard Worker #endif
3226*6777b538SAndroid Build Coastguard Worker 
3227*6777b538SAndroid Build Coastguard Worker     spdy::SpdyStreamId stream_id = PopStreamToPossiblyResume();
3228*6777b538SAndroid Build Coastguard Worker     if (stream_id == 0)
3229*6777b538SAndroid Build Coastguard Worker       break;
3230*6777b538SAndroid Build Coastguard Worker     ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
3231*6777b538SAndroid Build Coastguard Worker     // The stream may actually still be send-stalled after this (due
3232*6777b538SAndroid Build Coastguard Worker     // to its own send window) but that's okay -- it'll then be
3233*6777b538SAndroid Build Coastguard Worker     // resumed once its send window increases.
3234*6777b538SAndroid Build Coastguard Worker     if (it != active_streams_.end()) {
3235*6777b538SAndroid Build Coastguard Worker       if (it->second->PossiblyResumeIfSendStalled() == SpdyStream::Requeue)
3236*6777b538SAndroid Build Coastguard Worker         streams_to_requeue.push_back(it->second);
3237*6777b538SAndroid Build Coastguard Worker     }
3238*6777b538SAndroid Build Coastguard Worker 
3239*6777b538SAndroid Build Coastguard Worker     // The size should decrease unless we got send-stalled again.
3240*6777b538SAndroid Build Coastguard Worker     if (!IsSendStalled())
3241*6777b538SAndroid Build Coastguard Worker       DCHECK_LT(GetTotalSize(stream_send_unstall_queue_), old_size);
3242*6777b538SAndroid Build Coastguard Worker   }
3243*6777b538SAndroid Build Coastguard Worker   while (!streams_to_requeue.empty()) {
3244*6777b538SAndroid Build Coastguard Worker     SpdyStream* stream = streams_to_requeue.front();
3245*6777b538SAndroid Build Coastguard Worker     streams_to_requeue.pop_front();
3246*6777b538SAndroid Build Coastguard Worker     QueueSendStalledStream(*stream);
3247*6777b538SAndroid Build Coastguard Worker   }
3248*6777b538SAndroid Build Coastguard Worker }
3249*6777b538SAndroid Build Coastguard Worker 
PopStreamToPossiblyResume()3250*6777b538SAndroid Build Coastguard Worker spdy::SpdyStreamId SpdySession::PopStreamToPossiblyResume() {
3251*6777b538SAndroid Build Coastguard Worker   for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
3252*6777b538SAndroid Build Coastguard Worker     base::circular_deque<spdy::SpdyStreamId>* queue =
3253*6777b538SAndroid Build Coastguard Worker         &stream_send_unstall_queue_[i];
3254*6777b538SAndroid Build Coastguard Worker     if (!queue->empty()) {
3255*6777b538SAndroid Build Coastguard Worker       spdy::SpdyStreamId stream_id = queue->front();
3256*6777b538SAndroid Build Coastguard Worker       queue->pop_front();
3257*6777b538SAndroid Build Coastguard Worker       return stream_id;
3258*6777b538SAndroid Build Coastguard Worker     }
3259*6777b538SAndroid Build Coastguard Worker   }
3260*6777b538SAndroid Build Coastguard Worker   return 0;
3261*6777b538SAndroid Build Coastguard Worker }
3262*6777b538SAndroid Build Coastguard Worker 
CheckConnectionStatus()3263*6777b538SAndroid Build Coastguard Worker void SpdySession::CheckConnectionStatus() {
3264*6777b538SAndroid Build Coastguard Worker   MaybeSendPrefacePing();
3265*6777b538SAndroid Build Coastguard Worker   // Also schedule the next check.
3266*6777b538SAndroid Build Coastguard Worker   heartbeat_timer_.Start(
3267*6777b538SAndroid Build Coastguard Worker       FROM_HERE, heartbeat_interval_,
3268*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&SpdySession::MaybeCheckConnectionStatus,
3269*6777b538SAndroid Build Coastguard Worker                      weak_factory_.GetWeakPtr()));
3270*6777b538SAndroid Build Coastguard Worker }
3271*6777b538SAndroid Build Coastguard Worker 
OnDefaultNetworkActive()3272*6777b538SAndroid Build Coastguard Worker void SpdySession::OnDefaultNetworkActive() {
3273*6777b538SAndroid Build Coastguard Worker   if (!check_connection_on_radio_wakeup_)
3274*6777b538SAndroid Build Coastguard Worker     return;
3275*6777b538SAndroid Build Coastguard Worker 
3276*6777b538SAndroid Build Coastguard Worker   check_connection_on_radio_wakeup_ = false;
3277*6777b538SAndroid Build Coastguard Worker   CheckConnectionStatus();
3278*6777b538SAndroid Build Coastguard Worker }
3279*6777b538SAndroid Build Coastguard Worker 
MaybeDisableBrokenConnectionDetection()3280*6777b538SAndroid Build Coastguard Worker void SpdySession::MaybeDisableBrokenConnectionDetection() {
3281*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(broken_connection_detection_requests_, 0);
3282*6777b538SAndroid Build Coastguard Worker   DCHECK(IsBrokenConnectionDetectionEnabled());
3283*6777b538SAndroid Build Coastguard Worker   if (--broken_connection_detection_requests_ > 0)
3284*6777b538SAndroid Build Coastguard Worker     return;
3285*6777b538SAndroid Build Coastguard Worker 
3286*6777b538SAndroid Build Coastguard Worker   heartbeat_timer_.Stop();
3287*6777b538SAndroid Build Coastguard Worker   NetworkChangeNotifier::RemoveDefaultNetworkActiveObserver(this);
3288*6777b538SAndroid Build Coastguard Worker   check_connection_on_radio_wakeup_ = false;
3289*6777b538SAndroid Build Coastguard Worker }
3290*6777b538SAndroid Build Coastguard Worker 
3291*6777b538SAndroid Build Coastguard Worker }  // namespace net
3292