15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_session.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/field_trial.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/sparse_histogram.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/stats_counters.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_number_conversions.h"
215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
225e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/ec_private_key.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/ec_signature_creator.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/connection_type_histograms.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/asn1_util.h"
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "net/cert/cert_verify_result.h"
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "net/http/http_log_util.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_server_properties.h"
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "net/http/http_util.h"
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "net/http/transport_security_state.h"
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/socket/ssl_client_socket.h"
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/spdy/spdy_buffer_producer.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_frame_builder.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_http_utils.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_protocol.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_session_pool.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_stream.h"
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/ssl/channel_id_service.h"
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/ssl/ssl_cipher_suite_names.h"
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/ssl/ssl_connection_status_flags.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kReadBufferSize = 8 * 1024;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultConnectionAtRiskOfLossSeconds = 10;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kHungIntervalSeconds = 10;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minimum seconds that unclaimed pushed streams will be kept in memory.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinPushedStreamLifetimeSeconds = 300;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue(
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const SpdyHeaderBlock& headers,
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    net::NetLog::LogLevel log_level) {
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<base::ListValue> headers_list(new base::ListValue());
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (SpdyHeaderBlock::const_iterator it = headers.begin();
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)       it != headers.end(); ++it) {
668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    headers_list->AppendString(
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        it->first + ": " +
6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ElideHeaderValueForNetLog(log_level, it->first, it->second));
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return headers_list.Pass();
718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)base::Value* NetLogSpdySynStreamSentCallback(const SpdyHeaderBlock* headers,
748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                             bool fin,
758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                             bool unidirectional,
768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                             SpdyPriority spdy_priority,
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                             SpdyStreamId stream_id,
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                             NetLog::LogLevel log_level) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  dict->Set("headers",
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            SpdyHeaderBlockToListValue(*headers, log_level).release());
828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetBoolean("fin", fin);
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetBoolean("unidirectional", unidirectional);
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetInteger("spdy_priority", static_cast<int>(spdy_priority));
858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetInteger("stream_id", stream_id);
868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return dict;
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)base::Value* NetLogSpdySynStreamReceivedCallback(
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const SpdyHeaderBlock* headers,
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool fin,
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool unidirectional,
938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    SpdyPriority spdy_priority,
948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    SpdyStreamId stream_id,
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    SpdyStreamId associated_stream,
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    NetLog::LogLevel log_level) {
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  dict->Set("headers",
9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            SpdyHeaderBlockToListValue(*headers, log_level).release());
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("fin", fin);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("unidirectional", unidirectional);
1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetInteger("spdy_priority", static_cast<int>(spdy_priority));
1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetInteger("stream_id", stream_id);
1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetInteger("associated_stream", associated_stream);
1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return dict;
1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)base::Value* NetLogSpdySynReplyOrHeadersReceivedCallback(
1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const SpdyHeaderBlock* headers,
1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    bool fin,
1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    SpdyStreamId stream_id,
11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    NetLog::LogLevel log_level) {
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  dict->Set("headers",
11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            SpdyHeaderBlockToListValue(*headers, log_level).release());
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  dict->SetBoolean("fin", fin);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", stream_id);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionCloseCallback(int net_error,
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const std::string* description,
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            NetLog::LogLevel /* log_level */) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("net_error", net_error);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("description", *description);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionCallback(const HostPortProxyPair* host_pair,
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NetLog::LogLevel /* log_level */) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("host", host_pair->first.ToString());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("proxy", host_pair->second.ToPacString());
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibase::Value* NetLogSpdyInitializedCallback(NetLog::Source source,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           const NextProto protocol_version,
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           NetLog::LogLevel /* log_level */) {
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::DictionaryValue* dict = new base::DictionaryValue();
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (source.IsValid()) {
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    source.AddToEventParameters(dict);
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  dict->SetString("protocol",
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  SSLClientSocket::NextProtoToString(protocol_version));
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return dict;
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::Value* NetLogSpdySettingsCallback(const HostPortPair& host_port_pair,
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        bool clear_persisted,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        NetLog::LogLevel /* log_level */) {
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetString("host", host_port_pair.ToString());
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetBoolean("clear_persisted", clear_persisted);
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return dict;
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySettingCallback(SpdySettingsIds id,
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       const SpdyMajorVersion protocol_version,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       SpdySettingsFlags flags,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       uint32 value,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NetLog::LogLevel /* log_level */) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  dict->SetInteger("id",
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   SpdyConstants::SerializeSettingId(protocol_version, id));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("flags", flags);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("value", value);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibase::Value* NetLogSpdySendSettingsCallback(
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const SettingsMap* settings,
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const SpdyMajorVersion protocol_version,
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NetLog::LogLevel /* log_level */) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* settings_list = new base::ListValue();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SettingsMap::const_iterator it = settings->begin();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != settings->end(); ++it) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SpdySettingsIds id = it->first;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SpdySettingsFlags flags = it->second.first;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32 value = it->second.second;
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    settings_list->Append(new base::StringValue(base::StringPrintf(
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "[id:%u flags:%u value:%u]",
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        SpdyConstants::SerializeSettingId(protocol_version, id),
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        flags,
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        value)));
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set("settings", settings_list);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyWindowUpdateFrameCallback(
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpdyStreamId stream_id,
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 delta,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NetLog::LogLevel /* log_level */) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("delta", delta);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionWindowUpdateCallback(
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int32 delta,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int32 window_size,
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NetLog::LogLevel /* log_level */) {
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* dict = new base::DictionaryValue();
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("delta", delta);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("window_size", window_size);
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return dict;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyDataCallback(SpdyStreamId stream_id,
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    int size,
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bool fin,
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    NetLog::LogLevel /* log_level */) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("size", size);
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetBoolean("fin", fin);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyRstCallback(SpdyStreamId stream_id,
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   int status,
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const std::string* description,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   NetLog::LogLevel /* log_level */) {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("status", status);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("description", *description);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* NetLogSpdyPingCallback(SpdyPingId unique_id,
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    bool is_ack,
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    const char* type,
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    NetLog::LogLevel /* log_level */) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unique_id", unique_id);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("type", type);
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dict->SetBoolean("is_ack", is_ack);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyGoAwayCallback(SpdyStreamId last_stream_id,
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      int active_streams,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      int unclaimed_streams,
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      SpdyGoAwayStatus status,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      NetLog::LogLevel /* log_level */) {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("last_accepted_stream_id",
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   static_cast<int>(last_stream_id));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("active_streams", active_streams);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unclaimed_streams", unclaimed_streams);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("status", static_cast<int>(status));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)base::Value* NetLogSpdyPushPromiseReceivedCallback(
2616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const SpdyHeaderBlock* headers,
2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SpdyStreamId stream_id,
2636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SpdyStreamId promised_stream_id,
2646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    NetLog::LogLevel log_level) {
2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dict->Set("headers",
2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            SpdyHeaderBlockToListValue(*headers, log_level).release());
2686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dict->SetInteger("id", stream_id);
2696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  dict->SetInteger("promised_stream_id", promised_stream_id);
2706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return dict;
2716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
2726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Helper function to return the total size of an array of objects
2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// with .size() member functions.
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  size_t total_size = 0;
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (size_t i = 0; i < N; ++i) {
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    total_size += arr[i].size();
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return total_size;
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Helper class for std:find_if on STL container containing
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// SpdyStreamRequest weak pointers.
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class RequestEquals {
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  RequestEquals(const base::WeakPtr<SpdyStreamRequest>& request)
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : request_(request) {}
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool operator()(const base::WeakPtr<SpdyStreamRequest>& request) const {
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return request_.get() == request.get();
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const base::WeakPtr<SpdyStreamRequest> request_;
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of concurrent streams we will ever create.  Even if
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the server permits more, we will never exceed this limit.
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxConcurrentStreamLimit = 256;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SpdyProtocolErrorDetails MapFramerErrorToProtocolError(
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SpdyFramer::SpdyError err) {
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch(err) {
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_NO_ERROR:
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_NO_ERROR;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_CONTROL_FRAME:
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_INVALID_CONTROL_FRAME;
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE:
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_CONTROL_PAYLOAD_TOO_LARGE;
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_ZLIB_INIT_FAILURE:
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_ZLIB_INIT_FAILURE;
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_UNSUPPORTED_VERSION:
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_UNSUPPORTED_VERSION;
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_DECOMPRESS_FAILURE:
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_DECOMPRESS_FAILURE;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_COMPRESS_FAILURE:
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_COMPRESS_FAILURE;
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT:
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_GOAWAY_FRAME_CORRUPT;
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_RST_STREAM_FRAME_CORRUPT:
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_RST_STREAM_FRAME_CORRUPT;
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS:
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_INVALID_DATA_FRAME_FLAGS;
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS:
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return SPDY_ERROR_INVALID_CONTROL_FRAME_FLAGS;
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case SpdyFramer::SPDY_UNEXPECTED_FRAME:
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return SPDY_ERROR_UNEXPECTED_FRAME;
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED();
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return static_cast<SpdyProtocolErrorDetails>(-1);
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error MapFramerErrorToNetError(SpdyFramer::SpdyError err) {
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (err) {
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_NO_ERROR:
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return OK;
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_CONTROL_FRAME:
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE:
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_FRAME_SIZE_ERROR;
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_ZLIB_INIT_FAILURE:
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_COMPRESSION_ERROR;
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_UNSUPPORTED_VERSION:
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_DECOMPRESS_FAILURE:
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_COMPRESSION_ERROR;
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_COMPRESS_FAILURE:
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_COMPRESSION_ERROR;
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT:
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_RST_STREAM_FRAME_CORRUPT:
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS:
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS:
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case SpdyFramer::SPDY_UNEXPECTED_FRAME:
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      NOTREACHED();
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return ERR_SPDY_PROTOCOL_ERROR;
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SpdyProtocolErrorDetails MapRstStreamStatusToProtocolError(
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SpdyRstStreamStatus status) {
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch(status) {
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_PROTOCOL_ERROR:
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_PROTOCOL_ERROR;
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_INVALID_STREAM:
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_INVALID_STREAM;
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_REFUSED_STREAM:
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_REFUSED_STREAM;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_UNSUPPORTED_VERSION:
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_UNSUPPORTED_VERSION;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_CANCEL:
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_CANCEL;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_INTERNAL_ERROR:
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_INTERNAL_ERROR;
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_FLOW_CONTROL_ERROR:
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_FLOW_CONTROL_ERROR;
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_STREAM_IN_USE:
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_STREAM_IN_USE;
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_STREAM_ALREADY_CLOSED:
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_STREAM_ALREADY_CLOSED;
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case RST_STREAM_INVALID_CREDENTIALS:
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return STATUS_CODE_INVALID_CREDENTIALS;
3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case RST_STREAM_FRAME_SIZE_ERROR:
3935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return STATUS_CODE_FRAME_SIZE_ERROR;
3945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case RST_STREAM_SETTINGS_TIMEOUT:
3955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return STATUS_CODE_SETTINGS_TIMEOUT;
3965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case RST_STREAM_CONNECT_ERROR:
3975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return STATUS_CODE_CONNECT_ERROR;
3985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case RST_STREAM_ENHANCE_YOUR_CALM:
3995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return STATUS_CODE_ENHANCE_YOUR_CALM;
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED();
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return static_cast<SpdyProtocolErrorDetails>(-1);
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
406f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SpdyGoAwayStatus MapNetErrorToGoAwayStatus(Error err) {
407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (err) {
408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case OK:
409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_NO_ERROR;
410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case ERR_SPDY_PROTOCOL_ERROR:
411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_PROTOCOL_ERROR;
412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case ERR_SPDY_FLOW_CONTROL_ERROR:
413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_FLOW_CONTROL_ERROR;
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case ERR_SPDY_FRAME_SIZE_ERROR:
415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_FRAME_SIZE_ERROR;
416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case ERR_SPDY_COMPRESSION_ERROR:
417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_COMPRESSION_ERROR;
418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY:
419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_INADEQUATE_SECURITY;
420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return GOAWAY_PROTOCOL_ERROR;
422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
424f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
425f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SplitPushedHeadersToRequestAndResponse(const SpdyHeaderBlock& headers,
426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            SpdyMajorVersion protocol_version,
427f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            SpdyHeaderBlock* request_headers,
428f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            SpdyHeaderBlock* response_headers) {
429f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(response_headers);
430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(request_headers);
431f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (SpdyHeaderBlock::const_iterator it = headers.begin();
432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       it != headers.end();
433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       ++it) {
434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SpdyHeaderBlock* to_insert = response_headers;
435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (protocol_version == SPDY2) {
436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (it->first == "url")
437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        to_insert = request_headers;
438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const char* host = protocol_version >= SPDY4 ? ":authority" : ":host";
440f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      static const char* scheme = ":scheme";
441f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      static const char* path = ":path";
442f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (it->first == host || it->first == scheme || it->first == path)
443f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        to_insert = request_headers;
444f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
445f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    to_insert->insert(*it);
446f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
447f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
448f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)SpdyStreamRequest::SpdyStreamRequest() : weak_ptr_factory_(this) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpdyStreamRequest::~SpdyStreamRequest() {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CancelRequest();
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdyStreamRequest::StartRequest(
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SpdyStreamType type,
459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::WeakPtr<SpdySession>& session,
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url,
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RequestPriority priority,
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BoundNetLog& net_log,
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const CompletionCallback& callback) {
4643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session);
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!session_);
4663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(callback_.is_null());
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  type_ = type;
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  session_ = session;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url_ = url;
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  priority_ = priority;
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_ = net_log;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_ = callback;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
476a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream;
4773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int rv = session->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv == OK) {
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Reset();
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = stream;
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return rv;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdyStreamRequest::CancelRequest() {
4863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (session_)
4873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    session_->CancelStreamRequest(weak_ptr_factory_.GetWeakPtr());
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Do this to cancel any pending CompleteStreamRequest() tasks.
4903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
493a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() {
4943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!session_);
495a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream = stream_;
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(stream);
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return stream;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
501a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdyStreamRequest::OnRequestCompleteSuccess(
5023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream) {
5033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session_);
5043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
505a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(!callback_.is_null());
506a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CompletionCallback callback = callback_;
507a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Reset();
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(stream);
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  stream_ = stream;
510a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  callback.Run(OK);
511a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
512a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
513a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdyStreamRequest::OnRequestCompleteFailure(int rv) {
5143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session_);
5153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_.is_null());
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CompletionCallback callback = callback_;
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
519a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK_NE(rv, OK);
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(rv);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdyStreamRequest::Reset() {
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  type_ = SPDY_BIDIRECTIONAL_STREAM;
525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  session_.reset();
526a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream_.reset();
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url_ = GURL();
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  priority_ = MINIMUM_PRIORITY;
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_ = BoundNetLog();
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_.Reset();
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::ActiveStreamInfo()
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream(NULL),
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      waiting_for_syn_reply(false) {}
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream)
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream(stream),
5396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {
5406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::~ActiveStreamInfo() {}
543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {}
545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::PushedStreamInfo(
547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStreamId stream_id,
548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::TimeTicks creation_time)
549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream_id(stream_id),
550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      creation_time(creation_time) {}
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::~PushedStreamInfo() {}
553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
55403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// static
55503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
55603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                          const SSLInfo& ssl_info,
55703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                          const std::string& old_hostname,
55803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                          const std::string& new_hostname) {
55903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Pooling is prohibited if the server cert is not valid for the new domain,
56003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // and for connections on which client certs were sent. It is also prohibited
56103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // when channel ID was sent if the hosts are from different eTLDs+1.
56203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsCertStatusError(ssl_info.cert_status))
56303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
56403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
56503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ssl_info.client_cert_sent)
56603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
56703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
56803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ssl_info.channel_id_sent &&
56903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ChannelIDService::GetDomainForHost(new_hostname) !=
57003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ChannelIDService::GetDomainForHost(old_hostname)) {
57103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
57203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
57303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
57403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool unused = false;
57503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!ssl_info.cert->VerifyNameMatch(new_hostname, &unused))
57603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
57703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
57803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string pinning_failure_log;
57903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!transport_security_state->CheckPublicKeyPins(
58003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          new_hostname,
58103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          ssl_info.is_issued_by_known_root,
58203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          ssl_info.public_key_hashes,
58303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          &pinning_failure_log)) {
58403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
58503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
58603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
58703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
58803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
58903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
590ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochSpdySession::SpdySession(
591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const SpdySessionKey& spdy_session_key,
592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::WeakPtr<HttpServerProperties>& http_server_properties,
59303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    TransportSecurityState* transport_security_state,
594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool verify_domain_authentication,
595a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bool enable_sending_initial_data,
596ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool enable_compression,
597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool enable_ping_based_connection_checking,
598ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NextProto default_protocol,
599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t stream_initial_recv_window_size,
600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t initial_max_concurrent_streams,
601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t max_concurrent_streams_limit,
602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    TimeFunc time_func,
603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const HostPortPair& trusted_spdy_proxy,
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NetLog* net_log)
605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : in_io_loop_(false),
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      spdy_session_key_(spdy_session_key),
607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pool_(NULL),
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_server_properties_(http_server_properties),
60903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      transport_security_state_(transport_security_state),
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_buffer_(new IOBuffer(kReadBufferSize)),
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_hi_water_mark_(kFirstStreamId),
6121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      last_accepted_push_stream_id_(0),
613116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      num_pushed_streams_(0u),
614116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      num_active_pushed_streams_(0u),
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_type_(DATA),
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_size_(0),
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_secure_(false),
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      certificate_error_code_(OK),
619ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      availability_state_(STATE_AVAILABLE),
620ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      read_state_(READ_STATE_DO_READ),
621ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_state_(WRITE_STATE_IDLE),
622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      error_on_close_(OK),
6236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      max_concurrent_streams_(initial_max_concurrent_streams == 0
6246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                  ? kInitialMaxConcurrentStreams
6256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                  : initial_max_concurrent_streams),
6266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      max_concurrent_streams_limit_(max_concurrent_streams_limit == 0
6276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                        ? kMaxConcurrentStreamLimit
6286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                        : max_concurrent_streams_limit),
629116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      max_concurrent_pushed_streams_(kMaxConcurrentPushedStreams),
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_initiated_count_(0),
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_count_(0),
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_and_claimed_count_(0),
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_abandoned_count_(0),
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      total_bytes_received_(0),
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sent_settings_(false),
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      received_settings_(false),
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stalled_streams_(0),
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pings_in_flight_(0),
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_ping_id_(1),
640ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      last_activity_time_(time_func()),
641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      last_compressed_frame_len_(0),
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      check_ping_status_pending_(false),
643a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      send_connection_header_prefix_(false),
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      flow_control_state_(FLOW_CONTROL_NONE),
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_initial_send_window_size_(kSpdyStreamInitialWindowSize),
6466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      stream_initial_recv_window_size_(stream_initial_recv_window_size == 0
6476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                           ? kDefaultInitialRecvWindowSize
6486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                           : stream_initial_recv_window_size),
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_send_window_size_(0),
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_recv_window_size_(0),
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_unacked_recv_window_bytes_(0),
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verify_domain_authentication_(verify_domain_authentication),
654a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      enable_sending_initial_data_(enable_sending_initial_data),
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_compression_(enable_compression),
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_ping_based_connection_checking_(
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          enable_ping_based_connection_checking),
658558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      protocol_(default_protocol),
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection_at_risk_of_loss_time_(
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
6616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      trusted_spdy_proxy_(trusted_spdy_proxy),
663cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      time_func_(time_func),
664cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      weak_factory_(this) {
6654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
666558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(HttpStreamFactory::spdy_enabled());
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.BeginEvent(
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION,
67090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  next_unclaimed_push_stream_sweep_time_ = time_func_() +
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdySession::~SpdySession() {
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DcheckDraining();
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(akalin): Check connection->is_initialized() instead. This
6817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // requires re-working CreateFakeSpdySession(), though.
6827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(connection_->socket());
6837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // With SPDY we can't recycle sockets.
6847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  connection_->socket()->Disconnect();
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordHistograms();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION);
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
691effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid SpdySession::InitializeWithSocket(
6927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_ptr<ClientSocketHandle> connection,
693ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    SpdySessionPool* pool,
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_secure,
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int certificate_error_code) {
696ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
697ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(availability_state_, STATE_AVAILABLE);
698ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(read_state_, READ_STATE_DO_READ);
699ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, WRITE_STATE_IDLE);
7007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!connection_);
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(certificate_error_code == OK ||
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch         certificate_error_code < ERR_IO_PENDING);
7047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(akalin): Check connection->is_initialized() instead. This
7057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // requires re-working CreateFakeSpdySession(), though.
7067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(connection->socket());
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter spdy_sessions("spdy.sessions");
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_sessions.Increment();
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  connection_ = connection.Pass();
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_secure_ = is_secure;
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  certificate_error_code_ = certificate_error_code;
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NextProto protocol_negotiated =
7167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      connection_->socket()->GetNegotiatedProtocol();
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol_negotiated != kProtoUnknown) {
718558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    protocol_ = protocol_negotiated;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
721558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
723a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (protocol_ == kProtoSPDY4)
724a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    send_connection_header_prefix_ = true;
725a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
726558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (protocol_ >= kProtoSPDY31) {
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_STREAM_AND_SESSION;
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    session_send_window_size_ = kSpdySessionInitialWindowSize;
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    session_recv_window_size_ = kSpdySessionInitialWindowSize;
730558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  } else if (protocol_ >= kProtoSPDY3) {
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_STREAM;
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_NONE;
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
736c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  buffered_spdy_framer_.reset(
737558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new BufferedSpdyFramer(NextProtoToSpdyMajorVersion(protocol_),
738558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                             enable_compression_));
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffered_spdy_framer_->set_visitor(this);
7407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  buffered_spdy_framer_->set_debug_visitor(this);
7411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_ENUMERATION(
7421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      "Net.SpdyVersion2",
7431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      protocol_ - kProtoSPDYMinimumVersion,
7441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      kProtoSPDYMaximumVersion - kProtoSPDYMinimumVersion + 1);
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_INITIALIZED,
7471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    base::Bind(&NetLogSpdyInitializedCallback,
7481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               connection_->socket()->NetLog().source(),
7491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               protocol_));
750c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_EQ(availability_state_, STATE_AVAILABLE);
752effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  connection_->AddHigherLayeredPool(this);
753effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (enable_sending_initial_data_)
754effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SendInitialData();
755effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  pool_ = pool;
756effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
757effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Bootstrap the read loop.
758effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::MessageLoop::current()->PostTask(
759effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
760effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&SpdySession::PumpReadLoop,
761effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!verify_domain_authentication_)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
768cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLInfo ssl_info;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_npn_negotiated;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NextProto protocol_negotiated = kProtoUnknown;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;   // This is not a secure session, so all domains are okay.
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return CanPool(transport_security_state_, ssl_info,
77803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 host_port_pair().host(), domain);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetPushStream(
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
783a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::WeakPtr<SpdyStream>* stream,
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& stream_net_log) {
785ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
787a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream->reset();
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
789cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING)
790ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
792ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(url);
793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK)
794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  *stream = GetActivePushStream(url);
797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (*stream) {
798ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_);
799ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    streams_pushed_and_claimed_count_++;
800ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
801ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return OK;
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
803ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
804bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// {,Try}CreateStream() and TryAccessStream() can be called with
805bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// |in_io_loop_| set if a stream is being created in response to
806bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// another being closed due to received data.
807bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochError SpdySession::TryAccessStream(const GURL& url) {
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_secure_ && certificate_error_code_ != OK &&
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (url.SchemeIs("https") || url.SchemeIs("wss"))) {
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
813cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(
814c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_cast<Error>(certificate_error_code_),
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Tried to get SPDY stream for secure content over an unauthenticated "
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "session.");
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_SPDY_PROTOCOL_ERROR;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return OK;
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)int SpdySession::TryCreateStream(
8233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& request,
8243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStream>* stream) {
8253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(request);
826ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
827ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_GOING_AWAY)
828ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_FAILED;
829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
830cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING)
831ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
832ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
833ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(request->url());
834ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK)
835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
8367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!max_concurrent_streams_ ||
838116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      (active_streams_.size() + created_streams_.size() - num_pushed_streams_ <
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       max_concurrent_streams_)) {
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateStream(*request, stream);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stalled_streams_++;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS);
8458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  RequestPriority priority = request->priority();
8468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_GE(priority, MINIMUM_PRIORITY);
8478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_LE(priority, MAXIMUM_PRIORITY);
8488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  pending_create_stream_queues_[priority].push_back(request);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERR_IO_PENDING;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::CreateStream(const SpdyStreamRequest& request,
853a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                              base::WeakPtr<SpdyStream>* stream) {
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
8558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_LE(request.priority(), MAXIMUM_PRIORITY);
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
857ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_GOING_AWAY)
858ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_FAILED;
859ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
860cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING)
861ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
862ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
863ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(request.url());
864ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK) {
865ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // This should have been caught in TryCreateStream().
866ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NOTREACHED();
867ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(connection_->socket());
871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(connection_->socket()->IsConnected());
872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected",
874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          connection_->socket()->IsConnected());
875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!connection_->socket()->IsConnected()) {
876cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DoDrainSession(
877c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ERR_CONNECTION_CLOSED,
878c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          "Tried to create SPDY stream for a closed socket connection.");
879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return ERR_CONNECTION_CLOSED;
880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
881c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
883a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SpdyStream> new_stream(
884ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      new SpdyStream(request.type(), GetWeakPtr(), request.url(),
885ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                     request.priority(),
886a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                     stream_initial_send_window_size_,
887a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                     stream_initial_recv_window_size_,
88890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     request.net_log()));
889a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  *stream = new_stream->GetWeakPtr();
890a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  InsertCreatedStream(new_stream.Pass());
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "Net.SpdyPriorityCount",
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<int>(request.priority()), 0, 10, 11);
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void SpdySession::CancelStreamRequest(
9003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& request) {
9013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(request);
9028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  RequestPriority priority = request->priority();
9038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_GE(priority, MINIMUM_PRIORITY);
9048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_LE(priority, MAXIMUM_PRIORITY);
9057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
906a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if DCHECK_IS_ON
907a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // |request| should not be in a queue not matching its priority.
908a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
909a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (priority == i)
910a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
911a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i];
912a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(std::find_if(queue->begin(),
913a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        queue->end(),
914a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        RequestEquals(request)) == queue->end());
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
916a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PendingStreamRequestQueue* queue =
9198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      &pending_create_stream_queues_[priority];
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remove |request| from |queue| while preserving the order of the
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // other elements.
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PendingStreamRequestQueue::iterator it =
9233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      std::find_if(queue->begin(), queue->end(), RequestEquals(request));
9243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // The request may already be removed if there's a
9253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // CompleteStreamRequest() in flight.
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != queue->end()) {
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it = queue->erase(it);
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |request| should be in the queue at most once, and if it is
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // present, should not be pending completion.
9303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(std::find_if(it, queue->end(), RequestEquals(request)) ==
9313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           queue->end());
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() {
9368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (int j = MAXIMUM_PRIORITY; j >= MINIMUM_PRIORITY; --j) {
9373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (pending_create_stream_queues_[j].empty())
9383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
9413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        pending_create_stream_queues_[j].front();
9423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(pending_request);
9433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_create_stream_queues_[j].pop_front();
9443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return pending_request;
9453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
9463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return base::WeakPtr<SpdyStreamRequest>();
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::ProcessPendingStreamRequests() {
950a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Like |max_concurrent_streams_|, 0 means infinite for
951a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // |max_requests_to_process|.
952a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  size_t max_requests_to_process = 0;
953a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (max_concurrent_streams_ != 0) {
954a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    max_requests_to_process =
955a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        max_concurrent_streams_ -
956a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        (active_streams_.size() + created_streams_.size());
957a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
958a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (size_t i = 0;
959a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       max_requests_to_process == 0 || i < max_requests_to_process; ++i) {
9603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
9613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetNextPendingStreamRequest();
9623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pending_request)
963a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
9643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
965cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Note that this post can race with other stream creations, and it's
966cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // possible that the un-stalled stream will be stalled again if it loses.
967cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(jgraettinger): Provide stronger ordering guarantees.
9683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
9693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE,
9703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::Bind(&SpdySession::CompleteStreamRequest,
9713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                   weak_factory_.GetWeakPtr(),
9723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                   pending_request));
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
97790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pooled_aliases_.insert(alias_key);
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
980f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SpdyMajorVersion SpdySession::GetProtocolVersion() const {
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffered_spdy_framer_->protocol_version();
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool SpdySession::HasAcceptableTransportSecurity() const {
986cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // If we're not even using TLS, we have no standards to meet.
987cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!is_secure_) {
988cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
989cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
990cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
991cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We don't enforce transport security standards for older SPDY versions.
992cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetProtocolVersion() < SPDY4) {
993cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
994cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
995cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
996cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SSLInfo ssl_info;
997cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(connection_->socket()->GetSSLInfo(&ssl_info));
998cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
999cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // HTTP/2 requires TLS 1.2+
1000cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (SSLConnectionStatusToVersion(ssl_info.connection_status) <
1001cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SSL_CONNECTION_VERSION_TLS1_2) {
1002cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
1003cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1004cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1005cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!IsSecureTLSCipherSuite(
1006cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          SSLConnectionStatusToCipherSuite(ssl_info.connection_status))) {
1007cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
1008cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1009cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1010cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
1011cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1012cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1013ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbase::WeakPtr<SpdySession> SpdySession::GetWeakPtr() {
1014ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return weak_factory_.GetWeakPtr();
1015ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1016ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1017a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool SpdySession::CloseOneIdleConnection() {
1018ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1019ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(pool_);
1020cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (active_streams_.empty()) {
1021cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1022ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1023cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Return false as the socket wasn't immediately closed.
1024cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
1025a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
1026a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1027c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueStreamWrite(
1028a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream,
1029c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyFrameType frame_type,
1030c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<SpdyBufferProducer> producer) {
1031c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(frame_type == HEADERS ||
1032c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == DATA ||
1033c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == CREDENTIAL ||
1034c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == SYN_STREAM);
1035c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream);
1036c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1038c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<SpdyFrame> SpdySession::CreateSynStream(
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyStreamId stream_id,
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RequestPriority priority,
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyControlFlags flags,
1042116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const SpdyHeaderBlock& block) {
1043a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
1044a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
1045eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendPrefacePingIfNoneInFlight();
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
10508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SpdyPriority spdy_priority =
10518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      ConvertRequestPriorityToSpdyPriority(priority, GetProtocolVersion());
1052116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1053116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<SpdyFrame> syn_frame;
1054116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(hkhalil): Avoid copy of |block|.
1055116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (GetProtocolVersion() <= SPDY3) {
1056116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SpdySynStreamIR syn_stream(stream_id);
1057116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_stream.set_associated_to_stream_id(0);
1058116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_stream.set_priority(spdy_priority);
1059116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1060116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
1061116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_stream.set_name_value_block(block);
1062116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream));
1063116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
1064116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SpdyHeadersIR headers(stream_id);
1065116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    headers.set_priority(spdy_priority);
1066116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    headers.set_has_priority(true);
1067116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1068116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    headers.set_name_value_block(block);
1069116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
1070116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter spdy_requests("spdy.requests");
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_requests.Increment();
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  streams_initiated_count_++;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1076a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
1077116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
1078116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       base::Bind(&NetLogSpdySynStreamSentCallback,
1079116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  &block,
1080116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  (flags & CONTROL_FLAG_FIN) != 0,
1081116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
1082116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  spdy_priority,
1083116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  stream_id));
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1086c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return syn_frame.Pass();
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1089c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id,
1090c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     IOBuffer* data,
1091c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     int len,
1092c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     SpdyDataFlags flags) {
1093cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING) {
1094ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return scoped_ptr<SpdyBuffer>();
1095ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1096ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1097a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
1098a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
1099eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(stream->stream_id(), stream_id);
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (len < 0) {
11032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
1104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return scoped_ptr<SpdyBuffer>();
11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int effective_len = std::min(len, kMaxSpdyFrameChunkSize);
1108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool send_stalled_by_stream =
1110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (flow_control_state_ >= FLOW_CONTROL_STREAM) &&
1111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (stream->send_window_size() <= 0);
1112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool send_stalled_by_session = IsSendStalled();
1113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // NOTE: There's an enum of the same name in histograms.xml.
1115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  enum SpdyFrameFlowControlState {
1116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_NOT_STALLED,
1117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_STREAM,
1118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_SESSION,
1119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_STREAM_AND_SESSION,
1120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
1121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SpdyFrameFlowControlState frame_flow_control_state = SEND_NOT_STALLED;
1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (send_stalled_by_stream) {
1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_session) {
1125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      frame_flow_control_state = SEND_STALLED_BY_STREAM_AND_SESSION;
1126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
1127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      frame_flow_control_state = SEND_STALLED_BY_STREAM;
1128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (send_stalled_by_session) {
1130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    frame_flow_control_state = SEND_STALLED_BY_SESSION;
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM) {
1134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
1135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Net.SpdyFrameStreamFlowControlState",
1136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        frame_flow_control_state,
1137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SEND_STALLED_BY_STREAM + 1);
1138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
1139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
1140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Net.SpdyFrameStreamAndSessionFlowControlState",
1141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        frame_flow_control_state,
1142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SEND_STALLED_BY_STREAM_AND_SESSION + 1);
1143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Obey send window size of the stream if stream flow control is
1146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // enabled.
11472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flow_control_state_ >= FLOW_CONTROL_STREAM) {
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_stream) {
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream->set_send_stalled_by_flow_control(true);
1150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Even though we're currently stalled only by the stream, we
1151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // might end up being stalled by the session also.
1152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      QueueSendStalledStream(*stream);
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log().AddEvent(
1154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NetLog::IntegerCallback("stream_id", stream_id));
1156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return scoped_ptr<SpdyBuffer>();
11572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    effective_len = std::min(effective_len, stream->send_window_size());
1160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Obey send window size of the session if session flow control is
1163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // enabled.
1164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
1165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_session) {
1166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      stream->set_send_stalled_by_flow_control(true);
1167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      QueueSendStalledStream(*stream);
1168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      net_log().AddEvent(
1169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
1170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::IntegerCallback("stream_id", stream_id));
1171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return scoped_ptr<SpdyBuffer>();
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    effective_len = std::min(effective_len, session_send_window_size_);
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(effective_len, 0);
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Clear FIN flag if only some of the data will be in the data
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // frame.
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (effective_len < len)
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN);
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SEND_DATA,
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len,
11882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   (flags & DATA_FLAG_FIN) != 0));
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send PrefacePing for DATA_FRAMEs with nonzero payload size.
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (effective_len > 0)
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendPrefacePingIfNoneInFlight();
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): reduce memory copies here.
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
11972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> frame(
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateDataFrame(
1199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          stream_id, data->data(),
1200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<uint32>(effective_len), flags));
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass()));
1203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
120403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Send window size is based on payload size, so nothing to do if this is
120503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // just a FIN with no payload.
120603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION &&
120703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      effective_len != 0) {
1208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DecreaseSendWindowSize(static_cast<int32>(effective_len));
1209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    data_buffer->AddConsumeCallback(
1210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&SpdySession::OnWriteBufferConsumed,
1211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   weak_factory_.GetWeakPtr(),
1212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   static_cast<size_t>(effective_len)));
1213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return data_buffer.Pass();
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1218a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::CloseActiveStream(SpdyStreamId stream_id, int status) {
1219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
1220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1221a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
1223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1224a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
1225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1226a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseActiveStreamIterator(it, status);
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::CloseCreatedStream(
1231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream, int status) {
1232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_EQ(stream->stream_id(), 0u);
1233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CreatedStreamSet::iterator it = created_streams_.find(stream.get());
1235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == created_streams_.end()) {
1236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseCreatedStreamIterator(it, status);
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::ResetStream(SpdyStreamId stream_id,
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              SpdyRstStreamStatus status,
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& description) {
1246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
1250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResetStreamIterator(it, status, description);
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ContainsKey(active_streams_, stream_id);
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState SpdySession::GetLoadState() const {
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just report that we're idle since the session could be doing
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // many things concurrently.
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LOAD_STATE_IDLE;
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            int status) {
1269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(mbelshe): We should send a RST_STREAM control frame here
1270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //                so that the server can cancel a large send.
1271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  active_streams_.erase(it);
1274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1275ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(akalin): When SpdyStream was ref-counted (and
1276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // was only done when status was not OK. This meant that pushed
1278ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // streams can still be claimed after they're closed. This is
1279ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // probably something that we still want to support, although server
1280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // push is hardly used. Write tests for this and fix this. (See
1281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // http://crbug.com/261712 .)
1282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (owned_stream->type() == SPDY_PUSH_STREAM) {
12833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    unclaimed_pushed_streams_.erase(owned_stream->url());
1284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    num_pushed_streams_--;
1285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!owned_stream->IsReservedRemote())
1286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      num_active_pushed_streams_--;
1287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
12883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DeleteStream(owned_stream.Pass(), status);
1290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MaybeFinishGoingAway();
12913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If there are no active streams and the socket pool is stalled, close the
12933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // session to free up a socket slot.
12943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (active_streams_.empty() && connection_->IsPoolStalled()) {
1295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
12963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
1300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                             int status) {
1301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyStream> owned_stream(*it);
1302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  created_streams_.erase(it);
1303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DeleteStream(owned_stream.Pass(), status);
1304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
1307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      SpdyRstStreamStatus status,
1308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const std::string& description) {
1309bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Send the RST_STREAM frame first as CloseActiveStreamIterator()
1310bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // may close us.
1311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStreamId stream_id = it->first;
1312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RequestPriority priority = it->second.stream->priority();
1313bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  EnqueueResetStreamFrame(stream_id, priority, status, description);
1314bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Removes any pending writes for the stream except for possibly an
1316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // in-flight one.
1317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
1318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1320bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
1321bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          RequestPriority priority,
1322bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          SpdyRstStreamStatus status,
1323bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          const std::string& description) {
1324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
1325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  net_log().AddEvent(
1327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM,
1328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
1329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(buffered_spdy_framer_.get());
1331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyFrame> rst_frame(
1332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      buffered_spdy_framer_->CreateRstStream(stream_id, status));
1333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass());
13355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordProtocolErrorHistogram(MapRstStreamStatusToProtocolError(status));
1336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
1339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING) {
1341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ignore_result(DoReadLoop(expected_read_state, result));
13449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
13452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
1347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
13480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK_EQ(read_state_, expected_read_state);
13492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = true;
13512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int bytes_read_without_yielding = 0;
1353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Loop until the session is draining, the read becomes blocked, or
1355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // the read limit is exceeded.
1356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (true) {
1357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    switch (read_state_) {
1358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case READ_STATE_DO_READ:
13590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        CHECK_EQ(result, OK);
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = DoRead();
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1362ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case READ_STATE_DO_READ_COMPLETE:
1363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (result > 0)
1364ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          bytes_read_without_yielding += result;
13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = DoReadComplete(result);
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
13672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
1368ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        NOTREACHED() << "read_state_: " << read_state_;
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
13702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (availability_state_ == STATE_DRAINING)
1373ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1374ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1375ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result == ERR_IO_PENDING)
1376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1377ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1378ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (bytes_read_without_yielding > kMaxReadBytesWithoutYielding) {
1379ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      read_state_ = READ_STATE_DO_READ;
1380ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MessageLoop::current()->PostTask(
1381ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          FROM_HERE,
1382ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          base::Bind(&SpdySession::PumpReadLoop,
1383ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                     weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
1384ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      result = ERR_IO_PENDING;
1385ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1386ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1387ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1388ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1389ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1390ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = false;
13912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return result;
13932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::DoRead() {
1396ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
13972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CHECK(connection_);
13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(connection_->socket());
1400ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  read_state_ = READ_STATE_DO_READ_COMPLETE;
14012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return connection_->socket()->Read(
14022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      read_buffer_.get(),
14032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kReadBufferSize,
1404ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&SpdySession::PumpReadLoop,
1405ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE));
14062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::DoReadComplete(int result) {
1409ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1410ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse a frame.  For now this code requires that the frame fit into our
1412ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // buffer (kReadBufferSize).
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): support arbitrarily large frames!
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (result == 0) {
1416ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
1417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                total_bytes_received_, 1, 100000000, 50);
1418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(ERR_CONNECTION_CLOSED, "Connection closed");
1419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
14202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ERR_CONNECTION_CLOSED;
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (result < 0) {
1424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(static_cast<Error>(result), "result is < 0.");
1425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return result;
1426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1427a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CHECK_LE(result, kReadBufferSize);
14282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  total_bytes_received_ += result;
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  last_activity_time_ = time_func_();
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
14332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  char* data = read_buffer_->data();
1434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (result > 0) {
1435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    uint32 bytes_processed = buffered_spdy_framer_->ProcessInput(data, result);
14362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result -= bytes_processed;
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data += bytes_processed;
1438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1439cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (availability_state_ == STATE_DRAINING) {
1440cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return ERR_CONNECTION_CLOSED;
1441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
14429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1443ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(buffered_spdy_framer_->error_code(), SpdyFramer::SPDY_NO_ERROR);
1444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1445ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1446ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  read_state_ = READ_STATE_DO_READ;
14472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return OK;
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::PumpWriteLoop(WriteState expected_write_state, int result) {
1451ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1452ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, expected_write_state);
1453ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1454cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DoWriteLoop(expected_write_state, result);
1455ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING && !in_flight_write_ &&
1457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      write_queue_.IsEmpty()) {
1458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pool_->RemoveUnavailableSession(GetWeakPtr());  // Destroys |this|.
1459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1460ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1462ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1463ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWriteLoop(WriteState expected_write_state, int result) {
1464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1465ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(write_state_, WRITE_STATE_IDLE);
1466ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, expected_write_state);
1467ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1468ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = true;
1469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Loop until the session is closed or the write becomes blocked.
1471ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (true) {
1472ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    switch (write_state_) {
1473ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_DO_WRITE:
1474ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DCHECK_EQ(result, OK);
1475ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        result = DoWrite();
1476ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1477ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_DO_WRITE_COMPLETE:
1478ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        result = DoWriteComplete(result);
1479ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1480ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_IDLE:
1481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      default:
1482ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        NOTREACHED() << "write_state_: " << write_state_;
1483ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1484ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1485ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1486ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (write_state_ == WRITE_STATE_IDLE) {
1487ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, ERR_IO_PENDING);
1488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1489ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1490ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1491ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result == ERR_IO_PENDING)
1492ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1493ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1495ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1496ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = false;
1497ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1498ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return result;
1499ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1500ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1501ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWrite() {
1502ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1504ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(buffered_spdy_framer_);
1505ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (in_flight_write_) {
1506ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
1507ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
1508ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Grab the next frame to send.
1509ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    SpdyFrameType frame_type = DATA;
1510ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    scoped_ptr<SpdyBufferProducer> producer;
1511ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::WeakPtr<SpdyStream> stream;
1512ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!write_queue_.Dequeue(&frame_type, &producer, &stream)) {
1513ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_state_ = WRITE_STATE_IDLE;
1514ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return ERR_IO_PENDING;
1515ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1516ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1517ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (stream.get())
15180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CHECK(!stream->IsClosed());
1519ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1520ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Activate the stream only when sending the SYN_STREAM frame to
1521ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // guarantee monotonically-increasing stream IDs.
1522ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (frame_type == SYN_STREAM) {
15230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CHECK(stream.get());
15240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CHECK_EQ(stream->stream_id(), 0u);
15250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_ptr<SpdyStream> owned_stream =
15260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          ActivateCreatedStream(stream.get());
15270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      InsertActivatedStream(owned_stream.Pass());
1528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (stream_hi_water_mark_ > kLastStreamId) {
1530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        CHECK_EQ(stream->stream_id(), kLastStreamId);
1531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // We've exhausted the stream ID space, and no new streams may be
1532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // created after this one.
1533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        MakeUnavailable();
1534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        StartGoingAway(kLastStreamId, ERR_ABORTED);
1535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
1536ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1537ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1538ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_ = producer->ProduceBuffer();
1539ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!in_flight_write_) {
1540ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      NOTREACHED();
1541ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return ERR_UNEXPECTED;
1542ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1543ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_frame_type_ = frame_type;
1544ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
1545ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_GE(in_flight_write_frame_size_,
1546ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              buffered_spdy_framer_->GetFrameMinimumSize());
1547ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_stream_ = stream;
1548ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1549ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1550ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  write_state_ = WRITE_STATE_DO_WRITE_COMPLETE;
1551ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1552ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
1553ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // with Socket implementations that don't store their IOBuffer
1554ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
1555ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  scoped_refptr<IOBuffer> write_io_buffer =
1556ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      in_flight_write_->GetIOBufferForRemainingData();
1557ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return connection_->socket()->Write(
1558ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_io_buffer.get(),
1559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      in_flight_write_->GetRemainingSize(),
1560ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&SpdySession::PumpWriteLoop,
1561ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE_COMPLETE));
1562ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1563ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWriteComplete(int result) {
1565ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1566ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(result, ERR_IO_PENDING);
1567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1569ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  last_activity_time_ = time_func_();
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (result < 0) {
1572ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_NE(result, ERR_IO_PENDING);
1573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_.reset();
1574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_frame_type_ = DATA;
1575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_frame_size_ = 0;
1576a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    in_flight_write_stream_.reset();
1577cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    write_state_ = WRITE_STATE_DO_WRITE;
1578cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(static_cast<Error>(result), "Write error");
1579cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return OK;
1580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It should not be possible to have written more bytes than our
1583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in_flight_write_.
1584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(static_cast<size_t>(result),
1585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_->GetRemainingSize());
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (result > 0) {
1588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_->Consume(static_cast<size_t>(result));
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only notify the stream when we've fully written the pending frame.
1591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (in_flight_write_->GetRemainingSize() == 0) {
1592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // It is possible that the stream was cancelled while we were
1593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // writing to the socket.
1594868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (in_flight_write_stream_.get()) {
1595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DCHECK_GT(in_flight_write_frame_size_, 0u);
1596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        in_flight_write_stream_->OnFrameWriteComplete(
1597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_frame_type_,
1598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_frame_size_);
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Cleanup the write which just completed.
1602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_.reset();
1603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_type_ = DATA;
1604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_size_ = 0;
1605a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      in_flight_write_stream_.reset();
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  write_state_ = WRITE_STATE_DO_WRITE;
1610ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return OK;
16119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
16129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1613ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::DcheckGoingAway() const {
1614a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if DCHECK_IS_ON
1615ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1616a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
1617a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(pending_create_stream_queues_[i].empty());
16189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
1619ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(created_streams_.empty());
1620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
1621ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SpdySession::DcheckDraining() const {
1624ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckGoingAway();
1625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_EQ(availability_state_, STATE_DRAINING);
1626ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(active_streams_.empty());
1627ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(unclaimed_pushed_streams_.empty());
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::StartGoingAway(SpdyStreamId last_good_stream_id,
1631ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                 Error status) {
1632ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1633bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1634ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // The loops below are carefully written to avoid reentrancy problems.
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  while (true) {
16373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = GetTotalSize(pending_create_stream_queues_);
16383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
16393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetNextPendingStreamRequest();
16403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pending_request)
16413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
16423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new stream requests should be added while the session is
16433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // going away.
16443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_));
16453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_request->OnRequestCompleteFailure(ERR_ABORTED);
1646ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
16477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
16487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  while (true) {
16493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = active_streams_.size();
16507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    ActiveStreamMap::iterator it =
16517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        active_streams_.lower_bound(last_good_stream_id + 1);
16527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (it == active_streams_.end())
16537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
1654ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LogAbandonedActiveStream(it, status);
1655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, status);
16563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new streams should be activated while the session is going
16573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // away.
16583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, active_streams_.size());
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!created_streams_.empty()) {
16623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = created_streams_.size();
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreatedStreamSet::iterator it = created_streams_.begin();
1664a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    LogAbandonedStream(*it, status);
1665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseCreatedStreamIterator(it, status);
16663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new streams should be created while the session is going
16673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // away.
16683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, created_streams_.size());
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id);
1672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1673ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckGoingAway();
1674ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::MaybeFinishGoingAway() {
1677cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (active_streams_.empty() && availability_state_ == STATE_GOING_AWAY) {
1678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(OK, "Finished going away");
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1680ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1681ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1682cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SpdySession::DoDrainSession(Error err, const std::string& description) {
1683cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING) {
1684cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
1685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1686cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MakeUnavailable();
1687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1688f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // If |err| indicates an error occurred, inform the peer that we're closing
1689f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // and why. Don't GOAWAY on a graceful or idle close, as that may
1690f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // unnecessarily wake the radio. We could technically GOAWAY on network errors
1691f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // (we'll probably fail to actually write it, but that's okay), however many
1692f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // unit-tests would need to be updated.
1693f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (err != OK &&
1694f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      err != ERR_ABORTED &&  // Used by SpdySessionPool to close idle sessions.
1695f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      err != ERR_NETWORK_CHANGED &&  // Used to deprecate sessions on IP change.
1696f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      err != ERR_SOCKET_NOT_CONNECTED &&
1697f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      err != ERR_CONNECTION_CLOSED && err != ERR_CONNECTION_RESET) {
1698f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Enqueue a GOAWAY to inform the peer of why we're closing the connection.
16991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SpdyGoAwayIR goaway_ir(last_accepted_push_stream_id_,
1700f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           MapNetErrorToGoAwayStatus(err),
1701f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           description);
1702f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    EnqueueSessionWrite(HIGHEST,
1703f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        GOAWAY,
1704f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        scoped_ptr<SpdyFrame>(
1705f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            buffered_spdy_framer_->SerializeFrame(goaway_ir)));
1706f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1707cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  availability_state_ = STATE_DRAINING;
1709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  error_on_close_ = err;
1710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  net_log_.AddEvent(
1712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      NetLog::TYPE_SPDY_SESSION_CLOSE,
1713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
1714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err);
1716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.OtherErrors",
1717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                              total_bytes_received_, 1, 100000000, 50);
1718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1719f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (err == OK) {
1720f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // We ought to be going away already, as this is a graceful close.
1721f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DcheckGoingAway();
1722f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
1723f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    StartGoingAway(0, err);
1724f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DcheckDraining();
1726cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MaybePostWriteLoop();
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1729a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) {
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(stream);
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description = base::StringPrintf(
1732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      "ABANDONED (stream_id=%d): ", stream->stream_id()) +
1733ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      stream->url().spec();
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream->LogStreamError(status, description);
1735ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We don't increment the streams abandoned counter here. If the
1736ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // stream isn't active (i.e., it hasn't written anything to the wire
1737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // yet) then it's as if it never existed. If it is active, then
1738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // LogAbandonedActiveStream() will increment the counters.
1739ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1740ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
1742ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                           Error status) {
1743ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GT(it->first, 0u);
1744ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  LogAbandonedStream(it->second.stream, status);
1745ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ++streams_abandoned_count_;
1746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::StatsCounter abandoned_streams("spdy.abandoned_streams");
1747ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  abandoned_streams.Increment();
1748ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (it->second.stream->type() == SPDY_PUSH_STREAM &&
1749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.find(it->second.stream->url()) !=
1750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.end()) {
1751ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::StatsCounter abandoned_push_streams("spdy.abandoned_push_streams");
1752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    abandoned_push_streams.Increment();
1753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1756cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SpdyStreamId SpdySession::GetNewStreamId() {
1757cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK_LE(stream_hi_water_mark_, kLastStreamId);
1758cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SpdyStreamId id = stream_hi_water_mark_;
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_hi_water_mark_ += 2;
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id;
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1763c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::CloseSessionOnError(Error err,
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& description) {
1765f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_LT(err, ERR_IO_PENDING);
1766cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DoDrainSession(err, description);
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SpdySession::MakeUnavailable() {
1770cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_AVAILABLE) {
17715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    availability_state_ = STATE_GOING_AWAY;
1772effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    pool_->MakeSessionUnavailable(GetWeakPtr());
17735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
17745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
17755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
17762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* SpdySession::GetInfoAsValue() const {
17772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("source_id", net_log_.source().id);
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dict->SetString("host_port_pair", host_port_pair().ToString());
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pooled_aliases_.empty()) {
17832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* alias_list = new base::ListValue();
178490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (std::set<SpdySessionKey>::const_iterator it =
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             pooled_aliases_.begin();
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         it != pooled_aliases_.end(); it++) {
178790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      alias_list->Append(new base::StringValue(
178890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          it->host_port_pair().ToString()));
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->Set("aliases", alias_list);
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
179290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dict->SetString("proxy", host_port_proxy_pair().second.ToURI());
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("active_streams", active_streams_.size());
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unclaimed_pushed_streams",
1797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   unclaimed_pushed_streams_.size());
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("is_secure", is_secure_);
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("protocol_negotiated",
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  SSLClientSocket::NextProtoToString(
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      connection_->socket()->GetNegotiatedProtocol()));
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dict->SetInteger("error", error_on_close_);
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("max_concurrent_streams", max_concurrent_streams_);
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_initiated_count", streams_initiated_count_);
18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_pushed_count", streams_pushed_count_);
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_pushed_and_claimed_count",
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_and_claimed_count_);
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_abandoned_count", streams_abandoned_count_);
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("frames_received", buffered_spdy_framer_->frames_received());
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("sent_settings", sent_settings_);
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("received_settings", received_settings_);
18182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("send_window_size", session_send_window_size_);
18202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("recv_window_size", session_recv_window_size_);
18212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("unacked_recv_window_bytes",
18222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   session_unacked_recv_window_bytes_);
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::IsReused() const {
1827effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return buffered_spdy_framer_->frames_received() > 0 ||
1828effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      connection_->reuse_type() == ClientSocketHandle::UNUSED_IDLE;
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id,
18322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    LoadTimingInfo* load_timing_info) const {
18332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return connection_->GetLoadTimingInfo(stream_id != kFirstStreamId,
18342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        load_timing_info);
18352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
18362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetPeerAddress(IPEndPoint* address) const {
1838c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int rv = ERR_SOCKET_NOT_CONNECTED;
1839c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
1840c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    rv = connection_->socket()->GetPeerAddress(address);
18412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetPeerAddress",
1844c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        rv == ERR_SOCKET_NOT_CONNECTED);
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1846c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return rv;
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1849c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int SpdySession::GetLocalAddress(IPEndPoint* address) const {
1850c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int rv = ERR_SOCKET_NOT_CONNECTED;
1851c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
1852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    rv = connection_->socket()->GetLocalAddress(address);
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetLocalAddress",
1856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        rv == ERR_SOCKET_NOT_CONNECTED);
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return rv;
1859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueSessionWrite(RequestPriority priority,
1862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      SpdyFrameType frame_type,
1863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      scoped_ptr<SpdyFrame> frame) {
1864f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(frame_type == RST_STREAM || frame_type == SETTINGS ||
1865f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         frame_type == WINDOW_UPDATE || frame_type == PING ||
1866f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         frame_type == GOAWAY);
1867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueWrite(
1868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      priority, frame_type,
1869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_ptr<SpdyBufferProducer>(
1870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          new SimpleBufferProducer(
1871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              scoped_ptr<SpdyBuffer>(new SpdyBuffer(frame.Pass())))),
1872a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::WeakPtr<SpdyStream>());
1873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueWrite(RequestPriority priority,
1876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               SpdyFrameType frame_type,
1877c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               scoped_ptr<SpdyBufferProducer> producer,
1878a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                               const base::WeakPtr<SpdyStream>& stream) {
1879cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_DRAINING)
1880ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1881ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_queue_.Enqueue(priority, frame_type, producer.Pass(), stream);
1883cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MaybePostWriteLoop();
1884cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1885cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1886cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SpdySession::MaybePostWriteLoop() {
1887ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (write_state_ == WRITE_STATE_IDLE) {
1888cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    CHECK(!in_flight_write_);
1889ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    write_state_ = WRITE_STATE_DO_WRITE;
1890ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MessageLoop::current()->PostTask(
1891ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        FROM_HERE,
1892ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        base::Bind(&SpdySession::PumpWriteLoop,
1893ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE, OK));
1894ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1897a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::InsertCreatedStream(scoped_ptr<SpdyStream> stream) {
18980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK_EQ(stream->stream_id(), 0u);
18990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(created_streams_.find(stream.get()) == created_streams_.end());
1900a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  created_streams_.insert(stream.release());
1901a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1903a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)scoped_ptr<SpdyStream> SpdySession::ActivateCreatedStream(SpdyStream* stream) {
19040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK_EQ(stream->stream_id(), 0u);
19050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(created_streams_.find(stream) != created_streams_.end());
1906a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream->set_stream_id(GetNewStreamId());
1907a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SpdyStream> owned_stream(stream);
1908a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  created_streams_.erase(stream);
1909a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return owned_stream.Pass();
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1912a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1913a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SpdyStreamId stream_id = stream->stream_id();
19140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK_NE(stream_id, 0u);
1915a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  std::pair<ActiveStreamMap::iterator, bool> result =
1916eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      active_streams_.insert(
1917eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
19180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(result.second);
19190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ignore_result(stream.release());
1920a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1922a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
1923868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (in_flight_write_stream_.get() == stream.get()) {
1924a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // If we're deleting the stream for the in-flight write, we still
1925a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // need to let the write complete, so we clear
1926a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // |in_flight_write_stream_| and let the write finish on its own
1927a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // without notifying |in_flight_write_stream_|.
1928a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    in_flight_write_stream_.reset();
1929a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
1930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1931a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  write_queue_.RemovePendingWritesForStream(stream->GetWeakPtr());
19322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stream->OnClose(status);
1933a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1934cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (availability_state_ == STATE_AVAILABLE) {
1935cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ProcessPendingStreamRequests();
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1939ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbase::WeakPtr<SpdyStream> SpdySession::GetActivePushStream(const GURL& url) {
19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter used_push_streams("spdy.claimed_push_streams");
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1942ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PushedStreamMap::iterator unclaimed_it = unclaimed_pushed_streams_.find(url);
1943ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (unclaimed_it == unclaimed_pushed_streams_.end())
1944eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return base::WeakPtr<SpdyStream>();
1945eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1946ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  SpdyStreamId stream_id = unclaimed_it->second.stream_id;
1947ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  unclaimed_pushed_streams_.erase(unclaimed_it);
1948eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1949ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
1950ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (active_it == active_streams_.end()) {
1951eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1952eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return base::WeakPtr<SpdyStream>();
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1954eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1955eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM);
1956eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  used_push_streams.Increment();
1957ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return active_it->second.stream->GetWeakPtr();
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::GetSSLInfo(SSLInfo* ssl_info,
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             bool* was_npn_negotiated,
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NextProto* protocol_negotiated) {
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *was_npn_negotiated = connection_->socket()->WasNpnNegotiated();
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *protocol_negotiated = connection_->socket()->GetNegotiatedProtocol();
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return connection_->socket()->GetSSLInfo(ssl_info);
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::GetSSLCertRequestInfo(
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SSLCertRequestInfo* cert_request_info) {
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetSSLClientSocket()->GetSSLCertRequestInfo(cert_request_info);
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
1977ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1978ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
19795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordProtocolErrorHistogram(MapFramerErrorToProtocolError(error_code));
1980f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string description =
1981f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::StringPrintf("Framer error: %d (%s).",
1982f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         error_code,
1983f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         SpdyFramer::ErrorCodeToString(error_code));
1984f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DoDrainSession(MapFramerErrorToNetError(error_code), description);
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnStreamError(SpdyStreamId stream_id,
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& description) {
1989ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1990ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1991eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1992eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
1993eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // We still want to send a frame to reset the stream even if we
1994eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // don't know anything about it.
1995bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(
1996eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        stream_id, IDLE, RST_STREAM_PROTOCOL_ERROR, description);
1997eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1998eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1999eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2000eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, description);
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2003a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SpdySession::OnDataFrameHeader(SpdyStreamId stream_id,
2004a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    size_t length,
2005a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    bool fin) {
2006a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CHECK(in_io_loop_);
2007a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2008a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2009a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2010a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // By the time data comes in, the stream may already be inactive.
2011a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (it == active_streams_.end())
2012a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
2013a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2014a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SpdyStream* stream = it->second.stream;
2015a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CHECK_EQ(stream->stream_id(), stream_id);
2016a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2017a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(buffered_spdy_framer_);
2018a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  size_t header_len = buffered_spdy_framer_->GetDataFrameMinimumSize();
2019a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream->IncrementRawReceivedBytes(header_len);
2020a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
2021a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const char* data,
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    size_t len,
20252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bool fin) {
2026ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2027ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
20284ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  if (data == NULL && len != 0) {
20294ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    // This is notification of consumed data padding.
20304ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    // TODO(jgraettinger): Properly flow padding into WINDOW_UPDATE frames.
20314ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    // See crbug.com/353012.
20324ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch    return;
20334ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  }
20344ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch
20352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(len, 1u << 24);
2036a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_DATA,
20392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&NetLogSpdyDataCallback, stream_id, len, fin));
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Build the buffer as early as possible so that we go through the
2043c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // session flow control checks and update
2044c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // |unacked_recv_window_bytes_| properly even when the stream is
2045c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // inactive (since the other side has still reduced its session send
2046c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // window).
2047c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  scoped_ptr<SpdyBuffer> buffer;
2048c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (data) {
2049c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    DCHECK_GT(len, 0u);
2050a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    CHECK_LE(len, static_cast<size_t>(kReadBufferSize));
2051c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    buffer.reset(new SpdyBuffer(data, len));
2052c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
2053c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
2054c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      DecreaseRecvWindowSize(static_cast<int32>(len));
2055c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      buffer->AddConsumeCallback(
2056c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch          base::Bind(&SpdySession::OnReadBufferConsumed,
2057c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                     weak_factory_.GetWeakPtr()));
2058c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
2059c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else {
2060c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    DCHECK_EQ(len, 0u);
2061c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
2062c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
2063eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2064c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
20652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // By the time data comes in, the stream may already be inactive.
2066c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (it == active_streams_.end())
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2069eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
2070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(stream->stream_id(), stream_id);
2071eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2072a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream->IncrementRawReceivedBytes(len);
2073a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2074eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it->second.waiting_for_syn_reply) {
2075eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& error = "Data received before SYN_REPLY.";
2076eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
2077eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
2078eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
2079eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2080eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2081eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  stream->OnDataReceived(buffer.Pass());
2082c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2083c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2084c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnSettings(bool clear_persisted) {
2085ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2086ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2087c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (clear_persisted)
2088c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    http_server_properties_->ClearSpdySettings(host_port_pair());
2089c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2090a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log_.IsLogging()) {
2091c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    net_log_.AddEvent(
2092c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS,
2093c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&NetLogSpdySettingsCallback, host_port_pair(),
2094c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   clear_persisted));
2095c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2096cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2097cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetProtocolVersion() >= SPDY4) {
2098cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Send an acknowledgment of the setting.
2099cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SpdySettingsIR settings_ir;
2100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    settings_ir.set_is_ack(true);
2101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    EnqueueSessionWrite(
2102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        HIGHEST,
2103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SETTINGS,
2104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        scoped_ptr<SpdyFrame>(
2105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            buffered_spdy_framer_->SerializeFrame(settings_ir)));
2106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSetting(SpdySettingsIds id,
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint8 flags,
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint32 value) {
2112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleSetting(id, value);
21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_server_properties_->SetSpdySetting(
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_port_pair(),
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id,
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<SpdySettingsFlags>(flags),
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value);
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  received_settings_ = true;
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Log the setting.
21231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const SpdyMajorVersion protocol_version = GetProtocolVersion();
21241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_SETTING,
21251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    base::Bind(&NetLogSpdySettingCallback,
21261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               id,
21271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               protocol_version,
21281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               static_cast<SpdySettingsFlags>(flags),
21291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               value));
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SpdySession::OnSendCompressedFrame(
21337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SpdyStreamId stream_id,
21347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SpdyFrameType type,
21357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t payload_len,
21367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t frame_len) {
2137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (type != SYN_STREAM && type != HEADERS)
21387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(buffered_spdy_framer_.get());
21417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t compressed_len =
21427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      frame_len - buffered_spdy_framer_->GetSynStreamMinimumSize();
21437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
21447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (payload_len) {
21457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Make sure we avoid early decimal truncation.
21467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int compression_pct = 100 - (100 * compressed_len) / payload_len;
21477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_PERCENTAGE("Net.SpdySynStreamCompressionPercentage",
21487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                             compression_pct);
21497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
21507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SpdySession::OnReceiveCompressedFrame(
2153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SpdyStreamId stream_id,
2154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SpdyFrameType type,
2155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    size_t frame_len) {
2156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  last_compressed_frame_len_ = frame_len;
2157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
2158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint SpdySession::OnInitialResponseHeadersReceived(
2160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SpdyHeaderBlock& response_headers,
2161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::Time response_time,
2162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::TimeTicks recv_first_byte_time,
2163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStream* stream) {
2164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SpdyStreamId stream_id = stream->stream_id();
2166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (stream->type() == SPDY_PUSH_STREAM) {
2168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(stream->IsReservedRemote());
2169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (max_concurrent_pushed_streams_ &&
2170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        num_active_pushed_streams_ >= max_concurrent_pushed_streams_) {
2171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ResetStream(stream_id,
2172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                  RST_STREAM_REFUSED_STREAM,
2173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                  "Stream concurrency limit reached.");
2174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return STATUS_CODE_REFUSED_STREAM;
2175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
2176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
2177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (stream->type() == SPDY_PUSH_STREAM) {
2179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Will be balanced in DeleteStream.
2180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    num_active_pushed_streams_++;
2181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
2182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2183a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // May invalidate |stream|.
2184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rv = stream->OnInitialResponseHeadersReceived(
2185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      response_headers, response_time, recv_first_byte_time);
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv < 0) {
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(rv, ERR_IO_PENDING);
2188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(active_streams_.find(stream_id) == active_streams_.end());
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return rv;
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSynStream(SpdyStreamId stream_id,
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              SpdyStreamId associated_stream_id,
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              SpdyPriority priority,
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool fin,
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool unidirectional,
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const SpdyHeaderBlock& headers) {
2200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2201ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
22026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (GetProtocolVersion() >= SPDY4) {
22036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    DCHECK_EQ(0u, associated_stream_id);
22046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    OnHeaders(stream_id, fin, headers);
22056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
22066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
22076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
2208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Time response_time = base::Time::Now();
2209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks recv_first_byte_time = time_func_();
2210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log_.IsLogging()) {
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log_.AddEvent(
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM,
22148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        base::Bind(&NetLogSpdySynStreamReceivedCallback,
22158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                   &headers, fin, unidirectional, priority,
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   stream_id, associated_stream_id));
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Split headers to simulate push promise and response.
22206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SpdyHeaderBlock request_headers;
22216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SpdyHeaderBlock response_headers;
22226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SplitPushedHeadersToRequestAndResponse(
22236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      headers, GetProtocolVersion(), &request_headers, &response_headers);
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!TryCreatePushStream(
22266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          stream_id, associated_stream_id, priority, request_headers))
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2228a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
2230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (active_it == active_streams_.end()) {
2231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    NOTREACHED();
2232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
2233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (OnInitialResponseHeadersReceived(response_headers,
2236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                       response_time,
2237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                       recv_first_byte_time,
2238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                       active_it->second.stream) != OK)
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter push_requests("spdy.pushed_streams");
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_requests.Increment();
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::DeleteExpiredPushedStreams() {
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unclaimed_pushed_streams_.empty())
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that adequate time has elapsed since the last sweep.
22502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (time_func_() < next_unclaimed_push_stream_sweep_time_)
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Gather old streams to delete.
22542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks minimum_freshness = time_func_() -
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
2256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<SpdyStreamId> streams_to_close;
2257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (PushedStreamMap::iterator it = unclaimed_pushed_streams_.begin();
2258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != unclaimed_pushed_streams_.end(); ++it) {
2259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (minimum_freshness > it->second.creation_time)
2260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      streams_to_close.push_back(it->second.stream_id);
2261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (std::vector<SpdyStreamId>::const_iterator to_close_it =
2264ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch           streams_to_close.begin();
2265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       to_close_it != streams_to_close.end(); ++to_close_it) {
2266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ActiveStreamMap::iterator active_it = active_streams_.find(*to_close_it);
2267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (active_it == active_streams_.end())
2268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
2269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2270ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LogAbandonedActiveStream(active_it, ERR_INVALID_SPDY_STREAM);
2271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // CloseActiveStreamIterator() will remove the stream from
2272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // |unclaimed_pushed_streams_|.
22735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResetStreamIterator(
22745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        active_it, RST_STREAM_REFUSED_STREAM, "Stream not claimed.");
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  next_unclaimed_push_stream_sweep_time_ = time_func_() +
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSynReply(SpdyStreamId stream_id,
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             bool fin,
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const SpdyHeaderBlock& headers) {
2284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2285ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Time response_time = base::Time::Now();
2287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks recv_first_byte_time = time_func_();
2288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SYN_REPLY,
22928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        base::Bind(&NetLogSpdySynReplyOrHeadersReceivedCallback,
22938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                   &headers, fin, stream_id));
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(stream->stream_id(), stream_id);
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream->IncrementRawReceivedBytes(last_compressed_frame_len_);
2306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  last_compressed_frame_len_ = 0;
2307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
23085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (GetProtocolVersion() >= SPDY4) {
23095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& error =
23105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "SPDY4 wasn't expecting SYN_REPLY.";
23115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
23125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
23135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
23145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!it->second.waiting_for_syn_reply) {
2316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& error =
2317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Received duplicate SYN_REPLY for stream.";
2318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
23195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  it->second.waiting_for_syn_reply = false;
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ignore_result(OnInitialResponseHeadersReceived(
2325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      headers, response_time, recv_first_byte_time, stream));
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnHeaders(SpdyStreamId stream_id,
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            bool fin,
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const SpdyHeaderBlock& headers) {
2331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_HEADERS,
23368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        base::Bind(&NetLogSpdySynReplyOrHeadersReceivedCallback,
23378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                   &headers, fin, stream_id));
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2340a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2341a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id;
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
2348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(stream->stream_id(), stream_id);
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream->IncrementRawReceivedBytes(last_compressed_frame_len_);
2351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  last_compressed_frame_len_ = 0;
2352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
23536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::Time response_time = base::Time::Now();
23546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::TimeTicks recv_first_byte_time = time_func_();
23556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
23565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (it->second.waiting_for_syn_reply) {
23575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (GetProtocolVersion() < SPDY4) {
23585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& error =
23595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Was expecting SYN_REPLY, not HEADERS.";
23605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
23615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
23625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
23635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
23645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
23655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    it->second.waiting_for_syn_reply = false;
23665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ignore_result(OnInitialResponseHeadersReceived(
23675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        headers, response_time, recv_first_byte_time, stream));
23686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else if (it->second.stream->IsReservedRemote()) {
23696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ignore_result(OnInitialResponseHeadersReceived(
23706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        headers, response_time, recv_first_byte_time, stream));
23715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
23725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int rv = stream->OnAdditionalResponseHeadersReceived(headers);
23735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (rv < 0) {
23745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK_NE(rv, ERR_IO_PENDING);
23755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(active_streams_.find(stream_id) == active_streams_.end());
23765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
238003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool SpdySession::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) {
238103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Validate stream id.
238203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Was the frame sent on a stream id that has not been used in this session?
238303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (stream_id % 2 == 1 && stream_id > stream_hi_water_mark_)
238403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
23851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
23861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (stream_id % 2 == 0 && stream_id > last_accepted_push_stream_id_)
23871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
23881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
238903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
239003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
239103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
23922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::OnRstStream(SpdyStreamId stream_id,
23932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              SpdyRstStreamStatus status) {
2394ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2395ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description;
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log().AddEvent(
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_RST_STREAM,
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdyRstCallback,
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 stream_id, status, &description));
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2402a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2403a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received RST for invalid stream" << stream_id;
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2408a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == 0) {
2412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->OnDataReceived(scoped_ptr<SpdyBuffer>());
24132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (status == RST_STREAM_REFUSED_STREAM) {
2414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM);
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM);
2418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->LogStreamError(
24192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ERR_SPDY_PROTOCOL_ERROR,
24202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf("SPDY stream closed with status: %d", status));
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(mbelshe): Map from Spdy-protocol errors to something sensical.
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //                For now, it doesn't matter much - it is a protocol error.
2423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           SpdyGoAwayStatus status) {
2429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2431f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(jgraettinger): UMA histogram on |status|.
2432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY,
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdyGoAwayCallback,
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 last_accepted_stream_id,
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 active_streams_.size(),
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 unclaimed_pushed_streams_.size(),
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 status));
24395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MakeUnavailable();
2440ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  StartGoingAway(last_accepted_stream_id, ERR_ABORTED);
2441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // This is to handle the case when we already don't have any active
2442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // streams (i.e., StartGoingAway() did nothing). Otherwise, we have
2443ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // active streams and so the last one being closed will finish the
2444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // going away process (see DeleteStream()).
2445ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  MaybeFinishGoingAway();
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void SpdySession::OnPing(SpdyPingId unique_id, bool is_ack) {
2449ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_PING,
2453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received"));
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send response to a PING from server.
2456a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if ((protocol_ >= kProtoSPDY4 && !is_ack) ||
2457a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      (protocol_ < kProtoSPDY4 && unique_id % 2 == 0)) {
2458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    WritePingFrame(unique_id, true);
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --pings_in_flight_;
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ < 0) {
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING);
2465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(ERR_SPDY_PROTOCOL_ERROR, "pings_in_flight_ is < 0.");
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pings_in_flight_ = 0;
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ > 0)
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We will record RTT in histogram when there are no more client sent
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pings_in_flight_.
2475ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  RecordPingRTTHistogram(time_func_() - last_ping_sent_time_);
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
24792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 uint32 delta_window_size) {
2480ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(delta_window_size, static_cast<uint32>(kint32max));
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
24842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
24852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 stream_id, delta_window_size));
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2488a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (stream_id == kSessionFlowControlStreamId) {
2489a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // WINDOW_UPDATE for the session.
2490a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (flow_control_state_ < FLOW_CONTROL_STREAM_AND_SESSION) {
2491a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for session when "
2492a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   << "session flow control is not turned on";
2493a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      // TODO(akalin): Record an error and close the session.
2494a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2495a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
24962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2497a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (delta_window_size < 1u) {
2498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
2499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DoDrainSession(
2500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ERR_SPDY_PROTOCOL_ERROR,
2501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          "Received WINDOW_UPDATE with an invalid delta_window_size " +
2502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              base::UintToString(delta_window_size));
2503a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2504a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2505a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2506a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    IncreaseSendWindowSize(static_cast<int32>(delta_window_size));
2507a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
2508a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // WINDOW_UPDATE for a stream.
2509a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (flow_control_state_ < FLOW_CONTROL_STREAM) {
2510a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      // TODO(akalin): Record an error and close the session.
2511a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for stream " << stream_id
2512a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   << " when flow control is not turned on";
2513a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2514a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2515a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2517a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2518a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (it == active_streams_.end()) {
2519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // NOTE:  it may just be that the stream was cancelled.
2520a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
2521a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2522a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2523a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStream* stream = it->second.stream;
2525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(stream->stream_id(), stream_id);
2526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2527a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (delta_window_size < 1u) {
2528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ResetStreamIterator(it,
2529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          RST_STREAM_FLOW_CONTROL_ERROR,
2530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          base::StringPrintf(
2531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              "Received WINDOW_UPDATE with an invalid "
2532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              "delta_window_size %ud", delta_window_size));
2533a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
25342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(it->second.stream->stream_id(), stream_id);
2537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->IncreaseSendWindowSize(
2538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        static_cast<int32>(delta_window_size));
25392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
25436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                      SpdyStreamId associated_stream_id,
25446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                      SpdyPriority priority,
25456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                      const SpdyHeaderBlock& headers) {
25466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Server-initiated streams should have even sequence numbers.
25476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if ((stream_id & 0x1) != 0) {
25486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    LOG(WARNING) << "Received invalid push stream id " << stream_id;
25491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (GetProtocolVersion() > SPDY2)
25501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Odd push stream id.");
25516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
25526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
25536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
25541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (GetProtocolVersion() > SPDY2) {
25551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (stream_id <= last_accepted_push_stream_id_) {
25561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(WARNING) << "Received push stream id lesser or equal to the last "
25571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   << "accepted before " << stream_id;
25581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CloseSessionOnError(
25591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          ERR_SPDY_PROTOCOL_ERROR,
25601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          "New push stream id must be greater than the last accepted.");
25611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return false;
25621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
25631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
25641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
25656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (IsStreamActive(stream_id)) {
25661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // For SPDY3 and higher we should not get here, we'll start going away
25671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // earlier on |last_seen_push_stream_id_| check.
25681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CHECK_GT(SPDY3, GetProtocolVersion());
25696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    LOG(WARNING) << "Received push for active stream " << stream_id;
25706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
25716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
25726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
25731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  last_accepted_push_stream_id_ = stream_id;
25741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
25756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RequestPriority request_priority =
25766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion());
25776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
25786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (availability_state_ == STATE_GOING_AWAY) {
25796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // TODO(akalin): This behavior isn't in the SPDY spec, although it
25806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // probably should be.
25816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnqueueResetStreamFrame(stream_id,
25826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            request_priority,
25836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            RST_STREAM_REFUSED_STREAM,
25846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            "push stream request received when going away");
25856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
25866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
25876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
25886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (associated_stream_id == 0) {
25896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // In SPDY4 0 stream id in PUSH_PROMISE frame leads to framer error and
25906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // session going away. We should never get here.
25916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CHECK_GT(SPDY4, GetProtocolVersion());
25926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    std::string description = base::StringPrintf(
25936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "Received invalid associated stream id %d for pushed stream %d",
25946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        associated_stream_id,
25956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        stream_id);
25966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnqueueResetStreamFrame(
25976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        stream_id, request_priority, RST_STREAM_REFUSED_STREAM, description);
25986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
25996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  streams_pushed_count_++;
26026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // TODO(mbelshe): DCHECK that this is a GET method?
26046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Verify that the response had a URL for us.
26066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true);
26076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!gurl.is_valid()) {
26086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnqueueResetStreamFrame(stream_id,
26096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            request_priority,
26106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            RST_STREAM_PROTOCOL_ERROR,
26116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                            "Pushed stream url was invalid: " + gurl.spec());
26126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
26136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Verify we have a valid stream association.
26166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ActiveStreamMap::iterator associated_it =
26176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      active_streams_.find(associated_stream_id);
26186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (associated_it == active_streams_.end()) {
26196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnqueueResetStreamFrame(
26206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        stream_id,
26216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        request_priority,
26226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        RST_STREAM_INVALID_STREAM,
26236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        base::StringPrintf("Received push for inactive associated stream %d",
26246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                           associated_stream_id));
26256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
26266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Check that the pushed stream advertises the same origin as its associated
26296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // stream. Bypass this check if and only if this session is with a SPDY proxy
26306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // that is trusted explicitly via the --trusted-spdy-proxy switch.
26316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (trusted_spdy_proxy_.Equals(host_port_pair())) {
26326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // Disallow pushing of HTTPS content.
26336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (gurl.SchemeIs("https")) {
26346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      EnqueueResetStreamFrame(
26356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          stream_id,
26366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          request_priority,
26376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          RST_STREAM_REFUSED_STREAM,
26386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          base::StringPrintf("Rejected push of Cross Origin HTTPS content %d",
26396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             associated_stream_id));
26406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
26416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
26426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    GURL associated_url(associated_it->second.stream->GetUrlFromHeaders());
26436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (associated_url.GetOrigin() != gurl.GetOrigin()) {
26446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      EnqueueResetStreamFrame(
26456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          stream_id,
26466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          request_priority,
26476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          RST_STREAM_REFUSED_STREAM,
26486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          base::StringPrintf("Rejected Cross Origin Push Stream %d",
26496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                             associated_stream_id));
26506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return false;
26516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
26526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // There should not be an existing pushed stream with the same path.
26556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  PushedStreamMap::iterator pushed_it =
26566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      unclaimed_pushed_streams_.lower_bound(gurl);
26576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (pushed_it != unclaimed_pushed_streams_.end() &&
26586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      pushed_it->first == gurl) {
26596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnqueueResetStreamFrame(
26606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        stream_id,
26616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        request_priority,
26626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        RST_STREAM_PROTOCOL_ERROR,
26636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        "Received duplicate pushed stream with url: " + gurl.spec());
26646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
26656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  scoped_ptr<SpdyStream> stream(new SpdyStream(SPDY_PUSH_STREAM,
26686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               GetWeakPtr(),
26696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               gurl,
26706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               request_priority,
26716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               stream_initial_send_window_size_,
26726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               stream_initial_recv_window_size_,
26736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                               net_log_));
26746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  stream->set_stream_id(stream_id);
26756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // In spdy4/http2 PUSH_PROMISE arrives on associated stream.
26776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (associated_it != active_streams_.end() && GetProtocolVersion() >= SPDY4) {
26786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    associated_it->second.stream->IncrementRawReceivedBytes(
26796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        last_compressed_frame_len_);
26806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
26816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    stream->IncrementRawReceivedBytes(last_compressed_frame_len_);
26826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
26836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  last_compressed_frame_len_ = 0;
26856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DeleteExpiredPushedStreams();
26876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  PushedStreamMap::iterator inserted_pushed_it =
26886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      unclaimed_pushed_streams_.insert(
26896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          pushed_it,
26906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_())));
26916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(inserted_pushed_it != pushed_it);
26926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  InsertActivatedStream(stream.Pass());
26946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
26956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
26966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (active_it == active_streams_.end()) {
26976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    NOTREACHED();
26986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return false;
26996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
27006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
27016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  active_it->second.stream->OnPushPromiseHeadersReceived(headers);
27026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(active_it->second.stream->IsReservedRemote());
2703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  num_pushed_streams_++;
27046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return true;
27056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
27066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
27077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SpdySession::OnPushPromise(SpdyStreamId stream_id,
2708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                SpdyStreamId promised_stream_id,
2709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                const SpdyHeaderBlock& headers) {
27106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  CHECK(in_io_loop_);
27116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
27126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (net_log_.IsLogging()) {
27136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_PUSH_PROMISE,
27146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                      base::Bind(&NetLogSpdyPushPromiseReceivedCallback,
27156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                 &headers,
27166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                 stream_id,
27176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                 promised_stream_id));
27186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
27196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
27206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Any priority will do.
27216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // TODO(baranovich): pass parent stream id priority?
27226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!TryCreatePushStream(promised_stream_id, stream_id, 0, headers))
27236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
27246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
27256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::StatsCounter push_requests("spdy.pushed_streams");
27266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  push_requests.Increment();
27277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
27287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
27292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id,
27302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         uint32 delta_window_size) {
27312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2732a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2733a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
2734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
2735eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SendWindowUpdateFrame(
2736eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      stream_id, delta_window_size, it->second.stream->priority());
27372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2739a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void SpdySession::SendInitialData() {
2740a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(enable_sending_initial_data_);
2741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2742a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (send_connection_header_prefix_) {
2743a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DCHECK_EQ(protocol_, kProtoSPDY4);
2744a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<SpdyFrame> connection_header_prefix_frame(
2745a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        new SpdyFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
2746a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      kHttp2ConnectionHeaderPrefixSize,
2747a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      false /* take_ownership */));
2748a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Count the prefix as part of the subsequent SETTINGS frame.
2749a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    EnqueueSessionWrite(HIGHEST, SETTINGS,
2750a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                        connection_header_prefix_frame.Pass());
2751a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
2752a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // First, notify the server about the settings they should use when
27545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // communicating with us.
2755a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SettingsMap settings_map;
2756a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Create a new settings frame notifying the server of our
2757a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // max concurrent streams and initial window size.
2758a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  settings_map[SETTINGS_MAX_CONCURRENT_STREAMS] =
2759a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
2760a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (flow_control_state_ >= FLOW_CONTROL_STREAM &&
2761a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      stream_initial_recv_window_size_ != kSpdyStreamInitialWindowSize) {
2762a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    settings_map[SETTINGS_INITIAL_WINDOW_SIZE] =
2763a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        SettingsFlagsAndValue(SETTINGS_FLAG_NONE,
2764a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              stream_initial_recv_window_size_);
2765a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
2766a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SendSettings(settings_map);
27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2768eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Next, notify the server about our initial recv window size.
2769a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
2770eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Bump up the receive window size to the real initial value. This
2771eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // has to go here since the WINDOW_UPDATE frame sent by
2772eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // IncreaseRecvWindowSize() call uses |buffered_spdy_framer_|.
2773eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_);
2774eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // This condition implies that |kDefaultInitialRecvWindowSize| -
2775eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // |session_recv_window_size_| doesn't overflow.
2776eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK_GT(session_recv_window_size_, 0);
2777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IncreaseRecvWindowSize(
2778eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        kDefaultInitialRecvWindowSize - session_recv_window_size_);
2779eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2780eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (protocol_ <= kProtoSPDY31) {
27821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Finally, notify the server about the settings they have
27831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // previously told us to use when communicating with them (after
27841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // applying them).
27851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const SettingsMap& server_settings_map =
27861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        http_server_properties_->GetSpdySettings(host_port_pair());
27871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (server_settings_map.empty())
27881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SettingsMap::const_iterator it =
27911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        server_settings_map.find(SETTINGS_CURRENT_CWND);
27921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    uint32 cwnd = (it != server_settings_map.end()) ? it->second.second : 0;
27931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwndSent", cwnd, 1, 200, 100);
27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (SettingsMap::const_iterator it = server_settings_map.begin();
27961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         it != server_settings_map.end(); ++it) {
27971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const SpdySettingsIds new_id = it->first;
27981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const uint32 new_val = it->second.second;
27991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      HandleSetting(new_id, new_val);
28001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SendSettings(server_settings_map);
28031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
28045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendSettings(const SettingsMap& settings) {
28081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const SpdyMajorVersion protocol_version = GetProtocolVersion();
28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS,
28111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&NetLogSpdySendSettingsCallback, &settings, protocol_version));
28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the SETTINGS frame and send it.
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
28142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> settings_frame(
28155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateSettings(settings));
28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sent_settings_ = true;
2817c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(HIGHEST, SETTINGS, settings_frame.Pass());
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::HandleSetting(uint32 id, uint32 value) {
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (id) {
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SETTINGS_MAX_CONCURRENT_STREAMS:
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_concurrent_streams_ = std::min(static_cast<size_t>(value),
28242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         kMaxConcurrentStreamLimit);
28252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProcessPendingStreamRequests();
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
28272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SETTINGS_INITIAL_WINDOW_SIZE: {
28282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (flow_control_state_ < FLOW_CONTROL_STREAM) {
2829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        net_log().AddEvent(
2830c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_NO_FLOW_CONTROL);
28312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
28322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
28332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2834c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (value > static_cast<uint32>(kint32max)) {
28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net_log().AddEvent(
2836c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            NetLog::IntegerCallback("initial_window_size", value));
28382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
28402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only.
2842c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int32 delta_window_size =
2843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<int32>(value) - stream_initial_send_window_size_;
2844c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      stream_initial_send_window_size_ = static_cast<int32>(value);
28452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateStreamsSendWindowSize(delta_window_size);
28462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      net_log().AddEvent(
28472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
28482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NetLog::IntegerCallback("delta_window_size", delta_window_size));
28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
28502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) {
28552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2856a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (ActiveStreamMap::iterator it = active_streams_.begin();
2857a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)       it != active_streams_.end(); ++it) {
2858eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->AdjustSendWindowSize(delta_window_size);
28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2861a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (CreatedStreamSet::const_iterator it = created_streams_.begin();
2862a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)       it != created_streams_.end(); it++) {
2863a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (*it)->AdjustSendWindowSize(delta_window_size);
28645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
28655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendPrefacePingIfNoneInFlight() {
28682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pings_in_flight_ || !enable_ping_based_connection_checking_)
28695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
28705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2871ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks now = time_func_();
28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no activity in the session, then send a preface-PING.
28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((now - last_activity_time_) > connection_at_risk_of_loss_time_)
28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendPrefacePing();
28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendPrefacePing() {
2878a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  WritePingFrame(next_ping_id_, false);
28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::SendWindowUpdateFrame(SpdyStreamId stream_id,
28822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        uint32 delta_window_size,
28832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RequestPriority priority) {
28842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2885a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2886a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it != active_streams_.end()) {
2887eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(it->second.stream->stream_id(), stream_id);
28882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
28892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
28902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(stream_id, kSessionFlowControlStreamId);
28912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
28922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_.AddEvent(
28942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_SENT_WINDOW_UPDATE_FRAME,
28952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
28962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 stream_id, delta_window_size));
28972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
28992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> window_update_frame(
29002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffered_spdy_framer_->CreateWindowUpdate(stream_id, delta_window_size));
2901c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(priority, WINDOW_UPDATE, window_update_frame.Pass());
29022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
29032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2904a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void SpdySession::WritePingFrame(uint32 unique_id, bool is_ack) {
29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
29062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> ping_frame(
2907a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffered_spdy_framer_->CreatePingFrame(unique_id, is_ack));
2908c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(HIGHEST, PING, ping_frame.Pass());
29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2910a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (net_log().IsLogging()) {
29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_PING,
2913a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "sent"));
29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!is_ack) {
29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_ping_id_ += 2;
29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++pings_in_flight_;
29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PlanToCheckPingStatus();
2919ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    last_ping_sent_time_ = time_func_();
29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::PlanToCheckPingStatus() {
29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (check_ping_status_pending_)
29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  check_ping_status_pending_ = true;
292890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
29295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
29305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
2931ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 time_func_()), hung_interval_);
29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) {
2935ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
2936ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
29375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we got a response back for all PINGs we had sent.
29385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ == 0) {
29395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_ping_status_pending_ = false;
29405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
29415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(check_ping_status_pending_);
29445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks now = time_func_();
29465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delay = hung_interval_ - (now - last_activity_time_);
29475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) {
29495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Track all failed PING messages in a separate bucket.
2950a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RecordPingRTTHistogram(base::TimeDelta::Max());
2951cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(ERR_SPDY_PING_FAILED, "Failed ping.");
29525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
29535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the status of connection after a delay.
295690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
29575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
29585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
29595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 now),
29605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delay);
29615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) {
29645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("Net.SpdyPing.RTT", duration);
29655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordProtocolErrorHistogram(
29685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyProtocolErrorDetails details) {
2969c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details,
29705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NUM_SPDY_PROTOCOL_ERROR_DETAILS);
29715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (EndsWith(host_port_pair().host(), "google.com", false)) {
2972c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details,
29735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              NUM_SPDY_PROTOCOL_ERROR_DETAILS);
29745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
29755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
29765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordHistograms() {
29785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
29795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_initiated_count_,
29805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
29815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
29825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_pushed_count_,
29835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
29845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
29855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_pushed_and_claimed_count_,
29865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
29875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
29885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_abandoned_count_,
29895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
29905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent",
29915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            sent_settings_ ? 1 : 0, 2);
29925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
29935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            received_settings_ ? 1 : 0, 2);
29945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamStallsPerSession",
29955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              stalled_streams_,
29965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
29975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionsWithStalls",
29985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            stalled_streams_ > 0 ? 1 : 0, 2);
29995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (received_settings_) {
30015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Enumerate the saved settings, and set histograms for it.
30025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SettingsMap& settings_map =
30035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http_server_properties_->GetSpdySettings(host_port_pair());
30045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SettingsMap::const_iterator it;
30065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (it = settings_map.begin(); it != settings_map.end(); ++it) {
30075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SpdySettingsIds id = it->first;
30085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint32 val = it->second.second;
30095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (id) {
30105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_CURRENT_CWND:
30115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Record several different histograms to see if cwnd converges
30125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // for larger volumes of data being sent.
30135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd",
30145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 200, 100);
30152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (total_bytes_received_ > 10 * 1024) {
30165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K",
30175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        val, 1, 200, 100);
30182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (total_bytes_received_ > 25 * 1024) {
30195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K",
30205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          val, 1, 200, 100);
30212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              if (total_bytes_received_ > 50 * 1024) {
30225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K",
30235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            val, 1, 200, 100);
30242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (total_bytes_received_ > 100 * 1024) {
30255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K",
30265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              val, 1, 200, 100);
30275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
30285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              }
30295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
30305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
30315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
30325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_ROUND_TRIP_TIME:
30335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT",
30345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 1200, 100);
30355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
30365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_DOWNLOAD_RETRANS_RATE:
30375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate",
30385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 100, 50);
30395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
30405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
30415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
30425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
30435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
30445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
30455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void SpdySession::CompleteStreamRequest(
30483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& pending_request) {
30492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Abort if the request has already been cancelled.
30503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!pending_request)
30515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
30525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3053a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream;
3054cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int rv = TryCreateStream(pending_request, &stream);
30552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3056a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (rv == OK) {
30573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(stream);
30583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_request->OnRequestCompleteSuccess(stream);
3059cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
3060cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
3061cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!stream);
3062cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3063cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (rv != ERR_IO_PENDING) {
3064a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pending_request->OnRequestCompleteFailure(rv);
3065a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
30665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SSLClientSocket* SpdySession::GetSSLClientSocket() const {
30695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
30705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
30715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLClientSocket* ssl_socket =
30725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<SSLClientSocket*>(connection_->socket());
30735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ssl_socket);
30745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ssl_socket;
30755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
30765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3077c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnWriteBufferConsumed(
3078c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t frame_payload_size,
3079c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t consume_size,
3080c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyBuffer::ConsumeSource consume_source) {
3081ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a write SpdyBuffer is
3082ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., a stream is closed due to incoming data).
3083ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
30842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
3085ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3086c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (consume_source == SpdyBuffer::DISCARD) {
3087c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If we're discarding a frame or part of it, increase the send
3088c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // window by the number of discarded bytes. (Although if we're
3089c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // discarding part of a frame, it's probably because of a write
3090c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // error and we'll be tearing down the session soon.)
3091c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t remaining_payload_bytes = std::min(consume_size, frame_payload_size);
3092c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(remaining_payload_bytes, 0u);
3093c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IncreaseSendWindowSize(static_cast<int32>(remaining_payload_bytes));
3094c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3095c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For consumed bytes, the send window is increased when we receive
3096c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // a WINDOW_UPDATE frame.
3097c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
30982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3099c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) {
3100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a SpdyBuffer is
3101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., a stream is closed due to incoming data).
3102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
31042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
31052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for overflow.
31072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32 max_delta_window_size = kint32max - session_send_window_size_;
31082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delta_window_size > max_delta_window_size) {
3109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
3110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(
3111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ERR_SPDY_PROTOCOL_ERROR,
3112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Received WINDOW_UPDATE [delta: " +
3113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            base::IntToString(delta_window_size) +
3114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            "] for session overflows session_send_window_size_ [current: " +
3115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            base::IntToString(session_send_window_size_) + "]");
31162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
31172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
31182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  session_send_window_size_ += delta_window_size;
31202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_.AddEvent(
31222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
31232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
31242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 delta_window_size, session_send_window_size_));
31252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
31262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!IsSendStalled());
31272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResumeSendStalledStreams();
31282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
31292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::DecreaseSendWindowSize(int32 delta_window_size) {
3131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
3132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We only call this method when sending a frame. Therefore,
3134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |delta_window_size| should be within the valid frame size range.
3135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
3136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
3137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |send_window_size_| should have been at least |delta_window_size| for
3139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // this call to happen.
3140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_send_window_size_, delta_window_size);
3141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_send_window_size_ -= delta_window_size;
3143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
3145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
3146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
3147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 -delta_window_size, session_send_window_size_));
3148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnReadBufferConsumed(
3151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t consume_size,
3152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyBuffer::ConsumeSource consume_source) {
3153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a read SpdyBuffer is
3154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., discarded by a SpdyReadQueue).
3155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
3157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(consume_size, 1u);
3158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(consume_size, static_cast<size_t>(kint32max));
3159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IncreaseRecvWindowSize(static_cast<int32>(consume_size));
3161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::IncreaseRecvWindowSize(int32 delta_window_size) {
3164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
3165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_unacked_recv_window_bytes_, 0);
3166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_recv_window_size_, session_unacked_recv_window_bytes_);
3167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
3168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check for overflow.
3169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(delta_window_size, kint32max - session_recv_window_size_);
3170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_recv_window_size_ += delta_window_size;
3172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
3173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_STREAM_UPDATE_RECV_WINDOW,
3174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
3175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 delta_window_size, session_recv_window_size_));
3176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_unacked_recv_window_bytes_ += delta_window_size;
3178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (session_unacked_recv_window_bytes_ > kSpdySessionInitialWindowSize / 2) {
3179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendWindowUpdateFrame(kSessionFlowControlStreamId,
3180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          session_unacked_recv_window_bytes_,
3181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          HIGHEST);
3182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session_unacked_recv_window_bytes_ = 0;
3183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) {
3187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
3188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
3189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
3190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Since we never decrease the initial receive window size,
3192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |delta_window_size| should never cause |recv_window_size_| to go
3193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // negative. If we do, the receive window isn't being respected.
3194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (delta_window_size > session_recv_window_size_) {
3195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION);
3196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DoDrainSession(
3197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        ERR_SPDY_FLOW_CONTROL_ERROR,
3198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "delta_window_size is " + base::IntToString(delta_window_size) +
3199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            " in DecreaseRecvWindowSize, which is larger than the receive " +
3200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            "window size of " + base::IntToString(session_recv_window_size_));
3201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
3202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_recv_window_size_ -= delta_window_size;
3205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
3206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW,
3207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
3208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 -delta_window_size, session_recv_window_size_));
3209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3211a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::QueueSendStalledStream(const SpdyStream& stream) {
3212a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(stream.send_stalled_by_flow_control());
32138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  RequestPriority priority = stream.priority();
32148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_GE(priority, MINIMUM_PRIORITY);
32158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK_LE(priority, MAXIMUM_PRIORITY);
32168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  stream_send_unstall_queue_[priority].push_back(stream.stream_id());
32172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
32182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::ResumeSendStalledStreams() {
32202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
32212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We don't have to worry about new streams being queued, since
32232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // doing so would cause IsSendStalled() to return true. But we do
32242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // have to worry about streams being closed, as well as ourselves
32252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // being closed.
32262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  while (!IsSendStalled()) {
32282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t old_size = 0;
3229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if DCHECK_IS_ON
3230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    old_size = GetTotalSize(stream_send_unstall_queue_);
3231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
32322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpdyStreamId stream_id = PopStreamToPossiblyResume();
32342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_id == 0)
32352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
32362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
32372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The stream may actually still be send-stalled after this (due
32382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to its own send window) but that's okay -- it'll then be
32392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // resumed once its send window increases.
32402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it != active_streams_.end())
3241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      it->second.stream->PossiblyResumeIfSendStalled();
32422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The size should decrease unless we got send-stalled again.
32442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsSendStalled())
32452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_LT(GetTotalSize(stream_send_unstall_queue_), old_size);
32462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
32472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
32482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpdyStreamId SpdySession::PopStreamToPossiblyResume() {
32508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
32512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::deque<SpdyStreamId>* queue = &stream_send_unstall_queue_[i];
32522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!queue->empty()) {
32532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpdyStreamId stream_id = queue->front();
32542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queue->pop_front();
32552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return stream_id;
32562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
32572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
32582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return 0;
32592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
32602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
3262