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