spdy_session.cc revision 3551c9c881056c480085172ff9840cab31610854
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"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_server_properties.h"
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/spdy/spdy_buffer_producer.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_credential_builder.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_frame_builder.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_http_utils.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_protocol.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_session_pool.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_stream.h"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/ssl/server_bound_cert_service.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kReadBufferSize = 8 * 1024;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultConnectionAtRiskOfLossSeconds = 10;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kHungIntervalSeconds = 10;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Always start at 1 for the first stream id.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SpdyStreamId kFirstStreamId = 1;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minimum seconds that unclaimed pushed streams will be kept in memory.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinPushedStreamLifetimeSeconds = 300;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySynCallback(const SpdyHeaderBlock* headers,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   bool fin,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   bool unidirectional,
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   SpdyStreamId stream_id,
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   SpdyStreamId associated_stream,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   NetLog::LogLevel /* log_level */) {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* headers_list = new base::ListValue();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SpdyHeaderBlock::const_iterator it = headers->begin();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != headers->end(); ++it) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    headers_list->Append(new base::StringValue(base::StringPrintf(
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "%s: %s", it->first.c_str(),
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (ShouldShowHttpHeaderValue(
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            it->first) ? it->second : "[elided]").c_str())));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("fin", fin);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("unidirectional", unidirectional);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set("headers", headers_list);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", stream_id);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (associated_stream)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetInteger("associated_stream", associated_stream);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyCredentialCallback(size_t slot,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const std::string* origin,
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          NetLog::LogLevel /* log_level */) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("slot", slot);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("origin", *origin);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionCloseCallback(int net_error,
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const std::string* description,
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            NetLog::LogLevel /* log_level */) {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("net_error", net_error);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("description", *description);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionCallback(const HostPortProxyPair* host_pair,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NetLog::LogLevel /* log_level */) {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("host", host_pair->first.ToString());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("proxy", host_pair->second.ToPacString());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::Value* NetLogSpdySettingsCallback(const HostPortPair& host_port_pair,
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        bool clear_persisted,
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        NetLog::LogLevel /* log_level */) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetString("host", host_port_pair.ToString());
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetBoolean("clear_persisted", clear_persisted);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return dict;
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySettingCallback(SpdySettingsIds id,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       SpdySettingsFlags flags,
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       uint32 value,
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NetLog::LogLevel /* log_level */) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("id", id);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("flags", flags);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("value", value);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::Value* NetLogSpdySendSettingsCallback(const SettingsMap* settings,
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            NetLog::LogLevel /* log_level */) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* settings_list = new base::ListValue();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SettingsMap::const_iterator it = settings->begin();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != settings->end(); ++it) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SpdySettingsIds id = it->first;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SpdySettingsFlags flags = it->second.first;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32 value = it->second.second;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    settings_list->Append(new base::StringValue(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::StringPrintf("[id:%u flags:%u value:%u]", id, flags, value)));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set("settings", settings_list);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyWindowUpdateFrameCallback(
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpdyStreamId stream_id,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 delta,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NetLog::LogLevel /* log_level */) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("delta", delta);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdySessionWindowUpdateCallback(
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int32 delta,
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int32 window_size,
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NetLog::LogLevel /* log_level */) {
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* dict = new base::DictionaryValue();
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("delta", delta);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("window_size", window_size);
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return dict;
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyDataCallback(SpdyStreamId stream_id,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    int size,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bool fin,
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    NetLog::LogLevel /* log_level */) {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("size", size);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetBoolean("fin", fin);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyRstCallback(SpdyStreamId stream_id,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   int status,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const std::string* description,
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   NetLog::LogLevel /* log_level */) {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("stream_id", static_cast<int>(stream_id));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("status", status);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("description", *description);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyPingCallback(uint32 unique_id,
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    const char* type,
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    NetLog::LogLevel /* log_level */) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unique_id", unique_id);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("type", type);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* NetLogSpdyGoAwayCallback(SpdyStreamId last_stream_id,
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      int active_streams,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      int unclaimed_streams,
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      SpdyGoAwayStatus status,
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      NetLog::LogLevel /* log_level */) {
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("last_accepted_stream_id",
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   static_cast<int>(last_stream_id));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("active_streams", active_streams);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unclaimed_streams", unclaimed_streams);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("status", static_cast<int>(status));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Helper function to return the total size of an array of objects
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// with .size() member functions.
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  size_t total_size = 0;
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (size_t i = 0; i < N; ++i) {
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    total_size += arr[i].size();
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return total_size;
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Helper class for std:find_if on STL container containing
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// SpdyStreamRequest weak pointers.
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class RequestEquals {
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  RequestEquals(const base::WeakPtr<SpdyStreamRequest>& request)
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : request_(request) {}
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool operator()(const base::WeakPtr<SpdyStreamRequest>& request) const {
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return request_.get() == request.get();
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
2303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const base::WeakPtr<SpdyStreamRequest> request_;
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of concurrent streams we will ever create.  Even if
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the server permits more, we will never exceed this limit.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxConcurrentStreamLimit = 256;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)SpdyStreamRequest::SpdyStreamRequest() : weak_ptr_factory_(this) {
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpdyStreamRequest::~SpdyStreamRequest() {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CancelRequest();
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdyStreamRequest::StartRequest(
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SpdyStreamType type,
249ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::WeakPtr<SpdySession>& session,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url,
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RequestPriority priority,
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const BoundNetLog& net_log,
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const CompletionCallback& callback) {
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session);
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!session_);
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(callback_.is_null());
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  type_ = type;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  session_ = session;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url_ = url;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  priority_ = priority;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_ = net_log;
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_ = callback;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
266a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream;
2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int rv = session->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (rv == OK) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Reset();
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = stream;
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return rv;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdyStreamRequest::CancelRequest() {
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (session_)
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    session_->CancelStreamRequest(weak_ptr_factory_.GetWeakPtr());
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Do this to cancel any pending CompleteStreamRequest() tasks.
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() {
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!session_);
285a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream = stream_;
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(stream);
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return stream;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdyStreamRequest::OnRequestCompleteSuccess(
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream) {
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session_);
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(!callback_.is_null());
296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CompletionCallback callback = callback_;
297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  Reset();
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(stream);
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  stream_ = stream;
300a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  callback.Run(OK);
301a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
302a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
303a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdyStreamRequest::OnRequestCompleteFailure(int rv) {
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(session_);
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!stream_);
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_.is_null());
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CompletionCallback callback = callback_;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Reset();
309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK_NE(rv, OK);
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(rv);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdyStreamRequest::Reset() {
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  type_ = SPDY_BIDIRECTIONAL_STREAM;
315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  session_.reset();
316a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream_.reset();
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url_ = GURL();
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  priority_ = MINIMUM_PRIORITY;
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_ = BoundNetLog();
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_.Reset();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::ActiveStreamInfo()
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream(NULL),
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      waiting_for_syn_reply(false) {}
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream)
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream(stream),
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {}
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::ActiveStreamInfo::~ActiveStreamInfo() {}
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {}
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::PushedStreamInfo(
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStreamId stream_id,
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::TimeTicks creation_time)
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : stream_id(stream_id),
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      creation_time(creation_time) {}
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSpdySession::PushedStreamInfo::~PushedStreamInfo() {}
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochSpdySession::SpdySession(
344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const SpdySessionKey& spdy_session_key,
345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::WeakPtr<HttpServerProperties>& http_server_properties,
346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool verify_domain_authentication,
347a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bool enable_sending_initial_data,
348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool enable_credential_frames,
349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool enable_compression,
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    bool enable_ping_based_connection_checking,
351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NextProto default_protocol,
352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t stream_initial_recv_window_size,
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t initial_max_concurrent_streams,
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    size_t max_concurrent_streams_limit,
355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    TimeFunc time_func,
356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const HostPortPair& trusted_spdy_proxy,
357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NetLog* net_log)
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : weak_factory_(this),
359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      in_io_loop_(false),
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      spdy_session_key_(spdy_session_key),
361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pool_(NULL),
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_server_properties_(http_server_properties),
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_buffer_(new IOBuffer(kReadBufferSize)),
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_hi_water_mark_(kFirstStreamId),
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_type_(DATA),
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_size_(0),
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_secure_(false),
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      certificate_error_code_(OK),
369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      availability_state_(STATE_AVAILABLE),
370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      read_state_(READ_STATE_DO_READ),
371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_state_(WRITE_STATE_IDLE),
372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      error_on_close_(OK),
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      max_concurrent_streams_(initial_max_concurrent_streams == 0 ?
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              kInitialMaxConcurrentStreams :
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              initial_max_concurrent_streams),
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ?
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kMaxConcurrentStreamLimit :
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    max_concurrent_streams_limit),
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_initiated_count_(0),
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_count_(0),
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_and_claimed_count_(0),
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_abandoned_count_(0),
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      total_bytes_received_(0),
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sent_settings_(false),
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      received_settings_(false),
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stalled_streams_(0),
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pings_in_flight_(0),
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_ping_id_(1),
389ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      last_activity_time_(time_func()),
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      check_ping_status_pending_(false),
391a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      send_connection_header_prefix_(false),
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      flow_control_state_(FLOW_CONTROL_NONE),
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_initial_send_window_size_(kSpdyStreamInitialWindowSize),
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ?
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       kDefaultInitialRecvWindowSize :
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       stream_initial_recv_window_size),
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_send_window_size_(0),
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_recv_window_size_(0),
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session_unacked_recv_window_bytes_(0),
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verify_domain_authentication_(verify_domain_authentication),
402a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      enable_sending_initial_data_(enable_sending_initial_data),
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_credential_frames_(enable_credential_frames),
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_compression_(enable_compression),
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_ping_based_connection_checking_(
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          enable_ping_based_connection_checking),
407558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      protocol_(default_protocol),
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      credential_state_(SpdyCredentialState::kDefaultNumSlots),
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection_at_risk_of_loss_time_(
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hung_interval_(
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      trusted_spdy_proxy_(trusted_spdy_proxy),
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      time_func_(time_func) {
415558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // TODO(akalin): Change this to kProtoSPDYMinimumVersion once we
416558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // stop supporting SPDY/1.
417558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_GE(protocol_, kProtoSPDY2);
418558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(HttpStreamFactory::spdy_enabled());
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.BeginEvent(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION,
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  next_unclaimed_push_stream_sweep_time_ = time_func_() +
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdySession::~SpdySession() {
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(!pool_);
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckClosed();
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(akalin): Check connection->is_initialized() instead. This
4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // requires re-working CreateFakeSpdySession(), though.
4357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(connection_->socket());
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // With SPDY we can't recycle sockets.
4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  connection_->socket()->Disconnect();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordHistograms();
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Error SpdySession::InitializeWithSocket(
4457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scoped_ptr<ClientSocketHandle> connection,
446ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    SpdySessionPool* pool,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_secure,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int certificate_error_code) {
449ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(availability_state_, STATE_AVAILABLE);
451ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(read_state_, READ_STATE_DO_READ);
452ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, WRITE_STATE_IDLE);
4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!connection_);
454ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
455ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(certificate_error_code == OK ||
456ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch         certificate_error_code < ERR_IO_PENDING);
4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(akalin): Check connection->is_initialized() instead. This
4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // requires re-working CreateFakeSpdySession(), though.
4597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(connection->socket());
460ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter spdy_sessions("spdy.sessions");
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_sessions.Increment();
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  connection_ = connection.Pass();
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_secure_ = is_secure;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  certificate_error_code_ = certificate_error_code;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NextProto protocol_negotiated =
4697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      connection_->socket()->GetNegotiatedProtocol();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol_negotiated != kProtoUnknown) {
471558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    protocol_ = protocol_negotiated;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
473558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // TODO(akalin): Change this to kProtoSPDYMinimumVersion once we
474558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // stop supporting SPDY/1.
475558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_GE(protocol_, kProtoSPDY2);
476558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLClientSocket* ssl_socket = GetSSLClientSocket();
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ssl_socket && ssl_socket->WasChannelIDSent()) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // According to the SPDY spec, the credential associated with the TLS
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // connection is stored in slot[1].
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    credential_state_.SetHasCredential(GURL("https://" +
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            host_port_pair().ToString()));
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
486a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (protocol_ == kProtoHTTP2Draft04)
487a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    send_connection_header_prefix_ = true;
488a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
489558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (protocol_ >= kProtoSPDY31) {
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_STREAM_AND_SESSION;
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    session_send_window_size_ = kSpdySessionInitialWindowSize;
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    session_recv_window_size_ = kSpdySessionInitialWindowSize;
493558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  } else if (protocol_ >= kProtoSPDY3) {
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_STREAM;
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flow_control_state_ = FLOW_CONTROL_NONE;
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  buffered_spdy_framer_.reset(
500558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new BufferedSpdyFramer(NextProtoToSpdyMajorVersion(protocol_),
501558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                             enable_compression_));
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffered_spdy_framer_->set_visitor(this);
5037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  buffered_spdy_framer_->set_debug_visitor(this);
504558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  UMA_HISTOGRAM_ENUMERATION("Net.SpdyVersion", protocol_, kProtoMaximumVersion);
5057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(SPDY_PROXY_AUTH_ORIGIN)
5067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  UMA_HISTOGRAM_BOOLEAN("Net.SpdySessions_DataReductionProxy",
5077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        host_port_pair().Equals(HostPortPair::FromURL(
5087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            GURL(SPDY_PROXY_AUTH_ORIGIN))));
5097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_INITIALIZED,
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      connection_->socket()->NetLog().source().ToEventParametersCallback());
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
515ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int error = DoReadLoop(READ_STATE_DO_READ, OK);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error == ERR_IO_PENDING)
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    error = OK;
5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (error == OK) {
519ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_NE(availability_state_, STATE_CLOSED);
5203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    connection_->AddHigherLayeredPool(this);
521a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (enable_sending_initial_data_)
522a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SendInitialData();
523ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pool_ = pool;
524ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DcheckClosed();
5267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return static_cast<Error>(error);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!verify_domain_authentication_)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
534ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLInfo ssl_info;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_npn_negotiated;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NextProto protocol_negotiated = kProtoUnknown;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;   // This is not a secure session, so all domains are okay.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !ssl_info.client_cert_sent &&
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (enable_credential_frames_ || !ssl_info.channel_id_sent ||
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ServerBoundCertService::GetDomainForHost(domain) ==
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ServerBoundCertService::GetDomainForHost(host_port_pair().host())) &&
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ssl_info.cert->VerifyNameMatch(domain);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetPushStream(
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
552a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::WeakPtr<SpdyStream>* stream,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& stream_net_log) {
554ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
556a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream->reset();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
558ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(akalin): Add unit test exercising this code path.
559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
560ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
561ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
562ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(url);
563ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK)
564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
565ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
566ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  *stream = GetActivePushStream(url);
567ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (*stream) {
568ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_);
569ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    streams_pushed_and_claimed_count_++;
570ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
571ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return OK;
572ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
573ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
574bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// {,Try}CreateStream() and TryAccessStream() can be called with
575bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// |in_io_loop_| set if a stream is being created in response to
576bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// another being closed due to received data.
577bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
578ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochError SpdySession::TryAccessStream(const GURL& url) {
579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
580ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_secure_ && certificate_error_code_ != OK &&
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (url.SchemeIs("https") || url.SchemeIs("wss"))) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
585ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result = DoCloseSession(
586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_cast<Error>(certificate_error_code_),
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Tried to get SPDY stream for secure content over an unauthenticated "
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "session.");
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_SPDY_PROTOCOL_ERROR;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return OK;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)int SpdySession::TryCreateStream(
5963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& request,
5973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStream>* stream) {
5983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(request);
599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_GOING_AWAY)
601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_FAILED;
602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(akalin): Add unit test exercising this code path.
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
605ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(request->url());
608ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK)
609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
6107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!max_concurrent_streams_ ||
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (active_streams_.size() + created_streams_.size() <
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       max_concurrent_streams_)) {
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateStream(*request, stream);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stalled_streams_++;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS);
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_create_stream_queues_[request->priority()].push_back(request);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERR_IO_PENDING;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::CreateStream(const SpdyStreamRequest& request,
624a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                              base::WeakPtr<SpdyStream>* stream) {
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(request.priority(), NUM_PRIORITIES);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_GOING_AWAY)
629ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_FAILED;
630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
631ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(akalin): Add unit test exercising this code path.
632ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
633ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_CONNECTION_CLOSED;
634ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
635ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  Error err = TryAccessStream(request.url());
636ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (err != OK) {
637ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // This should have been caught in TryCreateStream().
638ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NOTREACHED();
639ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return err;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(connection_->socket());
643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(connection_->socket()->IsConnected());
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected",
646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          connection_->socket()->IsConnected());
647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!connection_->socket()->IsConnected()) {
648ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CloseSessionResult result = DoCloseSession(
649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ERR_CONNECTION_CLOSED,
650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          "Tried to create SPDY stream for a closed socket connection.");
651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return ERR_CONNECTION_CLOSED;
653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
656a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SpdyStream> new_stream(
657ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      new SpdyStream(request.type(), GetWeakPtr(), request.url(),
658ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                     request.priority(),
659a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                     stream_initial_send_window_size_,
660a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                     stream_initial_recv_window_size_,
66190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     request.net_log()));
662a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  *stream = new_stream->GetWeakPtr();
663a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  InsertCreatedStream(new_stream.Pass());
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "Net.SpdyPriorityCount",
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<int>(request.priority()), 0, 10, 11);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void SpdySession::CancelStreamRequest(
6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& request) {
6743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(request);
6757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DCHECK_IS_ON()) {
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |request| should not be in a queue not matching its priority.
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < NUM_PRIORITIES; ++i) {
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (request->priority() == i)
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i];
6823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DCHECK(std::find_if(queue->begin(),
6833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          queue->end(),
6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          RequestEquals(request)) == queue->end());
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PendingStreamRequestQueue* queue =
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &pending_create_stream_queues_[request->priority()];
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remove |request| from |queue| while preserving the order of the
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // other elements.
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PendingStreamRequestQueue::iterator it =
6933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      std::find_if(queue->begin(), queue->end(), RequestEquals(request));
6943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // The request may already be removed if there's a
6953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // CompleteStreamRequest() in flight.
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != queue->end()) {
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it = queue->erase(it);
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |request| should be in the queue at most once, and if it is
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // present, should not be pending completion.
7003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(std::find_if(it, queue->end(), RequestEquals(request)) ==
7013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           queue->end());
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() {
7063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (int j = NUM_PRIORITIES - 1; j >= MINIMUM_PRIORITY; --j) {
7073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (pending_create_stream_queues_[j].empty())
7083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
7113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        pending_create_stream_queues_[j].front();
7123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(pending_request);
7133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_create_stream_queues_[j].pop_front();
7143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return pending_request;
7153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
7163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return base::WeakPtr<SpdyStreamRequest>();
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::ProcessPendingStreamRequests() {
720a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Like |max_concurrent_streams_|, 0 means infinite for
721a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // |max_requests_to_process|.
722a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  size_t max_requests_to_process = 0;
723a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (max_concurrent_streams_ != 0) {
724a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    max_requests_to_process =
725a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        max_concurrent_streams_ -
726a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        (active_streams_.size() + created_streams_.size());
727a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
728a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (size_t i = 0;
729a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       max_requests_to_process == 0 || i < max_requests_to_process; ++i) {
7303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
7313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetNextPendingStreamRequest();
7323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pending_request)
733a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
7343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
7363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FROM_HERE,
7373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        base::Bind(&SpdySession::CompleteStreamRequest,
7383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                   weak_factory_.GetWeakPtr(),
7393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                   pending_request));
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::NeedsCredentials() const {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLClientSocket* ssl_socket = GetSSLClientSocket();
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ssl_socket->GetNegotiatedProtocol() < kProtoSPDY3)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ssl_socket->WasChannelIDSent();
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
75390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pooled_aliases_.insert(alias_key);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetProtocolVersion() const {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffered_spdy_framer_->protocol_version();
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
761ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbase::WeakPtr<SpdySession> SpdySession::GetWeakPtr() {
762ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return weak_factory_.GetWeakPtr();
763ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
765a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool SpdySession::CloseOneIdleConnection() {
766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(pool_);
769ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!active_streams_.empty())
770a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
771ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CloseSessionResult result =
772ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DoCloseSession(ERR_CONNECTION_CLOSED, "Closing one idle connection.");
773ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (result != SESSION_CLOSED_AND_REMOVED) {
774ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NOTREACHED();
775ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
776ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
777ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return true;
778a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
779a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
780c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueStreamWrite(
781a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream,
782c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyFrameType frame_type,
783c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<SpdyBufferProducer> producer) {
784c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(frame_type == HEADERS ||
785c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == DATA ||
786c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == CREDENTIAL ||
787c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == SYN_STREAM);
788c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream);
789c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
790c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
791c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<SpdyFrame> SpdySession::CreateSynStream(
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyStreamId stream_id,
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RequestPriority priority,
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8 credential_slot,
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyControlFlags flags,
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SpdyHeaderBlock& headers) {
797a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
798a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
799eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendPrefacePingIfNoneInFlight();
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> syn_frame(
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateSynStream(
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          stream_id, 0,
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ConvertRequestPriorityToSpdyPriority(priority, GetProtocolVersion()),
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          credential_slot, flags, enable_compression_, &headers));
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter spdy_requests("spdy.requests");
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_requests.Increment();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  streams_initiated_count_++;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdySynCallback, &headers,
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   (flags & CONTROL_FLAG_FIN) != 0,
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   stream_id, 0));
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
823c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return syn_frame.Pass();
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
826c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int SpdySession::CreateCredentialFrame(
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& origin,
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& key,
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cert,
830c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RequestPriority priority,
831c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<SpdyFrame>* credential_frame) {
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_secure_);
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLClientSocket* ssl_socket = GetSSLClientSocket();
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ssl_socket);
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ssl_socket->WasChannelIDSent());
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpdyCredential credential;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string tls_unique;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_socket->GetTLSUniqueChannelBinding(&tls_unique);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t slot = credential_state_.SetHasCredential(GURL(origin));
841bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  int rv = SpdyCredentialBuilder::Build(tls_unique, key, cert, slot,
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        &credential);
843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_NE(rv, ERR_IO_PENDING);
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != OK)
845c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return rv;
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
848c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  credential_frame->reset(
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateCredentialFrame(credential));
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SEND_CREDENTIAL,
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdyCredentialCallback, credential.slot, &origin));
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return OK;
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id,
860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     IOBuffer* data,
861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     int len,
862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     SpdyDataFlags flags) {
863ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED) {
864ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    NOTREACHED();
865ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return scoped_ptr<SpdyBuffer>();
866ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
867ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
868a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
869a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
870eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(stream->stream_id(), stream_id);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (len < 0) {
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return scoped_ptr<SpdyBuffer>();
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
878c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int effective_len = std::min(len, kMaxSpdyFrameChunkSize);
879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool send_stalled_by_stream =
881c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (flow_control_state_ >= FLOW_CONTROL_STREAM) &&
882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (stream->send_window_size() <= 0);
883c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool send_stalled_by_session = IsSendStalled();
884c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
885c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // NOTE: There's an enum of the same name in histograms.xml.
886c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  enum SpdyFrameFlowControlState {
887c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_NOT_STALLED,
888c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_STREAM,
889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_SESSION,
890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SEND_STALLED_BY_STREAM_AND_SESSION,
891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SpdyFrameFlowControlState frame_flow_control_state = SEND_NOT_STALLED;
894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (send_stalled_by_stream) {
895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_session) {
896c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      frame_flow_control_state = SEND_STALLED_BY_STREAM_AND_SESSION;
897c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
898c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      frame_flow_control_state = SEND_STALLED_BY_STREAM;
899c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
900c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (send_stalled_by_session) {
901c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    frame_flow_control_state = SEND_STALLED_BY_SESSION;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
904c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM) {
905c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
906c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Net.SpdyFrameStreamFlowControlState",
907c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        frame_flow_control_state,
908c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SEND_STALLED_BY_STREAM + 1);
909c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
910c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
911c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Net.SpdyFrameStreamAndSessionFlowControlState",
912c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        frame_flow_control_state,
913c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SEND_STALLED_BY_STREAM_AND_SESSION + 1);
914c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
915c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
916c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Obey send window size of the stream if stream flow control is
917c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // enabled.
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flow_control_state_ >= FLOW_CONTROL_STREAM) {
919c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_stream) {
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream->set_send_stalled_by_flow_control(true);
921c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Even though we're currently stalled only by the stream, we
922c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // might end up being stalled by the session also.
923a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      QueueSendStalledStream(*stream);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log().AddEvent(
925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NetLog::IntegerCallback("stream_id", stream_id));
927c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return scoped_ptr<SpdyBuffer>();
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    effective_len = std::min(effective_len, stream->send_window_size());
931c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
932c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
933c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Obey send window size of the session if session flow control is
934c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // enabled.
935c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
936c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (send_stalled_by_session) {
937c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      stream->set_send_stalled_by_flow_control(true);
938a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      QueueSendStalledStream(*stream);
939c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      net_log().AddEvent(
940c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
941c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          NetLog::IntegerCallback("stream_id", stream_id));
942c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return scoped_ptr<SpdyBuffer>();
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    effective_len = std::min(effective_len, session_send_window_size_);
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
948c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(effective_len, 0);
949c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
950c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Clear FIN flag if only some of the data will be in the data
951c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // frame.
952c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (effective_len < len)
953c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN);
954c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SEND_DATA,
958c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len,
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   (flags & DATA_FLAG_FIN) != 0));
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send PrefacePing for DATA_FRAMEs with nonzero payload size.
963c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (effective_len > 0)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendPrefacePingIfNoneInFlight();
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): reduce memory copies here.
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> frame(
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateDataFrame(
970c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          stream_id, data->data(),
971c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<uint32>(effective_len), flags));
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
973c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass()));
974c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
975c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
976c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DecreaseSendWindowSize(static_cast<int32>(effective_len));
977c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    data_buffer->AddConsumeCallback(
978c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&SpdySession::OnWriteBufferConsumed,
979c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   weak_factory_.GetWeakPtr(),
980c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   static_cast<size_t>(effective_len)));
981c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
982c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
983c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return data_buffer.Pass();
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
986a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::CloseActiveStream(SpdyStreamId stream_id, int status) {
987eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
988a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
989a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
990eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
991eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
992a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
993eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
994a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
995eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseActiveStreamIterator(it, status);
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
998a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::CloseCreatedStream(
999a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::WeakPtr<SpdyStream>& stream, int status) {
1000eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_EQ(stream->stream_id(), 0u);
1001a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1002eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CreatedStreamSet::iterator it = created_streams_.find(stream.get());
1003eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == created_streams_.end()) {
1004eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1005eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1006eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1007a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1008eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseCreatedStreamIterator(it, status);
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::ResetStream(SpdyStreamId stream_id,
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              SpdyRstStreamStatus status,
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& description) {
1014eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1016eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1017eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
1018eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1019eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1020eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1022eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResetStreamIterator(it, status, description);
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ContainsKey(active_streams_, stream_id);
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState SpdySession::GetLoadState() const {
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just report that we're idle since the session could be doing
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // many things concurrently.
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LOAD_STATE_IDLE;
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1036eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            int status) {
1037eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(mbelshe): We should send a RST_STREAM control frame here
1038eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //                so that the server can cancel a large send.
1039eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1040eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1041eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  active_streams_.erase(it);
1042eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1043ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // TODO(akalin): When SpdyStream was ref-counted (and
1044ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1045ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // was only done when status was not OK. This meant that pushed
1046ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // streams can still be claimed after they're closed. This is
1047ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // probably something that we still want to support, although server
1048ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // push is hardly used. Write tests for this and fix this. (See
1049ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // http://crbug.com/261712 .)
1050ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (owned_stream->type() == SPDY_PUSH_STREAM)
10513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    unclaimed_pushed_streams_.erase(owned_stream->url());
10523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::WeakPtr<SpdySession> weak_this = GetWeakPtr();
1054ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1055eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DeleteStream(owned_stream.Pass(), status);
10563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!weak_this)
10583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
10593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (availability_state_ == STATE_CLOSED)
10613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
10623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If there are no active streams and the socket pool is stalled, close the
10643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // session to free up a socket slot.
10653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (active_streams_.empty() && connection_->IsPoolStalled()) {
10663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseSessionResult result =
10673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        DoCloseSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
10683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_NE(result, SESSION_ALREADY_CLOSED);
10693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1071eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1072eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
1073eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                             int status) {
1074eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyStream> owned_stream(*it);
1075eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  created_streams_.erase(it);
1076eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DeleteStream(owned_stream.Pass(), status);
1077eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1078eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1079eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
1080eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      SpdyRstStreamStatus status,
1081eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      const std::string& description) {
1082bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Send the RST_STREAM frame first as CloseActiveStreamIterator()
1083bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // may close us.
1084eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStreamId stream_id = it->first;
1085eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RequestPriority priority = it->second.stream->priority();
1086bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  EnqueueResetStreamFrame(stream_id, priority, status, description);
1087bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1088eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Removes any pending writes for the stream except for possibly an
1089eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // in-flight one.
1090eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
1091eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1092eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1093bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
1094bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          RequestPriority priority,
1095bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          SpdyRstStreamStatus status,
1096bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                          const std::string& description) {
1097eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_NE(stream_id, 0u);
1098eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1099eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  net_log().AddEvent(
1100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM,
1101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
1102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(buffered_spdy_framer_.get());
1104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<SpdyFrame> rst_frame(
1105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      buffered_spdy_framer_->CreateRstStream(stream_id, status));
1106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass());
1108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RecordProtocolErrorHistogram(
1109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID));
1110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
1113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(read_state_, expected_read_state);
1116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  result = DoReadLoop(expected_read_state, result);
1118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED) {
1120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, error_on_close_);
1121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    RemoveFromPool();
1123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1124ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1126ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(result == OK || result == ERR_IO_PENDING);
11279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
1130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(read_state_, expected_read_state);
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = true;
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int bytes_read_without_yielding = 0;
1137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Loop until the session is closed, the read becomes blocked, or
1139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // the read limit is exceeded.
1140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (true) {
1141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    switch (read_state_) {
1142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case READ_STATE_DO_READ:
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DCHECK_EQ(result, OK);
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = DoRead();
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case READ_STATE_DO_READ_COMPLETE:
1147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (result > 0)
1148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          bytes_read_without_yielding += result;
11492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result = DoReadComplete(result);
11502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
1152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        NOTREACHED() << "read_state_: " << read_state_;
11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
11542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (availability_state_ == STATE_CLOSED) {
1157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, error_on_close_);
1158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_LT(result, ERR_IO_PENDING);
1159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result == ERR_IO_PENDING)
1163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (bytes_read_without_yielding > kMaxReadBytesWithoutYielding) {
1166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      read_state_ = READ_STATE_DO_READ;
1167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MessageLoop::current()->PostTask(
1168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          FROM_HERE,
1169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          base::Bind(&SpdySession::PumpReadLoop,
1170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                     weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
1171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      result = ERR_IO_PENDING;
1172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1173ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1174ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1176ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1177ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = false;
11782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return result;
11802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::DoRead() {
1183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
11852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CHECK(connection_);
11872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(connection_->socket());
1188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  read_state_ = READ_STATE_DO_READ_COMPLETE;
11892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return connection_->socket()->Read(
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      read_buffer_.get(),
11912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kReadBufferSize,
1192ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&SpdySession::PumpReadLoop,
1193ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE));
11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SpdySession::DoReadComplete(int result) {
1197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse a frame.  For now this code requires that the frame fit into our
1201ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // buffer (kReadBufferSize).
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): support arbitrarily large frames!
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (result == 0) {
1205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
1206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                total_bytes_received_, 1, 100000000, 50);
1207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult close_session_result =
1208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(ERR_CONNECTION_CLOSED, "Connection closed");
1209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(availability_state_, STATE_CLOSED);
1211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(error_on_close_, ERR_CONNECTION_CLOSED);
12122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ERR_CONNECTION_CLOSED;
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (result < 0) {
1216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult close_session_result =
1217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(static_cast<Error>(result), "result is < 0.");
1218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(availability_state_, STATE_CLOSED);
1220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(error_on_close_, result);
1221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return result;
1222ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1223ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  total_bytes_received_ += result;
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  last_activity_time_ = time_func_();
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  char* data = read_buffer_->data();
1230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (result > 0) {
1231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    uint32 bytes_processed = buffered_spdy_framer_->ProcessInput(data, result);
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result -= bytes_processed;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data += bytes_processed;
1234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (availability_state_ == STATE_CLOSED) {
1236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1237ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return error_on_close_;
1238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
12399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(buffered_spdy_framer_->error_code(), SpdyFramer::SPDY_NO_ERROR);
1241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  read_state_ = READ_STATE_DO_READ;
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return OK;
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::PumpWriteLoop(WriteState expected_write_state, int result) {
1248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1249ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1250ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, expected_write_state);
1251ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1252ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  result = DoWriteLoop(expected_write_state, result);
1253ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1254ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED) {
1255ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, error_on_close_);
1256ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1257ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    RemoveFromPool();
1258ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1259ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(result == OK || result == ERR_IO_PENDING);
1262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1264ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWriteLoop(WriteState expected_write_state, int result) {
1265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
1266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(write_state_, WRITE_STATE_IDLE);
1268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(write_state_, expected_write_state);
1269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1270ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = true;
1271ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1272ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Loop until the session is closed or the write becomes blocked.
1273ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (true) {
1274ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    switch (write_state_) {
1275ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_DO_WRITE:
1276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DCHECK_EQ(result, OK);
1277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        result = DoWrite();
1278ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1279ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_DO_WRITE_COMPLETE:
1280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        result = DoWriteComplete(result);
1281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1282ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      case WRITE_STATE_IDLE:
1283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      default:
1284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        NOTREACHED() << "write_state_: " << write_state_;
1285ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (availability_state_ == STATE_CLOSED) {
1289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, error_on_close_);
1290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_LT(result, ERR_IO_PENDING);
1291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (write_state_ == WRITE_STATE_IDLE) {
1295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, ERR_IO_PENDING);
1296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1297ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1298ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result == ERR_IO_PENDING)
1300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1304ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  in_io_loop_ = false;
1305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return result;
1307ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1309ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWrite() {
1310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1311ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(buffered_spdy_framer_);
1314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (in_flight_write_) {
1315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
1316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
1317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Grab the next frame to send.
1318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    SpdyFrameType frame_type = DATA;
1319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    scoped_ptr<SpdyBufferProducer> producer;
1320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::WeakPtr<SpdyStream> stream;
1321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!write_queue_.Dequeue(&frame_type, &producer, &stream)) {
1322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_state_ = WRITE_STATE_IDLE;
1323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return ERR_IO_PENDING;
1324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1325ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (stream.get())
1327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK(!stream->IsClosed());
1328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Activate the stream only when sending the SYN_STREAM frame to
1330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // guarantee monotonically-increasing stream IDs.
1331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (frame_type == SYN_STREAM) {
1332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (stream.get() && stream->stream_id() == 0) {
1333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        scoped_ptr<SpdyStream> owned_stream =
1334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            ActivateCreatedStream(stream.get());
1335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        InsertActivatedStream(owned_stream.Pass());
1336ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      } else {
1337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        NOTREACHED();
1338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        return ERR_UNEXPECTED;
1339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
1340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_ = producer->ProduceBuffer();
1343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!in_flight_write_) {
1344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      NOTREACHED();
1345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return ERR_UNEXPECTED;
1346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_frame_type_ = frame_type;
1348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
1349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_GE(in_flight_write_frame_size_,
1350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              buffered_spdy_framer_->GetFrameMinimumSize());
1351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    in_flight_write_stream_ = stream;
1352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  write_state_ = WRITE_STATE_DO_WRITE_COMPLETE;
1355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
1357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // with Socket implementations that don't store their IOBuffer
1358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
1359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  scoped_refptr<IOBuffer> write_io_buffer =
1360ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      in_flight_write_->GetIOBufferForRemainingData();
1361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return connection_->socket()->Write(
1362ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      write_io_buffer.get(),
1363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      in_flight_write_->GetRemainingSize(),
1364ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&SpdySession::PumpWriteLoop,
1365ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE_COMPLETE));
1366ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1367ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1368ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint SpdySession::DoWriteComplete(int result) {
1369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
1371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(result, ERR_IO_PENDING);
1372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1374ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  last_activity_time_ = time_func_();
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (result < 0) {
1377ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_NE(result, ERR_IO_PENDING);
1378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_.reset();
1379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_frame_type_ = DATA;
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_frame_size_ = 0;
1381a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    in_flight_write_stream_.reset();
1382ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult close_session_result =
1383ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(static_cast<Error>(result), "Write error");
1384ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1385ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(availability_state_, STATE_CLOSED);
1386ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(error_on_close_, result);
1387ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return result;
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It should not be possible to have written more bytes than our
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in_flight_write_.
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(static_cast<size_t>(result),
1393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_->GetRemainingSize());
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (result > 0) {
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    in_flight_write_->Consume(static_cast<size_t>(result));
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only notify the stream when we've fully written the pending frame.
1399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (in_flight_write_->GetRemainingSize() == 0) {
1400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // It is possible that the stream was cancelled while we were
1401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // writing to the socket.
1402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (in_flight_write_stream_.get()) {
1403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DCHECK_GT(in_flight_write_frame_size_, 0u);
1404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        in_flight_write_stream_->OnFrameWriteComplete(
1405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_frame_type_,
1406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            in_flight_write_frame_size_);
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Cleanup the write which just completed.
1410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_.reset();
1411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_type_ = DATA;
1412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_flight_write_frame_size_ = 0;
1413a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      in_flight_write_stream_.reset();
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  write_state_ = WRITE_STATE_DO_WRITE;
1418ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return OK;
14199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
14209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1421ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::DcheckGoingAway() const {
1422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (DCHECK_IS_ON()) {
1424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for (int i = 0; i < NUM_PRIORITIES; ++i) {
1425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK(pending_create_stream_queues_[i].empty());
14269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    }
14279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
1428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(created_streams_.empty());
1429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::DcheckClosed() const {
1432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckGoingAway();
1433ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(availability_state_, STATE_CLOSED);
1434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(active_streams_.empty());
1436ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(unclaimed_pushed_streams_.empty());
1437ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(write_queue_.IsEmpty());
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1440ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::StartGoingAway(SpdyStreamId last_good_stream_id,
1441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                 Error status) {
1442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1443bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // The loops below are carefully written to avoid reentrancy problems.
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  while (true) {
14473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = GetTotalSize(pending_create_stream_queues_);
14483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::WeakPtr<SpdyStreamRequest> pending_request =
14493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetNextPendingStreamRequest();
14503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!pending_request)
14513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
14523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new stream requests should be added while the session is
14533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // going away.
14543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_));
14553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_request->OnRequestCompleteFailure(ERR_ABORTED);
1456ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
14577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
14587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  while (true) {
14593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = active_streams_.size();
14607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    ActiveStreamMap::iterator it =
14617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        active_streams_.lower_bound(last_good_stream_id + 1);
14627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (it == active_streams_.end())
14637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
1464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LogAbandonedActiveStream(it, status);
1465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, status);
14663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new streams should be activated while the session is going
14673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // away.
14683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, active_streams_.size());
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!created_streams_.empty()) {
14723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t old_size = created_streams_.size();
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreatedStreamSet::iterator it = created_streams_.begin();
1474a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    LogAbandonedStream(*it, status);
1475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseCreatedStreamIterator(it, status);
14763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // No new streams should be created while the session is going
14773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // away.
14783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_GT(old_size, created_streams_.size());
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id);
1482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1483ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckGoingAway();
1484ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1486ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::MaybeFinishGoingAway() {
1487ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckGoingAway();
1488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (active_streams_.empty() && availability_state_ != STATE_CLOSED) {
1489ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result =
1490ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(ERR_CONNECTION_CLOSED, "Finished going away");
1491ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_NE(result, SESSION_ALREADY_CLOSED);
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1493ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1495ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochSpdySession::CloseSessionResult SpdySession::DoCloseSession(
1496ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    Error err,
1497ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const std::string& description) {
1498ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_LT(err, ERR_IO_PENDING);
1499ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1500ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1501ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return SESSION_ALREADY_CLOSED;
1502ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1503ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  net_log_.AddEvent(
1504ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      NetLog::TYPE_SPDY_SESSION_CLOSE,
1505ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
1506ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1507ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err);
1508ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.OtherErrors",
1509ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                              total_bytes_received_, 1, 100000000, 50);
1510ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1511ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // |pool_| will be NULL when |InitializeWithSocket()| is in the
1512ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // call stack.
1513ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (pool_ && availability_state_ != STATE_GOING_AWAY)
1514ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pool_->MakeSessionUnavailable(GetWeakPtr());
1515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1516ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  availability_state_ = STATE_CLOSED;
1517ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  error_on_close_ = err;
1518ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1519ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  StartGoingAway(0, err);
1520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_queue_.Clear();
1521ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1522ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckClosed();
1523ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1524ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (in_io_loop_)
1525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return SESSION_CLOSED_BUT_NOT_REMOVED;
1526ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1527ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  RemoveFromPool();
1528ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return SESSION_CLOSED_AND_REMOVED;
1529ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1530ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1531ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::RemoveFromPool() {
1532ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DcheckClosed();
1533ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(pool_);
1534ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1535ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  SpdySessionPool* pool = pool_;
1536ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pool_ = NULL;
1537ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pool->RemoveUnavailableSession(GetWeakPtr());
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1540a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) {
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(stream);
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description = base::StringPrintf(
1543ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      "ABANDONED (stream_id=%d): ", stream->stream_id()) +
1544ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      stream->url().spec();
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream->LogStreamError(status, description);
1546ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We don't increment the streams abandoned counter here. If the
1547ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // stream isn't active (i.e., it hasn't written anything to the wire
1548ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // yet) then it's as if it never existed. If it is active, then
1549ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // LogAbandonedActiveStream() will increment the counters.
1550ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1551ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1552ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
1553ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                           Error status) {
1554ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_GT(it->first, 0u);
1555ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  LogAbandonedStream(it->second.stream, status);
1556ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ++streams_abandoned_count_;
1557ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::StatsCounter abandoned_streams("spdy.abandoned_streams");
1558ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  abandoned_streams.Increment();
1559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (it->second.stream->type() == SPDY_PUSH_STREAM &&
1560ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.find(it->second.stream->url()) !=
1561ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.end()) {
1562ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::StatsCounter abandoned_push_streams("spdy.abandoned_push_streams");
1563ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    abandoned_push_streams.Increment();
1564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetNewStreamId() {
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int id = stream_hi_water_mark_;
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_hi_water_mark_ += 2;
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stream_hi_water_mark_ > 0x7fff)
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_hi_water_mark_ = 1;
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id;
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::CloseSessionOnError(Error err,
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& description) {
1577ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We may be called from anywhere, so we can't expect a particular
1578ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // return value.
1579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ignore_result(DoCloseSession(err, description));
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Value* SpdySession::GetInfoAsValue() const {
15832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("source_id", net_log_.source().id);
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dict->SetString("host_port_pair", host_port_pair().ToString());
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pooled_aliases_.empty()) {
15892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* alias_list = new base::ListValue();
159090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (std::set<SpdySessionKey>::const_iterator it =
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             pooled_aliases_.begin();
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         it != pooled_aliases_.end(); it++) {
159390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      alias_list->Append(new base::StringValue(
159490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          it->host_port_pair().ToString()));
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->Set("aliases", alias_list);
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
159890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dict->SetString("proxy", host_port_proxy_pair().second.ToURI());
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("active_streams", active_streams_.size());
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("unclaimed_pushed_streams",
1603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   unclaimed_pushed_streams_.size());
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("is_secure", is_secure_);
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("protocol_negotiated",
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  SSLClientSocket::NextProtoToString(
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      connection_->socket()->GetNegotiatedProtocol()));
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1611ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dict->SetInteger("error", error_on_close_);
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("max_concurrent_streams", max_concurrent_streams_);
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_initiated_count", streams_initiated_count_);
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_pushed_count", streams_pushed_count_);
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_pushed_and_claimed_count",
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      streams_pushed_and_claimed_count_);
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("streams_abandoned_count", streams_abandoned_count_);
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("frames_received", buffered_spdy_framer_->frames_received());
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("sent_settings", sent_settings_);
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("received_settings", received_settings_);
16242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("send_window_size", session_send_window_size_);
16262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("recv_window_size", session_recv_window_size_);
16272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict->SetInteger("unacked_recv_window_bytes",
16282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   session_unacked_recv_window_bytes_);
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::IsReused() const {
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffered_spdy_framer_->frames_received() > 0;
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id,
16372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    LoadTimingInfo* load_timing_info) const {
16382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return connection_->GetLoadTimingInfo(stream_id != kFirstStreamId,
16392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        load_timing_info);
16402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
16412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SpdySession::GetPeerAddress(IPEndPoint* address) const {
1643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int rv = ERR_SOCKET_NOT_CONNECTED;
1644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
1645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    rv = connection_->socket()->GetPeerAddress(address);
16462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetPeerAddress",
1649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        rv == ERR_SOCKET_NOT_CONNECTED);
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return rv;
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int SpdySession::GetLocalAddress(IPEndPoint* address) const {
1655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int rv = ERR_SOCKET_NOT_CONNECTED;
1656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->socket()) {
1657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    rv = connection_->socket()->GetLocalAddress(address);
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetLocalAddress",
1661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        rv == ERR_SOCKET_NOT_CONNECTED);
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return rv;
1664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueSessionWrite(RequestPriority priority,
1667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      SpdyFrameType frame_type,
1668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      scoped_ptr<SpdyFrame> frame) {
1669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(frame_type == RST_STREAM ||
1670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == SETTINGS ||
1671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == WINDOW_UPDATE ||
1672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         frame_type == PING);
1673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueWrite(
1674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      priority, frame_type,
1675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_ptr<SpdyBufferProducer>(
1676c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          new SimpleBufferProducer(
1677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              scoped_ptr<SpdyBuffer>(new SpdyBuffer(frame.Pass())))),
1678a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::WeakPtr<SpdyStream>());
1679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::EnqueueWrite(RequestPriority priority,
1682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               SpdyFrameType frame_type,
1683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               scoped_ptr<SpdyBufferProducer> producer,
1684a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                               const base::WeakPtr<SpdyStream>& stream) {
1685ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1686ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1688ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool was_idle = write_queue_.IsEmpty();
1689c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_queue_.Enqueue(priority, frame_type, producer.Pass(), stream);
1690ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (write_state_ == WRITE_STATE_IDLE) {
1691ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK(was_idle);
1692ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK(!in_flight_write_);
1693ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    write_state_ = WRITE_STATE_DO_WRITE;
1694ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::MessageLoop::current()->PostTask(
1695ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        FROM_HERE,
1696ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        base::Bind(&SpdySession::PumpWriteLoop,
1697ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE, OK));
1698ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1701a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::InsertCreatedStream(scoped_ptr<SpdyStream> stream) {
1702a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK_EQ(stream->stream_id(), 0u);
1703a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(created_streams_.find(stream.get()) == created_streams_.end());
1704a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  created_streams_.insert(stream.release());
1705a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1707a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)scoped_ptr<SpdyStream> SpdySession::ActivateCreatedStream(SpdyStream* stream) {
1708a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK_EQ(stream->stream_id(), 0u);
1709a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(created_streams_.find(stream) != created_streams_.end());
1710a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream->set_stream_id(GetNewStreamId());
1711a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SpdyStream> owned_stream(stream);
1712a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  created_streams_.erase(stream);
1713a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return owned_stream.Pass();
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1716a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1717a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SpdyStreamId stream_id = stream->stream_id();
1718a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK_NE(stream_id, 0u);
1719a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  std::pair<ActiveStreamMap::iterator, bool> result =
1720eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      active_streams_.insert(
1721eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
1722a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (result.second) {
1723a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    ignore_result(stream.release());
1724a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
1725a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    NOTREACHED();
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1727a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1729a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
1730868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (in_flight_write_stream_.get() == stream.get()) {
1731a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // If we're deleting the stream for the in-flight write, we still
1732a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // need to let the write complete, so we clear
1733a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // |in_flight_write_stream_| and let the write finish on its own
1734a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // without notifying |in_flight_write_stream_|.
1735a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    in_flight_write_stream_.reset();
1736a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
1737c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1738a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  write_queue_.RemovePendingWritesForStream(stream->GetWeakPtr());
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1740bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // |stream->OnClose()| may end up closing |this|, so detect that.
1741bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::WeakPtr<SpdySession> weak_this = GetWeakPtr();
1742bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
17432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stream->OnClose(status);
1744a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1745bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (!weak_this)
1746bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    return;
1747bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1748ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  switch (availability_state_) {
1749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    case STATE_AVAILABLE:
1750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      ProcessPendingStreamRequests();
1751ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    case STATE_GOING_AWAY:
1753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DcheckGoingAway();
1754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      MaybeFinishGoingAway();
1755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1756ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    case STATE_CLOSED:
1757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      // Do nothing.
1758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1762ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbase::WeakPtr<SpdyStream> SpdySession::GetActivePushStream(const GURL& url) {
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter used_push_streams("spdy.claimed_push_streams");
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PushedStreamMap::iterator unclaimed_it = unclaimed_pushed_streams_.find(url);
1766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (unclaimed_it == unclaimed_pushed_streams_.end())
1767eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return base::WeakPtr<SpdyStream>();
1768eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1769ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  SpdyStreamId stream_id = unclaimed_it->second.stream_id;
1770ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  unclaimed_pushed_streams_.erase(unclaimed_it);
1771eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1772ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
1773ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (active_it == active_streams_.end()) {
1774eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
1775eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return base::WeakPtr<SpdyStream>();
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1778eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM);
1779eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  used_push_streams.Increment();
1780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return active_it->second.stream->GetWeakPtr();
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::GetSSLInfo(SSLInfo* ssl_info,
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             bool* was_npn_negotiated,
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             NextProto* protocol_negotiated) {
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *was_npn_negotiated = connection_->socket()->WasNpnNegotiated();
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *protocol_negotiated = connection_->socket()->GetNegotiatedProtocol();
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return connection_->socket()->GetSSLInfo(ssl_info);
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdySession::GetSSLCertRequestInfo(
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SSLCertRequestInfo* cert_request_info) {
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetSSLClientSocket()->GetSSLCertRequestInfo(cert_request_info);
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServerBoundCertService* SpdySession::GetServerBoundCertService() const {
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetSSLClientSocket()->GetServerBoundCertService();
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
1806ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1807ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1809ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1810ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordProtocolErrorHistogram(
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<SpdyProtocolErrorDetails>(error_code));
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description = base::StringPrintf(
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SPDY_ERROR error_code: %d.", error_code);
1815ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CloseSessionResult result =
1816ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DoCloseSession(ERR_SPDY_PROTOCOL_ERROR, description);
1817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnStreamError(SpdyStreamId stream_id,
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& description) {
1822ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1825ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1826ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1827eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1828eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == active_streams_.end()) {
1829eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // We still want to send a frame to reset the stream even if we
1830eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // don't know anything about it.
1831bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(
1832eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        stream_id, IDLE, RST_STREAM_PROTOCOL_ERROR, description);
1833eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1834eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1835eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1836eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, description);
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const char* data,
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    size_t len,
18422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    bool fin) {
1843ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1844ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1845ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1846ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1847ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(len, 1u << 24);
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_DATA,
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&NetLogSpdyDataCallback, stream_id, len, fin));
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Build the buffer as early as possible so that we go through the
1856c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // session flow control checks and update
1857c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // |unacked_recv_window_bytes_| properly even when the stream is
1858c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // inactive (since the other side has still reduced its session send
1859c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // window).
1860c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  scoped_ptr<SpdyBuffer> buffer;
1861c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (data) {
1862c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    DCHECK_GT(len, 0u);
1863c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    buffer.reset(new SpdyBuffer(data, len));
1864c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1865c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
1866c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      DecreaseRecvWindowSize(static_cast<int32>(len));
1867c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      buffer->AddConsumeCallback(
1868c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch          base::Bind(&SpdySession::OnReadBufferConsumed,
1869c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                     weak_factory_.GetWeakPtr()));
1870c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
1871c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else {
1872c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    DCHECK_EQ(len, 0u);
1873c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
1874c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1875eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
18772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // By the time data comes in, the stream may already be inactive.
1878c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (it == active_streams_.end())
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1881eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
1882eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(stream->stream_id(), stream_id);
1883eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1884eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it->second.waiting_for_syn_reply) {
1885eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& error = "Data received before SYN_REPLY.";
1886eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
1887eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
1888eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1889eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1890eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1891eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  stream->OnDataReceived(buffer.Pass());
1892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnSettings(bool clear_persisted) {
1895ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1896ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1897ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1898ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1899ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1900c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (clear_persisted)
1901c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    http_server_properties_->ClearSpdySettings(host_port_pair());
1902c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1903c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (net_log_.IsLoggingAllEvents()) {
1904c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    net_log_.AddEvent(
1905c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS,
1906c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::Bind(&NetLogSpdySettingsCallback, host_port_pair(),
1907c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   clear_persisted));
1908c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSetting(SpdySettingsIds id,
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint8 flags,
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            uint32 value) {
1914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1915ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1916ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1917ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1918ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleSetting(id, value);
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_server_properties_->SetSpdySetting(
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_port_pair(),
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id,
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<SpdySettingsFlags>(flags),
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value);
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  received_settings_ = true;
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Log the setting.
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_RECV_SETTING,
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdySettingCallback,
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 id, static_cast<SpdySettingsFlags>(flags), value));
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SpdySession::OnSendCompressedFrame(
19357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SpdyStreamId stream_id,
19367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SpdyFrameType type,
19377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t payload_len,
19387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t frame_len) {
19397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (type != SYN_STREAM)
19407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(buffered_spdy_framer_.get());
19437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t compressed_len =
19447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      frame_len - buffered_spdy_framer_->GetSynStreamMinimumSize();
19457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
19467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (payload_len) {
19477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Make sure we avoid early decimal truncation.
19487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int compression_pct = 100 - (100 * compressed_len) / payload_len;
19497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    UMA_HISTOGRAM_PERCENTAGE("Net.SpdySynStreamCompressionPercentage",
19507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                             compression_pct);
19517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
19527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1954eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint SpdySession::OnInitialResponseHeadersReceived(
1955eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SpdyHeaderBlock& response_headers,
1956eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::Time response_time,
1957eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::TimeTicks recv_first_byte_time,
1958eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStream* stream) {
1959ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1960a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SpdyStreamId stream_id = stream->stream_id();
1961a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // May invalidate |stream|.
1962eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rv = stream->OnInitialResponseHeadersReceived(
1963eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      response_headers, response_time, recv_first_byte_time);
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv < 0) {
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(rv, ERR_IO_PENDING);
1966eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(active_streams_.find(stream_id) == active_streams_.end());
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1968eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return rv;
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSynStream(SpdyStreamId stream_id,
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              SpdyStreamId associated_stream_id,
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              SpdyPriority priority,
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              uint8 credential_slot,
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool fin,
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool unidirectional,
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const SpdyHeaderBlock& headers) {
1978ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
1979ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1980ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
1981ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
1982ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1983eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Time response_time = base::Time::Now();
1984ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks recv_first_byte_time = time_func_();
1985eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log_.IsLoggingAllEvents()) {
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log_.AddEvent(
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM,
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdySynCallback,
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &headers, fin, unidirectional,
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   stream_id, associated_stream_id));
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Server-initiated streams should have even sequence numbers.
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((stream_id & 0x1) != 0) {
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received invalid OnSyn stream id " << stream_id;
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsStreamActive(stream_id)) {
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received OnSyn for active stream " << stream_id;
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  RequestPriority request_priority =
2006a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion());
2007a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2008ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_GOING_AWAY) {
2009ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // TODO(akalin): This behavior isn't in the SPDY spec, although it
2010ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // probably should be.
2011bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(stream_id, request_priority,
2012bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                            RST_STREAM_REFUSED_STREAM,
2013bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                            "OnSyn received when going away");
2014ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2015ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
2016ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (associated_stream_id == 0) {
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string description = base::StringPrintf(
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Received invalid OnSyn associated stream id %d for stream %d",
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        associated_stream_id, stream_id);
2021bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(stream_id, request_priority,
2022bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                            RST_STREAM_REFUSED_STREAM, description);
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  streams_pushed_count_++;
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): DCHECK that this is a GET method?
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the response had a URL for us.
20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true);
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gurl.is_valid()) {
2033bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(
2034bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR,
2035bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        "Pushed stream url was invalid: " + gurl.spec());
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify we have a valid stream association.
2040a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator associated_it =
2041a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      active_streams_.find(associated_stream_id);
2042a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (associated_it == active_streams_.end()) {
2043bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(
2044eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        stream_id, request_priority, RST_STREAM_INVALID_STREAM,
2045eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::StringPrintf(
2046eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            "Received OnSyn with inactive associated stream %d",
2047eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            associated_stream_id));
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that the SYN advertises the same origin as its associated stream.
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bypass this check if and only if this session is with a SPDY proxy that
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is trusted explicitly via the --trusted-spdy-proxy switch.
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (trusted_spdy_proxy_.Equals(host_port_pair())) {
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Disallow pushing of HTTPS content.
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (gurl.SchemeIs("https")) {
2057bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      EnqueueResetStreamFrame(
2058eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          stream_id, request_priority, RST_STREAM_REFUSED_STREAM,
2059eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::StringPrintf(
2060eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              "Rejected push of Cross Origin HTTPS content %d",
2061eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              associated_stream_id));
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2064ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    GURL associated_url(associated_it->second.stream->GetUrlFromHeaders());
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (associated_url.GetOrigin() != gurl.GetOrigin()) {
2066bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      EnqueueResetStreamFrame(
2067eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          stream_id, request_priority, RST_STREAM_REFUSED_STREAM,
2068eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::StringPrintf(
2069eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              "Rejected Cross Origin Push Stream %d",
2070eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              associated_stream_id));
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There should not be an existing pushed stream with the same path.
2076ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PushedStreamMap::iterator pushed_it =
2077ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.lower_bound(gurl);
2078ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (pushed_it != unclaimed_pushed_streams_.end() &&
2079ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pushed_it->first == gurl) {
2080bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    EnqueueResetStreamFrame(
2081bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR,
2082bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        "Received duplicate pushed stream with url: " +
2083bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        gurl.spec());
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2087a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SpdyStream> stream(
2088ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl,
208990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     request_priority,
20902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     stream_initial_send_window_size_,
20912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     stream_initial_recv_window_size_,
209290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     net_log_));
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream->set_stream_id(stream_id);
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteExpiredPushedStreams();
2096ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PushedStreamMap::iterator inserted_pushed_it =
2097ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      unclaimed_pushed_streams_.insert(
2098ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          pushed_it,
2099ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_())));
2100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(inserted_pushed_it != pushed_it);
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  InsertActivatedStream(stream.Pass());
2103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
2105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (active_it == active_streams_.end()) {
2106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    NOTREACHED();
2107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
2108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse the headers.
2111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (OnInitialResponseHeadersReceived(
2112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          headers, response_time,
2113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          recv_first_byte_time, active_it->second.stream) != OK)
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StatsCounter push_requests("spdy.pushed_streams");
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_requests.Increment();
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::DeleteExpiredPushedStreams() {
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unclaimed_pushed_streams_.empty())
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that adequate time has elapsed since the last sweep.
21252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (time_func_() < next_unclaimed_push_stream_sweep_time_)
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Gather old streams to delete.
21292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks minimum_freshness = time_func_() -
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
2131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<SpdyStreamId> streams_to_close;
2132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (PushedStreamMap::iterator it = unclaimed_pushed_streams_.begin();
2133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != unclaimed_pushed_streams_.end(); ++it) {
2134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (minimum_freshness > it->second.creation_time)
2135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      streams_to_close.push_back(it->second.stream_id);
2136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (std::vector<SpdyStreamId>::const_iterator to_close_it =
2139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch           streams_to_close.begin();
2140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       to_close_it != streams_to_close.end(); ++to_close_it) {
2141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ActiveStreamMap::iterator active_it = active_streams_.find(*to_close_it);
2142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (active_it == active_streams_.end())
2143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
2144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LogAbandonedActiveStream(active_it, ERR_INVALID_SPDY_STREAM);
2146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // CloseActiveStreamIterator() will remove the stream from
2147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // |unclaimed_pushed_streams_|.
2148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseActiveStreamIterator(active_it, ERR_INVALID_SPDY_STREAM);
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
21512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  next_unclaimed_push_stream_sweep_time_ = time_func_() +
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnSynReply(SpdyStreamId stream_id,
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             bool fin,
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const SpdyHeaderBlock& headers) {
2158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Time response_time = base::Time::Now();
2164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks recv_first_byte_time = time_func_();
2165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_SYN_REPLY,
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdySynCallback,
21702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   &headers, fin, false,  // not unidirectional
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   stream_id, 0));
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(stream->stream_id(), stream_id);
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!it->second.waiting_for_syn_reply) {
2184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& error =
2185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Received duplicate SYN_REPLY for stream.";
2186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
2187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ResetStreamIterator(it, RST_STREAM_STREAM_IN_USE, error);
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  it->second.waiting_for_syn_reply = false;
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ignore_result(OnInitialResponseHeadersReceived(
2193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      headers, response_time, recv_first_byte_time, stream));
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnHeaders(SpdyStreamId stream_id,
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            bool fin,
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const SpdyHeaderBlock& headers) {
2199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2201ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_RECV_HEADERS,
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdySynCallback,
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &headers, fin, /*unidirectional=*/false,
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   stream_id, 0));
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2212a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2213a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id;
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SpdyStream* stream = it->second.stream;
2220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(stream->stream_id(), stream_id);
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rv = stream->OnAdditionalResponseHeadersReceived(headers);
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv < 0) {
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(rv, ERR_IO_PENDING);
2225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(active_streams_.find(stream_id) == active_streams_.end());
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::OnRstStream(SpdyStreamId stream_id,
22302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              SpdyRstStreamStatus status) {
2231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description;
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log().AddEvent(
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_RST_STREAM,
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdyRstCallback,
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 stream_id, status, &description));
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it == active_streams_.end()) {
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE:  it may just be that the stream was cancelled.
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Received RST for invalid stream" << stream_id;
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2248a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == 0) {
2252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->OnDataReceived(scoped_ptr<SpdyBuffer>());
22532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (status == RST_STREAM_REFUSED_STREAM) {
2254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM);
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM);
2258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->LogStreamError(
22592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ERR_SPDY_PROTOCOL_ERROR,
22602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf("SPDY stream closed with status: %d", status));
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(mbelshe): Map from Spdy-protocol errors to something sensical.
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //                For now, it doesn't matter much - it is a protocol error.
2263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           SpdyGoAwayStatus status) {
2269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2270ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2271ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2272ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2273ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY,
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdyGoAwayCallback,
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 last_accepted_stream_id,
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 active_streams_.size(),
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 unclaimed_pushed_streams_.size(),
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 status));
2280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ < STATE_GOING_AWAY) {
2281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    availability_state_ = STATE_GOING_AWAY;
2282ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // |pool_| will be NULL when |InitializeWithSocket()| is in the
2283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // call stack.
2284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (pool_)
2285ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pool_->MakeSessionUnavailable(GetWeakPtr());
2286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
2287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  StartGoingAway(last_accepted_stream_id, ERR_ABORTED);
2288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // This is to handle the case when we already don't have any active
2289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // streams (i.e., StartGoingAway() did nothing). Otherwise, we have
2290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // active streams and so the last one being closed will finish the
2291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // going away process (see DeleteStream()).
2292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  MaybeFinishGoingAway();
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnPing(uint32 unique_id) {
2296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2297ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2298ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_PING,
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogSpdyPingCallback, unique_id, "received"));
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send response to a PING from server.
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unique_id % 2 == 0) {
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WritePingFrame(unique_id);
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --pings_in_flight_;
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ < 0) {
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING);
2314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result =
2315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(ERR_SPDY_PROTOCOL_ERROR, "pings_in_flight_ is < 0.");
2316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pings_in_flight_ = 0;
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ > 0)
23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We will record RTT in histogram when there are no more client sent
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pings_in_flight_.
2326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  RecordPingRTTHistogram(time_func_() - last_ping_sent_time_);
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
23302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 uint32 delta_window_size) {
2331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
23362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(delta_window_size, static_cast<uint32>(kint32max));
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
23382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
23392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 stream_id, delta_window_size));
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2342a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (stream_id == kSessionFlowControlStreamId) {
2343a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // WINDOW_UPDATE for the session.
2344a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (flow_control_state_ < FLOW_CONTROL_STREAM_AND_SESSION) {
2345a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for session when "
2346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   << "session flow control is not turned on";
2347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      // TODO(akalin): Record an error and close the session.
2348a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2349a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
23502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2351a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (delta_window_size < 1u) {
2352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
2353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CloseSessionResult result = DoCloseSession(
2354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ERR_SPDY_PROTOCOL_ERROR,
2355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          "Received WINDOW_UPDATE with an invalid delta_window_size " +
2356a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          base::UintToString(delta_window_size));
2357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
2358a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2359a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2360a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2361a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    IncreaseSendWindowSize(static_cast<int32>(delta_window_size));
2362a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
2363a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // WINDOW_UPDATE for a stream.
2364a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (flow_control_state_ < FLOW_CONTROL_STREAM) {
2365a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      // TODO(akalin): Record an error and close the session.
2366a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for stream " << stream_id
2367a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   << " when flow control is not turned on";
2368a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2369a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2372a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2373a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (it == active_streams_.end()) {
2374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // NOTE:  it may just be that the stream was cancelled.
2375a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
2376a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
2377a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
2378a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SpdyStream* stream = it->second.stream;
2380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(stream->stream_id(), stream_id);
2381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2382a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (delta_window_size < 1u) {
2383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ResetStreamIterator(it,
2384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          RST_STREAM_FLOW_CONTROL_ERROR,
2385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          base::StringPrintf(
2386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              "Received WINDOW_UPDATE with an invalid "
2387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              "delta_window_size %ud", delta_window_size));
2388a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return;
23892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(it->second.stream->stream_id(), stream_id);
2392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->IncreaseSendWindowSize(
2393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        static_cast<int32>(delta_window_size));
23942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SpdySession::OnPushPromise(SpdyStreamId stream_id,
23987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                SpdyStreamId promised_stream_id) {
23997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(akalin): Handle PUSH_PROMISE frames.
24007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
24017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
24022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id,
24032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         uint32 delta_window_size) {
24042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2405a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2406a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK(it != active_streams_.end());
2407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CHECK_EQ(it->second.stream->stream_id(), stream_id);
2408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SendWindowUpdateFrame(
2409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      stream_id, delta_window_size, it->second.stream->priority());
24102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2412a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void SpdySession::SendInitialData() {
2413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(enable_sending_initial_data_);
2414ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2415ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (send_connection_header_prefix_) {
2417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    DCHECK_EQ(protocol_, kProtoHTTP2Draft04);
2418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<SpdyFrame> connection_header_prefix_frame(
2419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        new SpdyFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
2420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      kHttp2ConnectionHeaderPrefixSize,
2421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      false /* take_ownership */));
2422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Count the prefix as part of the subsequent SETTINGS frame.
2423a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    EnqueueSessionWrite(HIGHEST, SETTINGS,
2424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                        connection_header_prefix_frame.Pass());
2425a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
2426a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // First, notify the server about the settings they should use when
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // communicating with us.
2429a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SettingsMap settings_map;
2430a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Create a new settings frame notifying the server of our
2431a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // max concurrent streams and initial window size.
2432a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  settings_map[SETTINGS_MAX_CONCURRENT_STREAMS] =
2433a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
2434a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (flow_control_state_ >= FLOW_CONTROL_STREAM &&
2435a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      stream_initial_recv_window_size_ != kSpdyStreamInitialWindowSize) {
2436a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    settings_map[SETTINGS_INITIAL_WINDOW_SIZE] =
2437a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        SettingsFlagsAndValue(SETTINGS_FLAG_NONE,
2438a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                              stream_initial_recv_window_size_);
2439a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
2440a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SendSettings(settings_map);
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2442eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Next, notify the server about our initial recv window size.
2443a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
2444eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Bump up the receive window size to the real initial value. This
2445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // has to go here since the WINDOW_UPDATE frame sent by
2446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // IncreaseRecvWindowSize() call uses |buffered_spdy_framer_|.
2447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_);
2448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // This condition implies that |kDefaultInitialRecvWindowSize| -
2449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // |session_recv_window_size_| doesn't overflow.
2450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK_GT(session_recv_window_size_, 0);
2451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IncreaseRecvWindowSize(
2452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        kDefaultInitialRecvWindowSize - session_recv_window_size_);
2453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2455a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Finally, notify the server about the settings they have
2456a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // previously told us to use when communicating with them (after
2457a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // applying them).
2458a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const SettingsMap& server_settings_map =
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_server_properties_->GetSpdySettings(host_port_pair());
2460a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (server_settings_map.empty())
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2463a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SettingsMap::const_iterator it =
2464a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      server_settings_map.find(SETTINGS_CURRENT_CWND);
2465a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  uint32 cwnd = (it != server_settings_map.end()) ? it->second.second : 0;
2466a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwndSent", cwnd, 1, 200, 100);
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2468a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (SettingsMap::const_iterator it = server_settings_map.begin();
2469a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       it != server_settings_map.end(); ++it) {
2470a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const SpdySettingsIds new_id = it->first;
2471a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const uint32 new_val = it->second.second;
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleSetting(new_id, new_val);
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SendSettings(server_settings_map);
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendSettings(const SettingsMap& settings) {
2480ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net_log_.AddEvent(
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS,
2484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySendSettingsCallback, &settings));
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the SETTINGS frame and send it.
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
24882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> settings_frame(
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreateSettings(settings));
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sent_settings_ = true;
2491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(HIGHEST, SETTINGS, settings_frame.Pass());
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::HandleSetting(uint32 id, uint32 value) {
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (id) {
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SETTINGS_MAX_CONCURRENT_STREAMS:
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_concurrent_streams_ = std::min(static_cast<size_t>(value),
24982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         kMaxConcurrentStreamLimit);
24992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProcessPendingStreamRequests();
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
25012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SETTINGS_INITIAL_WINDOW_SIZE: {
25022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (flow_control_state_ < FLOW_CONTROL_STREAM) {
2503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        net_log().AddEvent(
2504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_NO_FLOW_CONTROL);
25052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
25062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
25072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (value > static_cast<uint32>(kint32max)) {
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net_log().AddEvent(
2510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            NetLog::IntegerCallback("initial_window_size", value));
25122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
25142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only.
2516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int32 delta_window_size =
2517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<int32>(value) - stream_initial_send_window_size_;
2518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      stream_initial_send_window_size_ = static_cast<int32>(value);
25192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateStreamsSendWindowSize(delta_window_size);
25202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      net_log().AddEvent(
25212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
25222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NetLog::IntegerCallback("delta_window_size", delta_window_size));
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
25242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) {
25292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2530a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (ActiveStreamMap::iterator it = active_streams_.begin();
2531a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)       it != active_streams_.end(); ++it) {
2532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    it->second.stream->AdjustSendWindowSize(delta_window_size);
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  for (CreatedStreamSet::const_iterator it = created_streams_.begin();
2536a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)       it != created_streams_.end(); it++) {
2537a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    (*it)->AdjustSendWindowSize(delta_window_size);
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendPrefacePingIfNoneInFlight() {
25422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pings_in_flight_ || !enable_ping_based_connection_checking_)
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks now = time_func_();
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no activity in the session, then send a preface-PING.
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((now - last_activity_time_) > connection_at_risk_of_loss_time_)
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendPrefacePing();
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::SendPrefacePing() {
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WritePingFrame(next_ping_id_);
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::SendWindowUpdateFrame(SpdyStreamId stream_id,
25562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        uint32 delta_window_size,
25572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RequestPriority priority) {
25582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
2559a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2560a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (it != active_streams_.end()) {
2561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    CHECK_EQ(it->second.stream->stream_id(), stream_id);
25622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
25632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
25642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(stream_id, kSessionFlowControlStreamId);
25652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
25662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_.AddEvent(
25682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_SENT_WINDOW_UPDATE_FRAME,
25692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
25702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 stream_id, delta_window_size));
25712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
25732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> window_update_frame(
25742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffered_spdy_framer_->CreateWindowUpdate(stream_id, delta_window_size));
2575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(priority, WINDOW_UPDATE, window_update_frame.Pass());
25762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
25772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::WritePingFrame(uint32 unique_id) {
25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffered_spdy_framer_.get());
25802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<SpdyFrame> ping_frame(
25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_spdy_framer_->CreatePingFrame(unique_id));
2582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnqueueSessionWrite(HIGHEST, PING, ping_frame.Pass());
25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (net_log().IsLoggingAllEvents()) {
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log().AddEvent(
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_SPDY_SESSION_PING,
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogSpdyPingCallback, unique_id, "sent"));
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unique_id % 2 != 0) {
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_ping_id_ += 2;
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++pings_in_flight_;
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PlanToCheckPingStatus();
2593ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    last_ping_sent_time_ = time_func_();
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::PlanToCheckPingStatus() {
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (check_ping_status_pending_)
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  check_ping_status_pending_ = true;
260290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
2605ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 time_func_()), hung_interval_);
26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) {
2609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(!in_io_loop_);
2610ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2611ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we got a response back for all PINGs we had sent.
26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pings_in_flight_ == 0) {
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_ping_status_pending_ = false;
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(check_ping_status_pending_);
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2620ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::TimeTicks now = time_func_();
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delay = hung_interval_ - (now - last_activity_time_);
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) {
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Track all failed PING messages in a separate bucket.
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta kFailedPing =
26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromInternalValue(INT_MAX);
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecordPingRTTHistogram(kFailedPing);
2628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result =
2629ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        DoCloseSession(ERR_SPDY_PING_FAILED, "Failed ping.");
2630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the status of connection after a delay.
263590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 now),
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delay);
26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) {
26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("Net.SpdyPing.RTT", duration);
26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordProtocolErrorHistogram(
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpdyProtocolErrorDetails details) {
2648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details,
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NUM_SPDY_PROTOCOL_ERROR_DETAILS);
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (EndsWith(host_port_pair().host(), "google.com", false)) {
2651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details,
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              NUM_SPDY_PROTOCOL_ERROR_DETAILS);
26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
26555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpdySession::RecordHistograms() {
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_initiated_count_,
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_pushed_count_,
26625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
26635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
26645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_pushed_and_claimed_count_,
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              streams_abandoned_count_,
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent",
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            sent_settings_ ? 1 : 0, 2);
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            received_settings_ ? 1 : 0, 2);
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamStallsPerSession",
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              stalled_streams_,
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              0, 300, 50);
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionsWithStalls",
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            stalled_streams_ > 0 ? 1 : 0, 2);
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (received_settings_) {
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Enumerate the saved settings, and set histograms for it.
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SettingsMap& settings_map =
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http_server_properties_->GetSpdySettings(host_port_pair());
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SettingsMap::const_iterator it;
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (it = settings_map.begin(); it != settings_map.end(); ++it) {
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SpdySettingsIds id = it->first;
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint32 val = it->second.second;
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (id) {
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_CURRENT_CWND:
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Record several different histograms to see if cwnd converges
26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // for larger volumes of data being sent.
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd",
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 200, 100);
26942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (total_bytes_received_ > 10 * 1024) {
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K",
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        val, 1, 200, 100);
26972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (total_bytes_received_ > 25 * 1024) {
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K",
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          val, 1, 200, 100);
27002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              if (total_bytes_received_ > 50 * 1024) {
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K",
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            val, 1, 200, 100);
27032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (total_bytes_received_ > 100 * 1024) {
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K",
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              val, 1, 200, 100);
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              }
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_ROUND_TRIP_TIME:
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT",
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 1200, 100);
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case SETTINGS_DOWNLOAD_RETRANS_RATE:
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate",
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      val, 1, 100, 50);
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void SpdySession::CompleteStreamRequest(
27273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::WeakPtr<SpdyStreamRequest>& pending_request) {
27282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Abort if the request has already been cancelled.
27293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!pending_request)
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2732a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::WeakPtr<SpdyStream> stream;
27332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int rv = CreateStream(*pending_request, &stream);
27342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2735a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (rv == OK) {
27363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(stream);
27373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pending_request->OnRequestCompleteSuccess(stream);
2738a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
27393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(!stream);
2740a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pending_request->OnRequestCompleteFailure(rv);
2741a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SSLClientSocket* SpdySession::GetSSLClientSocket() const {
27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_secure_)
27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLClientSocket* ssl_socket =
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<SSLClientSocket*>(connection_->socket());
27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ssl_socket);
27505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ssl_socket;
27515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2753c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnWriteBufferConsumed(
2754c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t frame_payload_size,
2755c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t consume_size,
2756c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyBuffer::ConsumeSource consume_source) {
2757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a write SpdyBuffer is
2758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., a stream is closed due to incoming data).
2759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2760ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2761ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2762ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
27632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2765c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (consume_source == SpdyBuffer::DISCARD) {
2766c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If we're discarding a frame or part of it, increase the send
2767c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // window by the number of discarded bytes. (Although if we're
2768c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // discarding part of a frame, it's probably because of a write
2769c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // error and we'll be tearing down the session soon.)
2770c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t remaining_payload_bytes = std::min(consume_size, frame_payload_size);
2771c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_GT(remaining_payload_bytes, 0u);
2772c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IncreaseSendWindowSize(static_cast<int32>(remaining_payload_bytes));
2773c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2774c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For consumed bytes, the send window is increased when we receive
2775c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // a WINDOW_UPDATE frame.
2776c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
27772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) {
2779ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a SpdyBuffer is
2780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., a stream is closed due to incoming data).
2781ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2782ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2783c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
27842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
27852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for overflow.
27872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int32 max_delta_window_size = kint32max - session_send_window_size_;
27882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delta_window_size > max_delta_window_size) {
2789c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
2790ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result = DoCloseSession(
2791c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ERR_SPDY_PROTOCOL_ERROR,
2792c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "Received WINDOW_UPDATE [delta: " +
2793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        base::IntToString(delta_window_size) +
2794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        "] for session overflows session_send_window_size_ [current: " +
2795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        base::IntToString(session_send_window_size_) + "]");
2796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_NE(result, SESSION_ALREADY_CLOSED);
27972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
27982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
27992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  session_send_window_size_ += delta_window_size;
28012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net_log_.AddEvent(
28032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
28042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
28052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 delta_window_size, session_send_window_size_));
28062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!IsSendStalled());
28082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResumeSendStalledStreams();
28092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
28102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2811c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::DecreaseSendWindowSize(int32 delta_window_size) {
2812ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2813c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2814c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2815c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We only call this method when sending a frame. Therefore,
2816c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |delta_window_size| should be within the valid frame size range.
2817c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
2818c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
2819c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2820c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |send_window_size_| should have been at least |delta_window_size| for
2821c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // this call to happen.
2822c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_send_window_size_, delta_window_size);
2823c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2824c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_send_window_size_ -= delta_window_size;
2825c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2826c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
2827c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
2828c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 -delta_window_size, session_send_window_size_));
2830c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2831c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2832c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::OnReadBufferConsumed(
2833c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t consume_size,
2834c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SpdyBuffer::ConsumeSource consume_source) {
2835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // We can be called with |in_io_loop_| set if a read SpdyBuffer is
2836ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // deleted (e.g., discarded by a SpdyReadQueue).
2837ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2838ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (availability_state_ == STATE_CLOSED)
2839ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
2840ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2841c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2842c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(consume_size, 1u);
2843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(consume_size, static_cast<size_t>(kint32max));
2844ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2845c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IncreaseRecvWindowSize(static_cast<int32>(consume_size));
2846c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2847c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2848c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::IncreaseRecvWindowSize(int32 delta_window_size) {
2849ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK_NE(availability_state_, STATE_CLOSED);
2850c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2851c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_unacked_recv_window_bytes_, 0);
2852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(session_recv_window_size_, session_unacked_recv_window_bytes_);
2853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
2854c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check for overflow.
2855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(delta_window_size, kint32max - session_recv_window_size_);
2856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_recv_window_size_ += delta_window_size;
2858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
2859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_STREAM_UPDATE_RECV_WINDOW,
2860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 delta_window_size, session_recv_window_size_));
2862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_unacked_recv_window_bytes_ += delta_window_size;
2864c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (session_unacked_recv_window_bytes_ > kSpdySessionInitialWindowSize / 2) {
2865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendWindowUpdateFrame(kSessionFlowControlStreamId,
2866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          session_unacked_recv_window_bytes_,
2867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          HIGHEST);
2868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session_unacked_recv_window_bytes_ = 0;
2869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) {
2873ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CHECK(in_io_loop_);
2874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(delta_window_size, 1);
2876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2877c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Since we never decrease the initial receive window size,
2878c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |delta_window_size| should never cause |recv_window_size_| to go
2879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // negative. If we do, the receive window isn't being respected.
2880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (delta_window_size > session_recv_window_size_) {
2881c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION);
2882ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CloseSessionResult result = DoCloseSession(
2883c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ERR_SPDY_PROTOCOL_ERROR,
2884c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "delta_window_size is " + base::IntToString(delta_window_size) +
2885c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            " in DecreaseRecvWindowSize, which is larger than the receive " +
2886c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            "window size of " + base::IntToString(session_recv_window_size_));
2887ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
2888c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
2889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_recv_window_size_ -= delta_window_size;
2892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  net_log_.AddEvent(
2893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW,
2894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 -delta_window_size, session_recv_window_size_));
2896c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
2897c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2898a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SpdySession::QueueSendStalledStream(const SpdyStream& stream) {
2899a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(stream.send_stalled_by_flow_control());
2900a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  stream_send_unstall_queue_[stream.priority()].push_back(stream.stream_id());
29012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
29022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpdySession::ResumeSendStalledStreams() {
29042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
29052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We don't have to worry about new streams being queued, since
29072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // doing so would cause IsSendStalled() to return true. But we do
29082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // have to worry about streams being closed, as well as ourselves
29092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // being closed.
29102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2911ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (availability_state_ != STATE_CLOSED && !IsSendStalled()) {
29122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t old_size = 0;
29132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (DCHECK_IS_ON())
29142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      old_size = GetTotalSize(stream_send_unstall_queue_);
29152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpdyStreamId stream_id = PopStreamToPossiblyResume();
29172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_id == 0)
29182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
29192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
29202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The stream may actually still be send-stalled after this (due
29212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to its own send window) but that's okay -- it'll then be
29222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // resumed once its send window increases.
29232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it != active_streams_.end())
2924eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      it->second.stream->PossiblyResumeIfSendStalled();
29252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The size should decrease unless we got send-stalled again.
29272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsSendStalled())
29282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_LT(GetTotalSize(stream_send_unstall_queue_), old_size);
29292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
29302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
29312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpdyStreamId SpdySession::PopStreamToPossiblyResume() {
29332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = NUM_PRIORITIES - 1; i >= 0; --i) {
29342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::deque<SpdyStreamId>* queue = &stream_send_unstall_queue_[i];
29352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!queue->empty()) {
29362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpdyStreamId stream_id = queue->front();
29372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queue->pop_front();
29382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return stream_id;
29392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
29402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
29412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return 0;
29422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
29432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
2945