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