blob: db4754937463fae658a5ebe600f54206f20c08a2 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/spdy/spdy_session.h"
6
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00007#include <algorithm>
Torne (Richard Coles)58218062012-11-14 11:43:16 +00008#include <map>
9
10#include "base/basictypes.h"
11#include "base/bind.h"
12#include "base/compiler_specific.h"
13#include "base/logging.h"
Ben Murdoch9ab55632013-07-18 11:57:30 +010014#include "base/message_loop/message_loop.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000015#include "base/metrics/field_trial.h"
16#include "base/metrics/histogram.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010017#include "base/metrics/sparse_histogram.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018#include "base/metrics/stats_counters.h"
19#include "base/stl_util.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010020#include "base/strings/string_number_conversions.h"
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010021#include "base/strings/string_util.h"
22#include "base/strings/stringprintf.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010023#include "base/strings/utf_string_conversions.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010024#include "base/time/time.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000025#include "base/values.h"
26#include "crypto/ec_private_key.h"
27#include "crypto/ec_signature_creator.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028#include "net/base/connection_type_histograms.h"
29#include "net/base/net_log.h"
30#include "net/base/net_util.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010031#include "net/cert/asn1_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000032#include "net/http/http_network_session.h"
33#include "net/http/http_server_properties.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010034#include "net/spdy/spdy_buffer_producer.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000035#include "net/spdy/spdy_credential_builder.h"
36#include "net/spdy/spdy_frame_builder.h"
37#include "net/spdy/spdy_http_utils.h"
38#include "net/spdy/spdy_protocol.h"
39#include "net/spdy/spdy_session_pool.h"
40#include "net/spdy/spdy_stream.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000041#include "net/ssl/server_bound_cert_service.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000042
43namespace net {
44
45namespace {
46
47const int kReadBufferSize = 8 * 1024;
48const int kDefaultConnectionAtRiskOfLossSeconds = 10;
49const int kHungIntervalSeconds = 10;
50
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000051// Always start at 1 for the first stream id.
52const SpdyStreamId kFirstStreamId = 1;
53
Torne (Richard Coles)58218062012-11-14 11:43:16 +000054// Minimum seconds that unclaimed pushed streams will be kept in memory.
55const int kMinPushedStreamLifetimeSeconds = 300;
56
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000057base::Value* NetLogSpdySynCallback(const SpdyHeaderBlock* headers,
58 bool fin,
59 bool unidirectional,
60 SpdyStreamId stream_id,
61 SpdyStreamId associated_stream,
62 NetLog::LogLevel /* log_level */) {
63 base::DictionaryValue* dict = new base::DictionaryValue();
64 base::ListValue* headers_list = new base::ListValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +000065 for (SpdyHeaderBlock::const_iterator it = headers->begin();
66 it != headers->end(); ++it) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000067 headers_list->Append(new base::StringValue(base::StringPrintf(
68 "%s: %s", it->first.c_str(),
69 (ShouldShowHttpHeaderValue(
70 it->first) ? it->second : "[elided]").c_str())));
Torne (Richard Coles)58218062012-11-14 11:43:16 +000071 }
72 dict->SetBoolean("fin", fin);
73 dict->SetBoolean("unidirectional", unidirectional);
74 dict->Set("headers", headers_list);
75 dict->SetInteger("stream_id", stream_id);
76 if (associated_stream)
77 dict->SetInteger("associated_stream", associated_stream);
78 return dict;
79}
80
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000081base::Value* NetLogSpdyCredentialCallback(size_t slot,
82 const std::string* origin,
83 NetLog::LogLevel /* log_level */) {
84 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085 dict->SetInteger("slot", slot);
86 dict->SetString("origin", *origin);
87 return dict;
88}
89
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000090base::Value* NetLogSpdySessionCloseCallback(int net_error,
91 const std::string* description,
92 NetLog::LogLevel /* log_level */) {
93 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +000094 dict->SetInteger("net_error", net_error);
95 dict->SetString("description", *description);
96 return dict;
97}
98
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000099base::Value* NetLogSpdySessionCallback(const HostPortProxyPair* host_pair,
100 NetLog::LogLevel /* log_level */) {
101 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000102 dict->SetString("host", host_pair->first.ToString());
103 dict->SetString("proxy", host_pair->second.ToPacString());
104 return dict;
105}
106
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100107base::Value* NetLogSpdySettingsCallback(const HostPortPair& host_port_pair,
108 bool clear_persisted,
109 NetLog::LogLevel /* log_level */) {
110 base::DictionaryValue* dict = new base::DictionaryValue();
111 dict->SetString("host", host_port_pair.ToString());
112 dict->SetBoolean("clear_persisted", clear_persisted);
113 return dict;
114}
115
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000116base::Value* NetLogSpdySettingCallback(SpdySettingsIds id,
117 SpdySettingsFlags flags,
118 uint32 value,
119 NetLog::LogLevel /* log_level */) {
120 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000121 dict->SetInteger("id", id);
122 dict->SetInteger("flags", flags);
123 dict->SetInteger("value", value);
124 return dict;
125}
126
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100127base::Value* NetLogSpdySendSettingsCallback(const SettingsMap* settings,
128 NetLog::LogLevel /* log_level */) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000129 base::DictionaryValue* dict = new base::DictionaryValue();
130 base::ListValue* settings_list = new base::ListValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000131 for (SettingsMap::const_iterator it = settings->begin();
132 it != settings->end(); ++it) {
133 const SpdySettingsIds id = it->first;
134 const SpdySettingsFlags flags = it->second.first;
135 const uint32 value = it->second.second;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000136 settings_list->Append(new base::StringValue(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000137 base::StringPrintf("[id:%u flags:%u value:%u]", id, flags, value)));
138 }
139 dict->Set("settings", settings_list);
140 return dict;
141}
142
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000143base::Value* NetLogSpdyWindowUpdateFrameCallback(
144 SpdyStreamId stream_id,
145 uint32 delta,
146 NetLog::LogLevel /* log_level */) {
147 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000148 dict->SetInteger("stream_id", static_cast<int>(stream_id));
149 dict->SetInteger("delta", delta);
150 return dict;
151}
152
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000153base::Value* NetLogSpdySessionWindowUpdateCallback(
154 int32 delta,
155 int32 window_size,
156 NetLog::LogLevel /* log_level */) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100157 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000158 dict->SetInteger("delta", delta);
159 dict->SetInteger("window_size", window_size);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000160 return dict;
161}
162
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000163base::Value* NetLogSpdyDataCallback(SpdyStreamId stream_id,
164 int size,
165 bool fin,
166 NetLog::LogLevel /* log_level */) {
167 base::DictionaryValue* dict = new base::DictionaryValue();
168 dict->SetInteger("stream_id", static_cast<int>(stream_id));
169 dict->SetInteger("size", size);
170 dict->SetBoolean("fin", fin);
171 return dict;
172}
173
174base::Value* NetLogSpdyRstCallback(SpdyStreamId stream_id,
175 int status,
176 const std::string* description,
177 NetLog::LogLevel /* log_level */) {
178 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000179 dict->SetInteger("stream_id", static_cast<int>(stream_id));
180 dict->SetInteger("status", status);
181 dict->SetString("description", *description);
182 return dict;
183}
184
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000185base::Value* NetLogSpdyPingCallback(uint32 unique_id,
186 const char* type,
187 NetLog::LogLevel /* log_level */) {
188 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000189 dict->SetInteger("unique_id", unique_id);
190 dict->SetString("type", type);
191 return dict;
192}
193
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000194base::Value* NetLogSpdyGoAwayCallback(SpdyStreamId last_stream_id,
195 int active_streams,
196 int unclaimed_streams,
197 SpdyGoAwayStatus status,
198 NetLog::LogLevel /* log_level */) {
199 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000200 dict->SetInteger("last_accepted_stream_id",
201 static_cast<int>(last_stream_id));
202 dict->SetInteger("active_streams", active_streams);
203 dict->SetInteger("unclaimed_streams", unclaimed_streams);
204 dict->SetInteger("status", static_cast<int>(status));
205 return dict;
206}
207
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000208// The maximum number of concurrent streams we will ever create. Even if
209// the server permits more, we will never exceed this limit.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000210const size_t kMaxConcurrentStreamLimit = 256;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000211
212} // namespace
213
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000214SpdyStreamRequest::SpdyStreamRequest() {
215 Reset();
216}
217
218SpdyStreamRequest::~SpdyStreamRequest() {
219 CancelRequest();
220}
221
222int SpdyStreamRequest::StartRequest(
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100223 SpdyStreamType type,
Ben Murdochca12bfa2013-07-23 11:17:05 +0100224 const base::WeakPtr<SpdySession>& session,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000225 const GURL& url,
226 RequestPriority priority,
227 const BoundNetLog& net_log,
228 const CompletionCallback& callback) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100229 DCHECK(session.get());
230 DCHECK(!session_.get());
231 DCHECK(!stream_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000232 DCHECK(callback_.is_null());
233
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100234 type_ = type;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000235 session_ = session;
236 url_ = url;
237 priority_ = priority;
238 net_log_ = net_log;
239 callback_ = callback;
240
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100241 base::WeakPtr<SpdyStream> stream;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000242 int rv = session->TryCreateStream(this, &stream);
243 if (rv == OK) {
244 Reset();
245 stream_ = stream;
246 }
247 return rv;
248}
249
250void SpdyStreamRequest::CancelRequest() {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100251 if (session_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000252 session_->CancelStreamRequest(this);
253 Reset();
254}
255
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100256base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000257 DCHECK(!session_.get());
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100258 base::WeakPtr<SpdyStream> stream = stream_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100259 DCHECK(stream.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000260 Reset();
261 return stream;
262}
263
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100264void SpdyStreamRequest::OnRequestCompleteSuccess(
265 base::WeakPtr<SpdyStream>* stream) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100266 DCHECK(session_.get());
267 DCHECK(!stream_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000268 DCHECK(!callback_.is_null());
269 CompletionCallback callback = callback_;
270 Reset();
Ben Murdochca12bfa2013-07-23 11:17:05 +0100271 DCHECK(*stream);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100272 stream_ = *stream;
273 callback.Run(OK);
274}
275
276void SpdyStreamRequest::OnRequestCompleteFailure(int rv) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100277 DCHECK(session_.get());
278 DCHECK(!stream_.get());
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100279 DCHECK(!callback_.is_null());
280 CompletionCallback callback = callback_;
281 Reset();
282 DCHECK_NE(rv, OK);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000283 callback.Run(rv);
284}
285
286void SpdyStreamRequest::Reset() {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100287 type_ = SPDY_BIDIRECTIONAL_STREAM;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100288 session_.reset();
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100289 stream_.reset();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000290 url_ = GURL();
291 priority_ = MINIMUM_PRIORITY;
292 net_log_ = BoundNetLog();
293 callback_.Reset();
294}
295
Ben Murdocheb525c52013-07-10 11:40:50 +0100296SpdySession::ActiveStreamInfo::ActiveStreamInfo()
297 : stream(NULL),
298 waiting_for_syn_reply(false) {}
299
300SpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream)
301 : stream(stream),
302 waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {}
303
304SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {}
305
306SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {}
307
308SpdySession::PushedStreamInfo::PushedStreamInfo(
309 SpdyStreamId stream_id,
310 base::TimeTicks creation_time)
311 : stream_id(stream_id),
312 creation_time(creation_time) {}
313
314SpdySession::PushedStreamInfo::~PushedStreamInfo() {}
315
Ben Murdochca12bfa2013-07-23 11:17:05 +0100316SpdySession::SpdySession(
317 const SpdySessionKey& spdy_session_key,
318 const base::WeakPtr<HttpServerProperties>& http_server_properties,
319 bool verify_domain_authentication,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100320 bool enable_sending_initial_data,
Ben Murdochca12bfa2013-07-23 11:17:05 +0100321 bool enable_credential_frames,
322 bool enable_compression,
323 bool enable_ping_based_connection_checking,
324 NextProto default_protocol,
325 size_t stream_initial_recv_window_size,
326 size_t initial_max_concurrent_streams,
327 size_t max_concurrent_streams_limit,
328 TimeFunc time_func,
329 const HostPortPair& trusted_spdy_proxy,
330 NetLog* net_log)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100331 : weak_factory_(this),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100332 in_io_loop_(false),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100333 spdy_session_key_(spdy_session_key),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100334 pool_(NULL),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000335 http_server_properties_(http_server_properties),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000336 read_buffer_(new IOBuffer(kReadBufferSize)),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000337 stream_hi_water_mark_(kFirstStreamId),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100338 in_flight_write_frame_type_(DATA),
339 in_flight_write_frame_size_(0),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000340 is_secure_(false),
341 certificate_error_code_(OK),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100342 availability_state_(STATE_AVAILABLE),
343 read_state_(READ_STATE_DO_READ),
344 write_state_(WRITE_STATE_IDLE),
345 error_on_close_(OK),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000346 max_concurrent_streams_(initial_max_concurrent_streams == 0 ?
347 kInitialMaxConcurrentStreams :
348 initial_max_concurrent_streams),
349 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ?
350 kMaxConcurrentStreamLimit :
351 max_concurrent_streams_limit),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000352 streams_initiated_count_(0),
353 streams_pushed_count_(0),
354 streams_pushed_and_claimed_count_(0),
355 streams_abandoned_count_(0),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000356 total_bytes_received_(0),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000357 sent_settings_(false),
358 received_settings_(false),
359 stalled_streams_(0),
360 pings_in_flight_(0),
361 next_ping_id_(1),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100362 last_activity_time_(time_func()),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000363 check_ping_status_pending_(false),
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100364 send_connection_header_prefix_(false),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000365 flow_control_state_(FLOW_CONTROL_NONE),
366 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize),
367 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ?
368 kDefaultInitialRecvWindowSize :
369 stream_initial_recv_window_size),
370 session_send_window_size_(0),
371 session_recv_window_size_(0),
372 session_unacked_recv_window_bytes_(0),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000373 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
374 verify_domain_authentication_(verify_domain_authentication),
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100375 enable_sending_initial_data_(enable_sending_initial_data),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000376 enable_credential_frames_(enable_credential_frames),
377 enable_compression_(enable_compression),
378 enable_ping_based_connection_checking_(
379 enable_ping_based_connection_checking),
Ben Murdoch558790d2013-07-30 15:19:42 +0100380 protocol_(default_protocol),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000381 credential_state_(SpdyCredentialState::kDefaultNumSlots),
382 connection_at_risk_of_loss_time_(
383 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
384 hung_interval_(
385 base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000386 trusted_spdy_proxy_(trusted_spdy_proxy),
387 time_func_(time_func) {
Ben Murdoch558790d2013-07-30 15:19:42 +0100388 // TODO(akalin): Change this to kProtoSPDYMinimumVersion once we
389 // stop supporting SPDY/1.
390 DCHECK_GE(protocol_, kProtoSPDY2);
391 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000392 DCHECK(HttpStreamFactory::spdy_enabled());
393 net_log_.BeginEvent(
394 NetLog::TYPE_SPDY_SESSION,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100395 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000396 next_unclaimed_push_stream_sweep_time_ = time_func_() +
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000397 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
398 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
399}
400
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000401SpdySession::~SpdySession() {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100402 CHECK(!in_io_loop_);
403 DCHECK(!pool_);
404 DcheckClosed();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000405
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100406 // TODO(akalin): Check connection->is_initialized() instead. This
407 // requires re-working CreateFakeSpdySession(), though.
408 DCHECK(connection_->socket());
409 // With SPDY we can't recycle sockets.
410 connection_->socket()->Disconnect();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000411
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000412 RecordHistograms();
413
414 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION);
415}
416
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100417Error SpdySession::InitializeWithSocket(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100418 scoped_ptr<ClientSocketHandle> connection,
Ben Murdochca12bfa2013-07-23 11:17:05 +0100419 SpdySessionPool* pool,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000420 bool is_secure,
421 int certificate_error_code) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100422 CHECK(!in_io_loop_);
423 DCHECK_EQ(availability_state_, STATE_AVAILABLE);
424 DCHECK_EQ(read_state_, READ_STATE_DO_READ);
425 DCHECK_EQ(write_state_, WRITE_STATE_IDLE);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100426 DCHECK(!connection_);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100427
428 DCHECK(certificate_error_code == OK ||
429 certificate_error_code < ERR_IO_PENDING);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100430 // TODO(akalin): Check connection->is_initialized() instead. This
431 // requires re-working CreateFakeSpdySession(), though.
432 DCHECK(connection->socket());
Ben Murdochca12bfa2013-07-23 11:17:05 +0100433
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000434 base::StatsCounter spdy_sessions("spdy.sessions");
435 spdy_sessions.Increment();
436
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100437 connection_ = connection.Pass();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000438 is_secure_ = is_secure;
439 certificate_error_code_ = certificate_error_code;
440
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100441 NextProto protocol_negotiated =
442 connection_->socket()->GetNegotiatedProtocol();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000443 if (protocol_negotiated != kProtoUnknown) {
Ben Murdoch558790d2013-07-30 15:19:42 +0100444 protocol_ = protocol_negotiated;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000445 }
Ben Murdoch558790d2013-07-30 15:19:42 +0100446 // TODO(akalin): Change this to kProtoSPDYMinimumVersion once we
447 // stop supporting SPDY/1.
448 DCHECK_GE(protocol_, kProtoSPDY2);
449 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000450
451 SSLClientSocket* ssl_socket = GetSSLClientSocket();
452 if (ssl_socket && ssl_socket->WasChannelIDSent()) {
453 // According to the SPDY spec, the credential associated with the TLS
454 // connection is stored in slot[1].
455 credential_state_.SetHasCredential(GURL("https://" +
456 host_port_pair().ToString()));
457 }
458
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100459 if (protocol_ == kProtoHTTP2Draft04)
460 send_connection_header_prefix_ = true;
461
Ben Murdoch558790d2013-07-30 15:19:42 +0100462 if (protocol_ >= kProtoSPDY31) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000463 flow_control_state_ = FLOW_CONTROL_STREAM_AND_SESSION;
464 session_send_window_size_ = kSpdySessionInitialWindowSize;
465 session_recv_window_size_ = kSpdySessionInitialWindowSize;
Ben Murdoch558790d2013-07-30 15:19:42 +0100466 } else if (protocol_ >= kProtoSPDY3) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000467 flow_control_state_ = FLOW_CONTROL_STREAM;
468 } else {
469 flow_control_state_ = FLOW_CONTROL_NONE;
470 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000471
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100472 buffered_spdy_framer_.reset(
Ben Murdoch558790d2013-07-30 15:19:42 +0100473 new BufferedSpdyFramer(NextProtoToSpdyMajorVersion(protocol_),
474 enable_compression_));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000475 buffered_spdy_framer_->set_visitor(this);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100476 buffered_spdy_framer_->set_debug_visitor(this);
Ben Murdoch558790d2013-07-30 15:19:42 +0100477 UMA_HISTOGRAM_ENUMERATION("Net.SpdyVersion", protocol_, kProtoMaximumVersion);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100478#if defined(SPDY_PROXY_AUTH_ORIGIN)
479 UMA_HISTOGRAM_BOOLEAN("Net.SpdySessions_DataReductionProxy",
480 host_port_pair().Equals(HostPortPair::FromURL(
481 GURL(SPDY_PROXY_AUTH_ORIGIN))));
482#endif
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000483
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100484 net_log_.AddEvent(
485 NetLog::TYPE_SPDY_SESSION_INITIALIZED,
486 connection_->socket()->NetLog().source().ToEventParametersCallback());
487
Ben Murdochca12bfa2013-07-23 11:17:05 +0100488 int error = DoReadLoop(READ_STATE_DO_READ, OK);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000489 if (error == ERR_IO_PENDING)
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100490 error = OK;
491 if (error == OK) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100492 DCHECK_NE(availability_state_, STATE_CLOSED);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100493 connection_->AddLayeredPool(this);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100494 if (enable_sending_initial_data_)
495 SendInitialData();
Ben Murdochca12bfa2013-07-23 11:17:05 +0100496 pool_ = pool;
497 } else {
498 DcheckClosed();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100499 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100500 return static_cast<Error>(error);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000501}
502
503bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
504 if (!verify_domain_authentication_)
505 return true;
506
Ben Murdochca12bfa2013-07-23 11:17:05 +0100507 if (availability_state_ == STATE_CLOSED)
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000508 return false;
509
510 SSLInfo ssl_info;
511 bool was_npn_negotiated;
512 NextProto protocol_negotiated = kProtoUnknown;
513 if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
514 return true; // This is not a secure session, so all domains are okay.
515
516 return !ssl_info.client_cert_sent &&
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000517 (enable_credential_frames_ || !ssl_info.channel_id_sent ||
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000518 ServerBoundCertService::GetDomainForHost(domain) ==
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100519 ServerBoundCertService::GetDomainForHost(host_port_pair().host())) &&
520 ssl_info.cert->VerifyNameMatch(domain);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000521}
522
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000523int SpdySession::GetPushStream(
524 const GURL& url,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100525 base::WeakPtr<SpdyStream>* stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000526 const BoundNetLog& stream_net_log) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100527 CHECK(!in_io_loop_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000528
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100529 stream->reset();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000530
Ben Murdochca12bfa2013-07-23 11:17:05 +0100531 // TODO(akalin): Add unit test exercising this code path.
532 if (availability_state_ == STATE_CLOSED)
533 return ERR_CONNECTION_CLOSED;
534
535 Error err = TryAccessStream(url);
536 if (err != OK)
537 return err;
538
539 *stream = GetActivePushStream(url);
540 if (*stream) {
541 DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_);
542 streams_pushed_and_claimed_count_++;
543 }
544 return OK;
545}
546
Ben Murdochbbcdd452013-07-25 10:06:34 +0100547// {,Try}CreateStream() and TryAccessStream() can be called with
548// |in_io_loop_| set if a stream is being created in response to
549// another being closed due to received data.
550
Ben Murdochca12bfa2013-07-23 11:17:05 +0100551Error SpdySession::TryAccessStream(const GURL& url) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100552 DCHECK_NE(availability_state_, STATE_CLOSED);
553
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000554 if (is_secure_ && certificate_error_code_ != OK &&
555 (url.SchemeIs("https") || url.SchemeIs("wss"))) {
556 RecordProtocolErrorHistogram(
557 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100558 CloseSessionResult result = DoCloseSession(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100559 static_cast<Error>(certificate_error_code_),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000560 "Tried to get SPDY stream for secure content over an unauthenticated "
561 "session.");
Ben Murdochca12bfa2013-07-23 11:17:05 +0100562 DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000563 return ERR_SPDY_PROTOCOL_ERROR;
564 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000565 return OK;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000566}
567
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000568int SpdySession::TryCreateStream(SpdyStreamRequest* request,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100569 base::WeakPtr<SpdyStream>* stream) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100570 CHECK(request);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100571
572 if (availability_state_ == STATE_GOING_AWAY)
573 return ERR_FAILED;
574
575 // TODO(akalin): Add unit test exercising this code path.
576 if (availability_state_ == STATE_CLOSED)
577 return ERR_CONNECTION_CLOSED;
578
579 Error err = TryAccessStream(request->url());
580 if (err != OK)
581 return err;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100582
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000583 if (!max_concurrent_streams_ ||
584 (active_streams_.size() + created_streams_.size() <
585 max_concurrent_streams_)) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000586 return CreateStream(*request, stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000587 }
588
589 stalled_streams_++;
590 net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000591 pending_create_stream_queues_[request->priority()].push_back(request);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000592 return ERR_IO_PENDING;
593}
594
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000595int SpdySession::CreateStream(const SpdyStreamRequest& request,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100596 base::WeakPtr<SpdyStream>* stream) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000597 DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
598 DCHECK_LT(request.priority(), NUM_PRIORITIES);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000599
Ben Murdochca12bfa2013-07-23 11:17:05 +0100600 if (availability_state_ == STATE_GOING_AWAY)
601 return ERR_FAILED;
602
603 // TODO(akalin): Add unit test exercising this code path.
604 if (availability_state_ == STATE_CLOSED)
605 return ERR_CONNECTION_CLOSED;
606
607 Error err = TryAccessStream(request.url());
608 if (err != OK) {
609 // This should have been caught in TryCreateStream().
610 NOTREACHED();
611 return err;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000612 }
613
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100614 DCHECK(connection_->socket());
615 DCHECK(connection_->socket()->IsConnected());
616 if (connection_->socket()) {
617 UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected",
618 connection_->socket()->IsConnected());
619 if (!connection_->socket()->IsConnected()) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100620 CloseSessionResult result = DoCloseSession(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100621 ERR_CONNECTION_CLOSED,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100622 "Tried to create SPDY stream for a closed socket connection.");
Ben Murdochca12bfa2013-07-23 11:17:05 +0100623 DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100624 return ERR_CONNECTION_CLOSED;
625 }
626 }
627
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100628 scoped_ptr<SpdyStream> new_stream(
Ben Murdochca12bfa2013-07-23 11:17:05 +0100629 new SpdyStream(request.type(), GetWeakPtr(), request.url(),
630 request.priority(),
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100631 stream_initial_send_window_size_,
632 stream_initial_recv_window_size_,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100633 request.net_log()));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100634 *stream = new_stream->GetWeakPtr();
635 InsertCreatedStream(new_stream.Pass());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000636
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000637 UMA_HISTOGRAM_CUSTOM_COUNTS(
638 "Net.SpdyPriorityCount",
639 static_cast<int>(request.priority()), 0, 10, 11);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000640
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000641 return OK;
642}
643
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000644void SpdySession::CancelStreamRequest(SpdyStreamRequest* request) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100645 CHECK(request);
646
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000647 if (DCHECK_IS_ON()) {
648 // |request| should not be in a queue not matching its priority.
649 for (int i = 0; i < NUM_PRIORITIES; ++i) {
650 if (request->priority() == i)
651 continue;
652 PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i];
653 DCHECK(std::find(queue->begin(), queue->end(), request) == queue->end());
654 }
655 }
656
657 PendingStreamRequestQueue* queue =
658 &pending_create_stream_queues_[request->priority()];
659 // Remove |request| from |queue| while preserving the order of the
660 // other elements.
661 PendingStreamRequestQueue::iterator it =
662 std::find(queue->begin(), queue->end(), request);
663 if (it != queue->end()) {
664 it = queue->erase(it);
665 // |request| should be in the queue at most once, and if it is
666 // present, should not be pending completion.
667 DCHECK(std::find(it, queue->end(), request) == queue->end());
668 DCHECK(!ContainsKey(pending_stream_request_completions_,
669 request));
670 return;
671 }
672
673 pending_stream_request_completions_.erase(request);
674}
675
676void SpdySession::ProcessPendingStreamRequests() {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100677 // Like |max_concurrent_streams_|, 0 means infinite for
678 // |max_requests_to_process|.
679 size_t max_requests_to_process = 0;
680 if (max_concurrent_streams_ != 0) {
681 max_requests_to_process =
682 max_concurrent_streams_ -
683 (active_streams_.size() + created_streams_.size());
684 }
685 for (size_t i = 0;
686 max_requests_to_process == 0 || i < max_requests_to_process; ++i) {
687 bool processed_request = false;
688 for (int j = NUM_PRIORITIES - 1; j >= MINIMUM_PRIORITY; --j) {
689 if (pending_create_stream_queues_[j].empty())
690 continue;
691
692 SpdyStreamRequest* pending_request =
693 pending_create_stream_queues_[j].front();
694 CHECK(pending_request);
695 pending_create_stream_queues_[j].pop_front();
696 processed_request = true;
697 DCHECK(!ContainsKey(pending_stream_request_completions_,
698 pending_request));
699 pending_stream_request_completions_.insert(pending_request);
700 base::MessageLoop::current()->PostTask(
701 FROM_HERE,
702 base::Bind(&SpdySession::CompleteStreamRequest,
703 weak_factory_.GetWeakPtr(), pending_request));
704 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000705 }
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100706 if (!processed_request)
707 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000708 }
709}
710
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000711bool SpdySession::NeedsCredentials() const {
712 if (!is_secure_)
713 return false;
714 SSLClientSocket* ssl_socket = GetSSLClientSocket();
715 if (ssl_socket->GetNegotiatedProtocol() < kProtoSPDY3)
716 return false;
717 return ssl_socket->WasChannelIDSent();
718}
719
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100720void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
721 pooled_aliases_.insert(alias_key);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000722}
723
724int SpdySession::GetProtocolVersion() const {
725 DCHECK(buffered_spdy_framer_.get());
726 return buffered_spdy_framer_->protocol_version();
727}
728
Ben Murdochca12bfa2013-07-23 11:17:05 +0100729base::WeakPtr<SpdySession> SpdySession::GetWeakPtr() {
730 return weak_factory_.GetWeakPtr();
731}
732
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100733bool SpdySession::CloseOneIdleConnection() {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100734 CHECK(!in_io_loop_);
735 DCHECK_NE(availability_state_, STATE_CLOSED);
736 DCHECK(pool_);
737 if (!active_streams_.empty())
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100738 return false;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100739 CloseSessionResult result =
740 DoCloseSession(ERR_CONNECTION_CLOSED, "Closing one idle connection.");
741 if (result != SESSION_CLOSED_AND_REMOVED) {
742 NOTREACHED();
743 return false;
744 }
745 return true;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100746}
747
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100748void SpdySession::EnqueueStreamWrite(
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100749 const base::WeakPtr<SpdyStream>& stream,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100750 SpdyFrameType frame_type,
751 scoped_ptr<SpdyBufferProducer> producer) {
752 DCHECK(frame_type == HEADERS ||
753 frame_type == DATA ||
754 frame_type == CREDENTIAL ||
755 frame_type == SYN_STREAM);
756 EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream);
757}
758
759scoped_ptr<SpdyFrame> SpdySession::CreateSynStream(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000760 SpdyStreamId stream_id,
761 RequestPriority priority,
762 uint8 credential_slot,
763 SpdyControlFlags flags,
764 const SpdyHeaderBlock& headers) {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100765 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
766 CHECK(it != active_streams_.end());
Ben Murdocheb525c52013-07-10 11:40:50 +0100767 CHECK_EQ(it->second.stream->stream_id(), stream_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000768
769 SendPrefacePingIfNoneInFlight();
770
771 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000772 scoped_ptr<SpdyFrame> syn_frame(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000773 buffered_spdy_framer_->CreateSynStream(
774 stream_id, 0,
775 ConvertRequestPriorityToSpdyPriority(priority, GetProtocolVersion()),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000776 credential_slot, flags, enable_compression_, &headers));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000777
778 base::StatsCounter spdy_requests("spdy.requests");
779 spdy_requests.Increment();
780 streams_initiated_count_++;
781
782 if (net_log().IsLoggingAllEvents()) {
783 net_log().AddEvent(
784 NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
785 base::Bind(&NetLogSpdySynCallback, &headers,
786 (flags & CONTROL_FLAG_FIN) != 0,
787 (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
788 stream_id, 0));
789 }
790
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100791 return syn_frame.Pass();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000792}
793
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100794int SpdySession::CreateCredentialFrame(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000795 const std::string& origin,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000796 const std::string& key,
797 const std::string& cert,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100798 RequestPriority priority,
799 scoped_ptr<SpdyFrame>* credential_frame) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000800 DCHECK(is_secure_);
801 SSLClientSocket* ssl_socket = GetSSLClientSocket();
802 DCHECK(ssl_socket);
803 DCHECK(ssl_socket->WasChannelIDSent());
804
805 SpdyCredential credential;
806 std::string tls_unique;
807 ssl_socket->GetTLSUniqueChannelBinding(&tls_unique);
808 size_t slot = credential_state_.SetHasCredential(GURL(origin));
Ben Murdochbb1529c2013-08-08 10:24:53 +0100809 int rv = SpdyCredentialBuilder::Build(tls_unique, key, cert, slot,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000810 &credential);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100811 DCHECK_NE(rv, ERR_IO_PENDING);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000812 if (rv != OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100813 return rv;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000814
815 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100816 credential_frame->reset(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000817 buffered_spdy_framer_->CreateCredentialFrame(credential));
818
819 if (net_log().IsLoggingAllEvents()) {
820 net_log().AddEvent(
821 NetLog::TYPE_SPDY_SESSION_SEND_CREDENTIAL,
822 base::Bind(&NetLogSpdyCredentialCallback, credential.slot, &origin));
823 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100824 return OK;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000825}
826
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100827scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id,
828 IOBuffer* data,
829 int len,
830 SpdyDataFlags flags) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100831 if (availability_state_ == STATE_CLOSED) {
832 NOTREACHED();
833 return scoped_ptr<SpdyBuffer>();
834 }
835
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100836 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
837 CHECK(it != active_streams_.end());
Ben Murdocheb525c52013-07-10 11:40:50 +0100838 SpdyStream* stream = it->second.stream;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000839 CHECK_EQ(stream->stream_id(), stream_id);
840
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000841 if (len < 0) {
842 NOTREACHED();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100843 return scoped_ptr<SpdyBuffer>();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000844 }
845
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100846 int effective_len = std::min(len, kMaxSpdyFrameChunkSize);
847
848 bool send_stalled_by_stream =
849 (flow_control_state_ >= FLOW_CONTROL_STREAM) &&
850 (stream->send_window_size() <= 0);
851 bool send_stalled_by_session = IsSendStalled();
852
853 // NOTE: There's an enum of the same name in histograms.xml.
854 enum SpdyFrameFlowControlState {
855 SEND_NOT_STALLED,
856 SEND_STALLED_BY_STREAM,
857 SEND_STALLED_BY_SESSION,
858 SEND_STALLED_BY_STREAM_AND_SESSION,
859 };
860
861 SpdyFrameFlowControlState frame_flow_control_state = SEND_NOT_STALLED;
862 if (send_stalled_by_stream) {
863 if (send_stalled_by_session) {
864 frame_flow_control_state = SEND_STALLED_BY_STREAM_AND_SESSION;
865 } else {
866 frame_flow_control_state = SEND_STALLED_BY_STREAM;
867 }
868 } else if (send_stalled_by_session) {
869 frame_flow_control_state = SEND_STALLED_BY_SESSION;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000870 }
871
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100872 if (flow_control_state_ == FLOW_CONTROL_STREAM) {
873 UMA_HISTOGRAM_ENUMERATION(
874 "Net.SpdyFrameStreamFlowControlState",
875 frame_flow_control_state,
876 SEND_STALLED_BY_STREAM + 1);
877 } else if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
878 UMA_HISTOGRAM_ENUMERATION(
879 "Net.SpdyFrameStreamAndSessionFlowControlState",
880 frame_flow_control_state,
881 SEND_STALLED_BY_STREAM_AND_SESSION + 1);
882 }
883
884 // Obey send window size of the stream if stream flow control is
885 // enabled.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000886 if (flow_control_state_ >= FLOW_CONTROL_STREAM) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100887 if (send_stalled_by_stream) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000888 stream->set_send_stalled_by_flow_control(true);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100889 // Even though we're currently stalled only by the stream, we
890 // might end up being stalled by the session also.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100891 QueueSendStalledStream(*stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000892 net_log().AddEvent(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100893 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000894 NetLog::IntegerCallback("stream_id", stream_id));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100895 return scoped_ptr<SpdyBuffer>();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000896 }
897
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100898 effective_len = std::min(effective_len, stream->send_window_size());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000899 }
900
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100901 // Obey send window size of the session if session flow control is
902 // enabled.
903 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
904 if (send_stalled_by_session) {
905 stream->set_send_stalled_by_flow_control(true);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100906 QueueSendStalledStream(*stream);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100907 net_log().AddEvent(
908 NetLog::TYPE_SPDY_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
909 NetLog::IntegerCallback("stream_id", stream_id));
910 return scoped_ptr<SpdyBuffer>();
911 }
912
913 effective_len = std::min(effective_len, session_send_window_size_);
914 }
915
916 DCHECK_GE(effective_len, 0);
917
918 // Clear FIN flag if only some of the data will be in the data
919 // frame.
920 if (effective_len < len)
921 flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN);
922
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000923 if (net_log().IsLoggingAllEvents()) {
924 net_log().AddEvent(
925 NetLog::TYPE_SPDY_SESSION_SEND_DATA,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100926 base::Bind(&NetLogSpdyDataCallback, stream_id, effective_len,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000927 (flags & DATA_FLAG_FIN) != 0));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000928 }
929
930 // Send PrefacePing for DATA_FRAMEs with nonzero payload size.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100931 if (effective_len > 0)
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000932 SendPrefacePingIfNoneInFlight();
933
934 // TODO(mbelshe): reduce memory copies here.
935 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000936 scoped_ptr<SpdyFrame> frame(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000937 buffered_spdy_framer_->CreateDataFrame(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100938 stream_id, data->data(),
939 static_cast<uint32>(effective_len), flags));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000940
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100941 scoped_ptr<SpdyBuffer> data_buffer(new SpdyBuffer(frame.Pass()));
942
943 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
944 DecreaseSendWindowSize(static_cast<int32>(effective_len));
945 data_buffer->AddConsumeCallback(
946 base::Bind(&SpdySession::OnWriteBufferConsumed,
947 weak_factory_.GetWeakPtr(),
948 static_cast<size_t>(effective_len)));
949 }
950
951 return data_buffer.Pass();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000952}
953
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100954void SpdySession::CloseActiveStream(SpdyStreamId stream_id, int status) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100955 DCHECK_NE(stream_id, 0u);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100956
Ben Murdocheb525c52013-07-10 11:40:50 +0100957 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
958 if (it == active_streams_.end()) {
959 NOTREACHED();
960 return;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100961 }
962
Ben Murdocheb525c52013-07-10 11:40:50 +0100963 CloseActiveStreamIterator(it, status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000964}
965
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100966void SpdySession::CloseCreatedStream(
967 const base::WeakPtr<SpdyStream>& stream, int status) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100968 DCHECK_EQ(stream->stream_id(), 0u);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100969
Ben Murdocheb525c52013-07-10 11:40:50 +0100970 CreatedStreamSet::iterator it = created_streams_.find(stream.get());
971 if (it == created_streams_.end()) {
972 NOTREACHED();
973 return;
974 }
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100975
Ben Murdocheb525c52013-07-10 11:40:50 +0100976 CloseCreatedStreamIterator(it, status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000977}
978
979void SpdySession::ResetStream(SpdyStreamId stream_id,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000980 SpdyRstStreamStatus status,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000981 const std::string& description) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100982 DCHECK_NE(stream_id, 0u);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000983
Ben Murdocheb525c52013-07-10 11:40:50 +0100984 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
985 if (it == active_streams_.end()) {
986 NOTREACHED();
987 return;
988 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000989
Ben Murdocheb525c52013-07-10 11:40:50 +0100990 ResetStreamIterator(it, status, description);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000991}
992
993bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
994 return ContainsKey(active_streams_, stream_id);
995}
996
997LoadState SpdySession::GetLoadState() const {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000998 // Just report that we're idle since the session could be doing
999 // many things concurrently.
1000 return LOAD_STATE_IDLE;
1001}
1002
Ben Murdocheb525c52013-07-10 11:40:50 +01001003void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1004 int status) {
1005 // TODO(mbelshe): We should send a RST_STREAM control frame here
1006 // so that the server can cancel a large send.
1007
Ben Murdocheb525c52013-07-10 11:40:50 +01001008 scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1009 active_streams_.erase(it);
1010
Ben Murdochca12bfa2013-07-23 11:17:05 +01001011 // TODO(akalin): When SpdyStream was ref-counted (and
1012 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1013 // was only done when status was not OK. This meant that pushed
1014 // streams can still be claimed after they're closed. This is
1015 // probably something that we still want to support, although server
1016 // push is hardly used. Write tests for this and fix this. (See
1017 // http://crbug.com/261712 .)
1018 if (owned_stream->type() == SPDY_PUSH_STREAM)
1019 unclaimed_pushed_streams_.erase(owned_stream->url());
1020
Ben Murdocheb525c52013-07-10 11:40:50 +01001021 DeleteStream(owned_stream.Pass(), status);
1022}
1023
1024void SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
1025 int status) {
1026 scoped_ptr<SpdyStream> owned_stream(*it);
1027 created_streams_.erase(it);
1028 DeleteStream(owned_stream.Pass(), status);
1029}
1030
1031void SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
1032 SpdyRstStreamStatus status,
1033 const std::string& description) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01001034 // Send the RST_STREAM frame first as CloseActiveStreamIterator()
1035 // may close us.
Ben Murdocheb525c52013-07-10 11:40:50 +01001036 SpdyStreamId stream_id = it->first;
1037 RequestPriority priority = it->second.stream->priority();
Ben Murdochbbcdd452013-07-25 10:06:34 +01001038 EnqueueResetStreamFrame(stream_id, priority, status, description);
1039
Ben Murdocheb525c52013-07-10 11:40:50 +01001040 // Removes any pending writes for the stream except for possibly an
1041 // in-flight one.
1042 CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
Ben Murdocheb525c52013-07-10 11:40:50 +01001043}
1044
Ben Murdochbbcdd452013-07-25 10:06:34 +01001045void SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
1046 RequestPriority priority,
1047 SpdyRstStreamStatus status,
1048 const std::string& description) {
Ben Murdocheb525c52013-07-10 11:40:50 +01001049 DCHECK_NE(stream_id, 0u);
Ben Murdocheb525c52013-07-10 11:40:50 +01001050
1051 net_log().AddEvent(
1052 NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM,
1053 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
1054
1055 DCHECK(buffered_spdy_framer_.get());
1056 scoped_ptr<SpdyFrame> rst_frame(
1057 buffered_spdy_framer_->CreateRstStream(stream_id, status));
1058
1059 EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass());
1060 RecordProtocolErrorHistogram(
1061 static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID));
1062}
1063
Ben Murdochca12bfa2013-07-23 11:17:05 +01001064void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
1065 CHECK(!in_io_loop_);
1066 DCHECK_NE(availability_state_, STATE_CLOSED);
1067 DCHECK_EQ(read_state_, expected_read_state);
1068
1069 result = DoReadLoop(expected_read_state, result);
1070
1071 if (availability_state_ == STATE_CLOSED) {
1072 DCHECK_EQ(result, error_on_close_);
1073 DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1074 RemoveFromPool();
1075 return;
1076 }
1077
1078 DCHECK(result == OK || result == ERR_IO_PENDING);
Ben Murdoch9ab55632013-07-18 11:57:30 +01001079}
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001080
Ben Murdochca12bfa2013-07-23 11:17:05 +01001081int SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
1082 CHECK(!in_io_loop_);
1083 DCHECK_NE(availability_state_, STATE_CLOSED);
1084 DCHECK_EQ(read_state_, expected_read_state);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001085
Ben Murdochca12bfa2013-07-23 11:17:05 +01001086 in_io_loop_ = true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001087
Ben Murdochca12bfa2013-07-23 11:17:05 +01001088 int bytes_read_without_yielding = 0;
1089
1090 // Loop until the session is closed, the read becomes blocked, or
1091 // the read limit is exceeded.
1092 while (true) {
1093 switch (read_state_) {
1094 case READ_STATE_DO_READ:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001095 DCHECK_EQ(result, OK);
1096 result = DoRead();
1097 break;
Ben Murdochca12bfa2013-07-23 11:17:05 +01001098 case READ_STATE_DO_READ_COMPLETE:
1099 if (result > 0)
1100 bytes_read_without_yielding += result;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001101 result = DoReadComplete(result);
1102 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001103 default:
Ben Murdochca12bfa2013-07-23 11:17:05 +01001104 NOTREACHED() << "read_state_: " << read_state_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001105 break;
1106 }
Ben Murdochca12bfa2013-07-23 11:17:05 +01001107
1108 if (availability_state_ == STATE_CLOSED) {
1109 DCHECK_EQ(result, error_on_close_);
1110 DCHECK_LT(result, ERR_IO_PENDING);
1111 break;
1112 }
1113
1114 if (result == ERR_IO_PENDING)
1115 break;
1116
1117 if (bytes_read_without_yielding > kMaxReadBytesWithoutYielding) {
1118 read_state_ = READ_STATE_DO_READ;
1119 base::MessageLoop::current()->PostTask(
1120 FROM_HERE,
1121 base::Bind(&SpdySession::PumpReadLoop,
1122 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
1123 result = ERR_IO_PENDING;
1124 break;
1125 }
1126 }
1127
1128 CHECK(in_io_loop_);
1129 in_io_loop_ = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001130
Ben Murdoch9ab55632013-07-18 11:57:30 +01001131 return result;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001132}
1133
1134int SpdySession::DoRead() {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001135 CHECK(in_io_loop_);
1136 DCHECK_NE(availability_state_, STATE_CLOSED);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001137
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01001138 CHECK(connection_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001139 CHECK(connection_->socket());
Ben Murdochca12bfa2013-07-23 11:17:05 +01001140 read_state_ = READ_STATE_DO_READ_COMPLETE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001141 return connection_->socket()->Read(
1142 read_buffer_.get(),
1143 kReadBufferSize,
Ben Murdochca12bfa2013-07-23 11:17:05 +01001144 base::Bind(&SpdySession::PumpReadLoop,
1145 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001146}
1147
1148int SpdySession::DoReadComplete(int result) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001149 CHECK(in_io_loop_);
1150 DCHECK_NE(availability_state_, STATE_CLOSED);
1151
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001152 // Parse a frame. For now this code requires that the frame fit into our
Ben Murdochca12bfa2013-07-23 11:17:05 +01001153 // buffer (kReadBufferSize).
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001154 // TODO(mbelshe): support arbitrarily large frames!
1155
Ben Murdochca12bfa2013-07-23 11:17:05 +01001156 if (result == 0) {
1157 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
1158 total_bytes_received_, 1, 100000000, 50);
1159 CloseSessionResult close_session_result =
1160 DoCloseSession(ERR_CONNECTION_CLOSED, "Connection closed");
1161 DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1162 DCHECK_EQ(availability_state_, STATE_CLOSED);
1163 DCHECK_EQ(error_on_close_, ERR_CONNECTION_CLOSED);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001164 return ERR_CONNECTION_CLOSED;
1165 }
1166
Ben Murdochca12bfa2013-07-23 11:17:05 +01001167 if (result < 0) {
1168 CloseSessionResult close_session_result =
1169 DoCloseSession(static_cast<Error>(result), "result is < 0.");
1170 DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1171 DCHECK_EQ(availability_state_, STATE_CLOSED);
1172 DCHECK_EQ(error_on_close_, result);
1173 return result;
1174 }
1175
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001176 total_bytes_received_ += result;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001177
Ben Murdochca12bfa2013-07-23 11:17:05 +01001178 last_activity_time_ = time_func_();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001179
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001180 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001181 char* data = read_buffer_->data();
Ben Murdochca12bfa2013-07-23 11:17:05 +01001182 while (result > 0) {
1183 uint32 bytes_processed = buffered_spdy_framer_->ProcessInput(data, result);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001184 result -= bytes_processed;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001185 data += bytes_processed;
Ben Murdochca12bfa2013-07-23 11:17:05 +01001186
1187 if (availability_state_ == STATE_CLOSED) {
1188 DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1189 return error_on_close_;
1190 }
1191
1192 DCHECK_EQ(buffered_spdy_framer_->error_code(), SpdyFramer::SPDY_NO_ERROR);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001193 }
1194
Ben Murdochca12bfa2013-07-23 11:17:05 +01001195 read_state_ = READ_STATE_DO_READ;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001196 return OK;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001197}
1198
Ben Murdochca12bfa2013-07-23 11:17:05 +01001199void SpdySession::PumpWriteLoop(WriteState expected_write_state, int result) {
1200 CHECK(!in_io_loop_);
1201 DCHECK_NE(availability_state_, STATE_CLOSED);
1202 DCHECK_EQ(write_state_, expected_write_state);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001203
Ben Murdochca12bfa2013-07-23 11:17:05 +01001204 result = DoWriteLoop(expected_write_state, result);
1205
1206 if (availability_state_ == STATE_CLOSED) {
1207 DCHECK_EQ(result, error_on_close_);
1208 DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1209 RemoveFromPool();
1210 return;
1211 }
1212
1213 DCHECK(result == OK || result == ERR_IO_PENDING);
1214}
1215
1216int SpdySession::DoWriteLoop(WriteState expected_write_state, int result) {
1217 CHECK(!in_io_loop_);
1218 DCHECK_NE(availability_state_, STATE_CLOSED);
1219 DCHECK_NE(write_state_, WRITE_STATE_IDLE);
1220 DCHECK_EQ(write_state_, expected_write_state);
1221
1222 in_io_loop_ = true;
1223
1224 // Loop until the session is closed or the write becomes blocked.
1225 while (true) {
1226 switch (write_state_) {
1227 case WRITE_STATE_DO_WRITE:
1228 DCHECK_EQ(result, OK);
1229 result = DoWrite();
1230 break;
1231 case WRITE_STATE_DO_WRITE_COMPLETE:
1232 result = DoWriteComplete(result);
1233 break;
1234 case WRITE_STATE_IDLE:
1235 default:
1236 NOTREACHED() << "write_state_: " << write_state_;
1237 break;
1238 }
1239
1240 if (availability_state_ == STATE_CLOSED) {
1241 DCHECK_EQ(result, error_on_close_);
1242 DCHECK_LT(result, ERR_IO_PENDING);
1243 break;
1244 }
1245
1246 if (write_state_ == WRITE_STATE_IDLE) {
1247 DCHECK_EQ(result, ERR_IO_PENDING);
1248 break;
1249 }
1250
1251 if (result == ERR_IO_PENDING)
1252 break;
1253 }
1254
1255 CHECK(in_io_loop_);
1256 in_io_loop_ = false;
1257
1258 return result;
1259}
1260
1261int SpdySession::DoWrite() {
1262 CHECK(in_io_loop_);
1263 DCHECK_NE(availability_state_, STATE_CLOSED);
1264
1265 DCHECK(buffered_spdy_framer_);
1266 if (in_flight_write_) {
1267 DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
1268 } else {
1269 // Grab the next frame to send.
1270 SpdyFrameType frame_type = DATA;
1271 scoped_ptr<SpdyBufferProducer> producer;
1272 base::WeakPtr<SpdyStream> stream;
1273 if (!write_queue_.Dequeue(&frame_type, &producer, &stream)) {
1274 write_state_ = WRITE_STATE_IDLE;
1275 return ERR_IO_PENDING;
1276 }
1277
1278 if (stream.get())
1279 DCHECK(!stream->IsClosed());
1280
1281 // Activate the stream only when sending the SYN_STREAM frame to
1282 // guarantee monotonically-increasing stream IDs.
1283 if (frame_type == SYN_STREAM) {
1284 if (stream.get() && stream->stream_id() == 0) {
1285 scoped_ptr<SpdyStream> owned_stream =
1286 ActivateCreatedStream(stream.get());
1287 InsertActivatedStream(owned_stream.Pass());
1288 } else {
1289 NOTREACHED();
1290 return ERR_UNEXPECTED;
1291 }
1292 }
1293
1294 in_flight_write_ = producer->ProduceBuffer();
1295 if (!in_flight_write_) {
1296 NOTREACHED();
1297 return ERR_UNEXPECTED;
1298 }
1299 in_flight_write_frame_type_ = frame_type;
1300 in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
1301 DCHECK_GE(in_flight_write_frame_size_,
1302 buffered_spdy_framer_->GetFrameMinimumSize());
1303 in_flight_write_stream_ = stream;
1304 }
1305
1306 write_state_ = WRITE_STATE_DO_WRITE_COMPLETE;
1307
1308 // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
1309 // with Socket implementations that don't store their IOBuffer
1310 // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
1311 scoped_refptr<IOBuffer> write_io_buffer =
1312 in_flight_write_->GetIOBufferForRemainingData();
1313 return connection_->socket()->Write(
1314 write_io_buffer.get(),
1315 in_flight_write_->GetRemainingSize(),
1316 base::Bind(&SpdySession::PumpWriteLoop,
1317 weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE_COMPLETE));
1318}
1319
1320int SpdySession::DoWriteComplete(int result) {
1321 CHECK(in_io_loop_);
1322 DCHECK_NE(availability_state_, STATE_CLOSED);
1323 DCHECK_NE(result, ERR_IO_PENDING);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001324 DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001325
Ben Murdochca12bfa2013-07-23 11:17:05 +01001326 last_activity_time_ = time_func_();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001327
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001328 if (result < 0) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001329 DCHECK_NE(result, ERR_IO_PENDING);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001330 in_flight_write_.reset();
1331 in_flight_write_frame_type_ = DATA;
1332 in_flight_write_frame_size_ = 0;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001333 in_flight_write_stream_.reset();
Ben Murdochca12bfa2013-07-23 11:17:05 +01001334 CloseSessionResult close_session_result =
1335 DoCloseSession(static_cast<Error>(result), "Write error");
1336 DCHECK_EQ(close_session_result, SESSION_CLOSED_BUT_NOT_REMOVED);
1337 DCHECK_EQ(availability_state_, STATE_CLOSED);
1338 DCHECK_EQ(error_on_close_, result);
1339 return result;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001340 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001341
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001342 // It should not be possible to have written more bytes than our
1343 // in_flight_write_.
1344 DCHECK_LE(static_cast<size_t>(result),
1345 in_flight_write_->GetRemainingSize());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001346
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001347 if (result > 0) {
1348 in_flight_write_->Consume(static_cast<size_t>(result));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001349
1350 // We only notify the stream when we've fully written the pending frame.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001351 if (in_flight_write_->GetRemainingSize() == 0) {
1352 // It is possible that the stream was cancelled while we were
1353 // writing to the socket.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001354 if (in_flight_write_stream_.get()) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001355 DCHECK_GT(in_flight_write_frame_size_, 0u);
1356 in_flight_write_stream_->OnFrameWriteComplete(
1357 in_flight_write_frame_type_,
1358 in_flight_write_frame_size_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001359 }
1360
1361 // Cleanup the write which just completed.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001362 in_flight_write_.reset();
1363 in_flight_write_frame_type_ = DATA;
1364 in_flight_write_frame_size_ = 0;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001365 in_flight_write_stream_.reset();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001366 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001367 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001368
Ben Murdochca12bfa2013-07-23 11:17:05 +01001369 write_state_ = WRITE_STATE_DO_WRITE;
1370 return OK;
Ben Murdoch9ab55632013-07-18 11:57:30 +01001371}
1372
Ben Murdochca12bfa2013-07-23 11:17:05 +01001373void SpdySession::DcheckGoingAway() const {
1374 DCHECK_GE(availability_state_, STATE_GOING_AWAY);
1375 if (DCHECK_IS_ON()) {
1376 for (int i = 0; i < NUM_PRIORITIES; ++i) {
1377 DCHECK(pending_create_stream_queues_[i].empty());
Ben Murdoch9ab55632013-07-18 11:57:30 +01001378 }
Ben Murdoch9ab55632013-07-18 11:57:30 +01001379 }
Ben Murdochca12bfa2013-07-23 11:17:05 +01001380 DCHECK(pending_stream_request_completions_.empty());
1381 DCHECK(created_streams_.empty());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001382}
1383
Ben Murdochca12bfa2013-07-23 11:17:05 +01001384void SpdySession::DcheckClosed() const {
1385 DcheckGoingAway();
1386 DCHECK_EQ(availability_state_, STATE_CLOSED);
1387 DCHECK_LT(error_on_close_, ERR_IO_PENDING);
1388 DCHECK(active_streams_.empty());
1389 DCHECK(unclaimed_pushed_streams_.empty());
1390 DCHECK(write_queue_.IsEmpty());
1391}
1392
1393void SpdySession::StartGoingAway(SpdyStreamId last_good_stream_id,
1394 Error status) {
1395 DCHECK_GE(availability_state_, STATE_GOING_AWAY);
Ben Murdochbbcdd452013-07-25 10:06:34 +01001396
Ben Murdochca12bfa2013-07-23 11:17:05 +01001397 // The loops below are carefully written to avoid reentrancy problems.
Ben Murdochbbcdd452013-07-25 10:06:34 +01001398 //
1399 // TODO(akalin): Any of the functions below can cause |this| to be
1400 // deleted, so handle that below (and add tests for it).
Ben Murdochca12bfa2013-07-23 11:17:05 +01001401
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001402 for (int i = 0; i < NUM_PRIORITIES; ++i) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001403 PendingStreamRequestQueue queue;
1404 queue.swap(pending_create_stream_queues_[i]);
1405 for (PendingStreamRequestQueue::const_iterator it = queue.begin();
1406 it != queue.end(); ++it) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01001407 CHECK(*it);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001408 (*it)->OnRequestCompleteFailure(ERR_ABORTED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001409 }
1410 }
1411
Ben Murdochca12bfa2013-07-23 11:17:05 +01001412 PendingStreamRequestCompletionSet pending_completions;
1413 pending_completions.swap(pending_stream_request_completions_);
1414 for (PendingStreamRequestCompletionSet::const_iterator it =
1415 pending_completions.begin();
1416 it != pending_completions.end(); ++it) {
1417 (*it)->OnRequestCompleteFailure(ERR_ABORTED);
1418 }
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01001419
1420 while (true) {
1421 ActiveStreamMap::iterator it =
1422 active_streams_.lower_bound(last_good_stream_id + 1);
1423 if (it == active_streams_.end())
1424 break;
Ben Murdochca12bfa2013-07-23 11:17:05 +01001425 LogAbandonedActiveStream(it, status);
Ben Murdocheb525c52013-07-10 11:40:50 +01001426 CloseActiveStreamIterator(it, status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001427 }
1428
1429 while (!created_streams_.empty()) {
1430 CreatedStreamSet::iterator it = created_streams_.begin();
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001431 LogAbandonedStream(*it, status);
Ben Murdocheb525c52013-07-10 11:40:50 +01001432 CloseCreatedStreamIterator(it, status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001433 }
1434
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001435 write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id);
Ben Murdochca12bfa2013-07-23 11:17:05 +01001436
1437 DcheckGoingAway();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001438}
1439
Ben Murdochca12bfa2013-07-23 11:17:05 +01001440void SpdySession::MaybeFinishGoingAway() {
1441 DcheckGoingAway();
1442 if (active_streams_.empty() && availability_state_ != STATE_CLOSED) {
1443 CloseSessionResult result =
1444 DoCloseSession(ERR_CONNECTION_CLOSED, "Finished going away");
1445 DCHECK_NE(result, SESSION_ALREADY_CLOSED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001446 }
Ben Murdochca12bfa2013-07-23 11:17:05 +01001447}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001448
Ben Murdochca12bfa2013-07-23 11:17:05 +01001449SpdySession::CloseSessionResult SpdySession::DoCloseSession(
1450 Error err,
1451 const std::string& description) {
1452 DCHECK_LT(err, ERR_IO_PENDING);
1453
1454 if (availability_state_ == STATE_CLOSED)
1455 return SESSION_ALREADY_CLOSED;
1456
1457 net_log_.AddEvent(
1458 NetLog::TYPE_SPDY_SESSION_CLOSE,
1459 base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
1460
1461 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err);
1462 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.OtherErrors",
1463 total_bytes_received_, 1, 100000000, 50);
1464
1465 // |pool_| will be NULL when |InitializeWithSocket()| is in the
1466 // call stack.
1467 if (pool_ && availability_state_ != STATE_GOING_AWAY)
1468 pool_->MakeSessionUnavailable(GetWeakPtr());
1469
1470 availability_state_ = STATE_CLOSED;
1471 error_on_close_ = err;
1472
1473 StartGoingAway(0, err);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001474 write_queue_.Clear();
Ben Murdochca12bfa2013-07-23 11:17:05 +01001475
1476 DcheckClosed();
1477
1478 if (in_io_loop_)
1479 return SESSION_CLOSED_BUT_NOT_REMOVED;
1480
1481 RemoveFromPool();
1482 return SESSION_CLOSED_AND_REMOVED;
1483}
1484
1485void SpdySession::RemoveFromPool() {
1486 DcheckClosed();
1487 CHECK(pool_);
1488
1489 SpdySessionPool* pool = pool_;
1490 pool_ = NULL;
1491 pool->RemoveUnavailableSession(GetWeakPtr());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001492}
1493
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001494void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001495 DCHECK(stream);
1496 std::string description = base::StringPrintf(
Ben Murdochca12bfa2013-07-23 11:17:05 +01001497 "ABANDONED (stream_id=%d): ", stream->stream_id()) +
1498 stream->url().spec();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001499 stream->LogStreamError(status, description);
Ben Murdochca12bfa2013-07-23 11:17:05 +01001500 // We don't increment the streams abandoned counter here. If the
1501 // stream isn't active (i.e., it hasn't written anything to the wire
1502 // yet) then it's as if it never existed. If it is active, then
1503 // LogAbandonedActiveStream() will increment the counters.
1504}
1505
1506void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
1507 Error status) {
1508 DCHECK_GT(it->first, 0u);
1509 LogAbandonedStream(it->second.stream, status);
1510 ++streams_abandoned_count_;
1511 base::StatsCounter abandoned_streams("spdy.abandoned_streams");
1512 abandoned_streams.Increment();
1513 if (it->second.stream->type() == SPDY_PUSH_STREAM &&
1514 unclaimed_pushed_streams_.find(it->second.stream->url()) !=
1515 unclaimed_pushed_streams_.end()) {
1516 base::StatsCounter abandoned_push_streams("spdy.abandoned_push_streams");
1517 abandoned_push_streams.Increment();
1518 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001519}
1520
1521int SpdySession::GetNewStreamId() {
1522 int id = stream_hi_water_mark_;
1523 stream_hi_water_mark_ += 2;
1524 if (stream_hi_water_mark_ > 0x7fff)
1525 stream_hi_water_mark_ = 1;
1526 return id;
1527}
1528
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001529void SpdySession::CloseSessionOnError(Error err,
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001530 const std::string& description) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001531 // We may be called from anywhere, so we can't expect a particular
1532 // return value.
1533 ignore_result(DoCloseSession(err, description));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001534}
1535
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001536base::Value* SpdySession::GetInfoAsValue() const {
1537 base::DictionaryValue* dict = new base::DictionaryValue();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001538
1539 dict->SetInteger("source_id", net_log_.source().id);
1540
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001541 dict->SetString("host_port_pair", host_port_pair().ToString());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001542 if (!pooled_aliases_.empty()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001543 base::ListValue* alias_list = new base::ListValue();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001544 for (std::set<SpdySessionKey>::const_iterator it =
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001545 pooled_aliases_.begin();
1546 it != pooled_aliases_.end(); it++) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001547 alias_list->Append(new base::StringValue(
1548 it->host_port_pair().ToString()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001549 }
1550 dict->Set("aliases", alias_list);
1551 }
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001552 dict->SetString("proxy", host_port_proxy_pair().second.ToURI());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001553
1554 dict->SetInteger("active_streams", active_streams_.size());
1555
1556 dict->SetInteger("unclaimed_pushed_streams",
Ben Murdochca12bfa2013-07-23 11:17:05 +01001557 unclaimed_pushed_streams_.size());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001558
1559 dict->SetBoolean("is_secure", is_secure_);
1560
1561 dict->SetString("protocol_negotiated",
1562 SSLClientSocket::NextProtoToString(
1563 connection_->socket()->GetNegotiatedProtocol()));
1564
Ben Murdochca12bfa2013-07-23 11:17:05 +01001565 dict->SetInteger("error", error_on_close_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001566 dict->SetInteger("max_concurrent_streams", max_concurrent_streams_);
1567
1568 dict->SetInteger("streams_initiated_count", streams_initiated_count_);
1569 dict->SetInteger("streams_pushed_count", streams_pushed_count_);
1570 dict->SetInteger("streams_pushed_and_claimed_count",
1571 streams_pushed_and_claimed_count_);
1572 dict->SetInteger("streams_abandoned_count", streams_abandoned_count_);
1573 DCHECK(buffered_spdy_framer_.get());
1574 dict->SetInteger("frames_received", buffered_spdy_framer_->frames_received());
1575
1576 dict->SetBoolean("sent_settings", sent_settings_);
1577 dict->SetBoolean("received_settings", received_settings_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001578
1579 dict->SetInteger("send_window_size", session_send_window_size_);
1580 dict->SetInteger("recv_window_size", session_recv_window_size_);
1581 dict->SetInteger("unacked_recv_window_bytes",
1582 session_unacked_recv_window_bytes_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001583 return dict;
1584}
1585
1586bool SpdySession::IsReused() const {
1587 return buffered_spdy_framer_->frames_received() > 0;
1588}
1589
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001590bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id,
1591 LoadTimingInfo* load_timing_info) const {
1592 return connection_->GetLoadTimingInfo(stream_id != kFirstStreamId,
1593 load_timing_info);
1594}
1595
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001596int SpdySession::GetPeerAddress(IPEndPoint* address) const {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001597 int rv = ERR_SOCKET_NOT_CONNECTED;
1598 if (connection_->socket()) {
1599 rv = connection_->socket()->GetPeerAddress(address);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001600 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001601
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001602 UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetPeerAddress",
1603 rv == ERR_SOCKET_NOT_CONNECTED);
1604
1605 return rv;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001606}
1607
1608int SpdySession::GetLocalAddress(IPEndPoint* address) const {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001609 int rv = ERR_SOCKET_NOT_CONNECTED;
1610 if (connection_->socket()) {
1611 rv = connection_->socket()->GetLocalAddress(address);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001612 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001613
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001614 UMA_HISTOGRAM_BOOLEAN("Net.SpdySessionSocketNotConnectedGetLocalAddress",
1615 rv == ERR_SOCKET_NOT_CONNECTED);
1616
1617 return rv;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001618}
1619
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001620void SpdySession::EnqueueSessionWrite(RequestPriority priority,
1621 SpdyFrameType frame_type,
1622 scoped_ptr<SpdyFrame> frame) {
1623 DCHECK(frame_type == RST_STREAM ||
1624 frame_type == SETTINGS ||
1625 frame_type == WINDOW_UPDATE ||
1626 frame_type == PING);
1627 EnqueueWrite(
1628 priority, frame_type,
1629 scoped_ptr<SpdyBufferProducer>(
1630 new SimpleBufferProducer(
1631 scoped_ptr<SpdyBuffer>(new SpdyBuffer(frame.Pass())))),
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001632 base::WeakPtr<SpdyStream>());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001633}
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001634
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001635void SpdySession::EnqueueWrite(RequestPriority priority,
1636 SpdyFrameType frame_type,
1637 scoped_ptr<SpdyBufferProducer> producer,
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001638 const base::WeakPtr<SpdyStream>& stream) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001639 if (availability_state_ == STATE_CLOSED)
1640 return;
1641
1642 bool was_idle = write_queue_.IsEmpty();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001643 write_queue_.Enqueue(priority, frame_type, producer.Pass(), stream);
Ben Murdochca12bfa2013-07-23 11:17:05 +01001644 if (write_state_ == WRITE_STATE_IDLE) {
1645 DCHECK(was_idle);
1646 DCHECK(!in_flight_write_);
1647 write_state_ = WRITE_STATE_DO_WRITE;
1648 base::MessageLoop::current()->PostTask(
1649 FROM_HERE,
1650 base::Bind(&SpdySession::PumpWriteLoop,
1651 weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE, OK));
1652 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001653}
1654
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001655void SpdySession::InsertCreatedStream(scoped_ptr<SpdyStream> stream) {
1656 DCHECK_EQ(stream->stream_id(), 0u);
1657 DCHECK(created_streams_.find(stream.get()) == created_streams_.end());
1658 created_streams_.insert(stream.release());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001659}
1660
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001661scoped_ptr<SpdyStream> SpdySession::ActivateCreatedStream(SpdyStream* stream) {
1662 DCHECK_EQ(stream->stream_id(), 0u);
1663 DCHECK(created_streams_.find(stream) != created_streams_.end());
1664 stream->set_stream_id(GetNewStreamId());
1665 scoped_ptr<SpdyStream> owned_stream(stream);
1666 created_streams_.erase(stream);
1667 return owned_stream.Pass();
1668}
1669
1670void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1671 SpdyStreamId stream_id = stream->stream_id();
1672 DCHECK_NE(stream_id, 0u);
1673 std::pair<ActiveStreamMap::iterator, bool> result =
Ben Murdocheb525c52013-07-10 11:40:50 +01001674 active_streams_.insert(
1675 std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001676 if (result.second) {
1677 ignore_result(stream.release());
1678 } else {
1679 NOTREACHED();
1680 }
1681}
1682
1683void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001684 if (in_flight_write_stream_.get() == stream.get()) {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001685 // If we're deleting the stream for the in-flight write, we still
1686 // need to let the write complete, so we clear
1687 // |in_flight_write_stream_| and let the write finish on its own
1688 // without notifying |in_flight_write_stream_|.
1689 in_flight_write_stream_.reset();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001690 }
1691
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001692 write_queue_.RemovePendingWritesForStream(stream->GetWeakPtr());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001693
Ben Murdochbbcdd452013-07-25 10:06:34 +01001694 // |stream->OnClose()| may end up closing |this|, so detect that.
1695 base::WeakPtr<SpdySession> weak_this = GetWeakPtr();
1696
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001697 stream->OnClose(status);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001698
Ben Murdochbbcdd452013-07-25 10:06:34 +01001699 if (!weak_this)
1700 return;
1701
Ben Murdochca12bfa2013-07-23 11:17:05 +01001702 switch (availability_state_) {
1703 case STATE_AVAILABLE:
1704 ProcessPendingStreamRequests();
1705 break;
1706 case STATE_GOING_AWAY:
1707 DcheckGoingAway();
1708 MaybeFinishGoingAway();
1709 break;
1710 case STATE_CLOSED:
1711 // Do nothing.
1712 break;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001713 }
1714}
1715
Ben Murdochca12bfa2013-07-23 11:17:05 +01001716base::WeakPtr<SpdyStream> SpdySession::GetActivePushStream(const GURL& url) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001717 base::StatsCounter used_push_streams("spdy.claimed_push_streams");
1718
Ben Murdochca12bfa2013-07-23 11:17:05 +01001719 PushedStreamMap::iterator unclaimed_it = unclaimed_pushed_streams_.find(url);
1720 if (unclaimed_it == unclaimed_pushed_streams_.end())
Ben Murdocheb525c52013-07-10 11:40:50 +01001721 return base::WeakPtr<SpdyStream>();
1722
Ben Murdochca12bfa2013-07-23 11:17:05 +01001723 SpdyStreamId stream_id = unclaimed_it->second.stream_id;
1724 unclaimed_pushed_streams_.erase(unclaimed_it);
Ben Murdocheb525c52013-07-10 11:40:50 +01001725
Ben Murdochca12bfa2013-07-23 11:17:05 +01001726 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
1727 if (active_it == active_streams_.end()) {
Ben Murdocheb525c52013-07-10 11:40:50 +01001728 NOTREACHED();
1729 return base::WeakPtr<SpdyStream>();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001730 }
Ben Murdocheb525c52013-07-10 11:40:50 +01001731
1732 net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM);
1733 used_push_streams.Increment();
Ben Murdochca12bfa2013-07-23 11:17:05 +01001734 return active_it->second.stream->GetWeakPtr();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001735}
1736
1737bool SpdySession::GetSSLInfo(SSLInfo* ssl_info,
1738 bool* was_npn_negotiated,
1739 NextProto* protocol_negotiated) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001740 *was_npn_negotiated = connection_->socket()->WasNpnNegotiated();
1741 *protocol_negotiated = connection_->socket()->GetNegotiatedProtocol();
1742 return connection_->socket()->GetSSLInfo(ssl_info);
1743}
1744
1745bool SpdySession::GetSSLCertRequestInfo(
1746 SSLCertRequestInfo* cert_request_info) {
1747 if (!is_secure_)
1748 return false;
1749 GetSSLClientSocket()->GetSSLCertRequestInfo(cert_request_info);
1750 return true;
1751}
1752
1753ServerBoundCertService* SpdySession::GetServerBoundCertService() const {
1754 if (!is_secure_)
1755 return NULL;
1756 return GetSSLClientSocket()->GetServerBoundCertService();
1757}
1758
1759void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001760 CHECK(in_io_loop_);
1761
1762 if (availability_state_ == STATE_CLOSED)
1763 return;
1764
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001765 RecordProtocolErrorHistogram(
1766 static_cast<SpdyProtocolErrorDetails>(error_code));
1767 std::string description = base::StringPrintf(
1768 "SPDY_ERROR error_code: %d.", error_code);
Ben Murdochca12bfa2013-07-23 11:17:05 +01001769 CloseSessionResult result =
1770 DoCloseSession(ERR_SPDY_PROTOCOL_ERROR, description);
1771 DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001772}
1773
1774void SpdySession::OnStreamError(SpdyStreamId stream_id,
1775 const std::string& description) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001776 CHECK(in_io_loop_);
1777
1778 if (availability_state_ == STATE_CLOSED)
1779 return;
1780
Ben Murdocheb525c52013-07-10 11:40:50 +01001781 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
1782 if (it == active_streams_.end()) {
1783 // We still want to send a frame to reset the stream even if we
1784 // don't know anything about it.
Ben Murdochbbcdd452013-07-25 10:06:34 +01001785 EnqueueResetStreamFrame(
Ben Murdocheb525c52013-07-10 11:40:50 +01001786 stream_id, IDLE, RST_STREAM_PROTOCOL_ERROR, description);
1787 return;
1788 }
1789
1790 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, description);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001791}
1792
1793void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
1794 const char* data,
1795 size_t len,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001796 bool fin) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001797 CHECK(in_io_loop_);
1798
1799 if (availability_state_ == STATE_CLOSED)
1800 return;
1801
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001802 DCHECK_LT(len, 1u << 24);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001803 if (net_log().IsLoggingAllEvents()) {
1804 net_log().AddEvent(
1805 NetLog::TYPE_SPDY_SESSION_RECV_DATA,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001806 base::Bind(&NetLogSpdyDataCallback, stream_id, len, fin));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001807 }
1808
Ben Murdocheb525c52013-07-10 11:40:50 +01001809 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001810
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001811 // By the time data comes in, the stream may already be inactive.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001812 if (it == active_streams_.end())
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001813 return;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001814
Ben Murdocheb525c52013-07-10 11:40:50 +01001815 SpdyStream* stream = it->second.stream;
1816 CHECK_EQ(stream->stream_id(), stream_id);
1817
1818 if (it->second.waiting_for_syn_reply) {
1819 const std::string& error = "Data received before SYN_REPLY.";
1820 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
1821 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
1822 return;
1823 }
1824
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001825 scoped_ptr<SpdyBuffer> buffer;
1826 if (data) {
1827 DCHECK_GT(len, 0u);
1828 buffer.reset(new SpdyBuffer(data, len));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001829
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001830 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
1831 DecreaseRecvWindowSize(static_cast<int32>(len));
1832 buffer->AddConsumeCallback(
1833 base::Bind(&SpdySession::OnReadBufferConsumed,
1834 weak_factory_.GetWeakPtr()));
1835 }
1836 } else {
1837 DCHECK_EQ(len, 0u);
1838 }
Ben Murdocheb525c52013-07-10 11:40:50 +01001839 stream->OnDataReceived(buffer.Pass());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001840}
1841
1842void SpdySession::OnSettings(bool clear_persisted) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001843 CHECK(in_io_loop_);
1844
1845 if (availability_state_ == STATE_CLOSED)
1846 return;
1847
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001848 if (clear_persisted)
1849 http_server_properties_->ClearSpdySettings(host_port_pair());
1850
1851 if (net_log_.IsLoggingAllEvents()) {
1852 net_log_.AddEvent(
1853 NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS,
1854 base::Bind(&NetLogSpdySettingsCallback, host_port_pair(),
1855 clear_persisted));
1856 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001857}
1858
1859void SpdySession::OnSetting(SpdySettingsIds id,
1860 uint8 flags,
1861 uint32 value) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001862 CHECK(in_io_loop_);
1863
1864 if (availability_state_ == STATE_CLOSED)
1865 return;
1866
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001867 HandleSetting(id, value);
1868 http_server_properties_->SetSpdySetting(
1869 host_port_pair(),
1870 id,
1871 static_cast<SpdySettingsFlags>(flags),
1872 value);
1873 received_settings_ = true;
1874
1875 // Log the setting.
1876 net_log_.AddEvent(
1877 NetLog::TYPE_SPDY_SESSION_RECV_SETTING,
1878 base::Bind(&NetLogSpdySettingCallback,
1879 id, static_cast<SpdySettingsFlags>(flags), value));
1880}
1881
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01001882void SpdySession::OnSendCompressedFrame(
1883 SpdyStreamId stream_id,
1884 SpdyFrameType type,
1885 size_t payload_len,
1886 size_t frame_len) {
1887 if (type != SYN_STREAM)
1888 return;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001889
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01001890 DCHECK(buffered_spdy_framer_.get());
1891 size_t compressed_len =
1892 frame_len - buffered_spdy_framer_->GetSynStreamMinimumSize();
1893
1894 if (payload_len) {
1895 // Make sure we avoid early decimal truncation.
1896 int compression_pct = 100 - (100 * compressed_len) / payload_len;
1897 UMA_HISTOGRAM_PERCENTAGE("Net.SpdySynStreamCompressionPercentage",
1898 compression_pct);
1899 }
1900}
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001901
Ben Murdocheb525c52013-07-10 11:40:50 +01001902int SpdySession::OnInitialResponseHeadersReceived(
1903 const SpdyHeaderBlock& response_headers,
1904 base::Time response_time,
1905 base::TimeTicks recv_first_byte_time,
1906 SpdyStream* stream) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001907 CHECK(in_io_loop_);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001908 SpdyStreamId stream_id = stream->stream_id();
1909 // May invalidate |stream|.
Ben Murdocheb525c52013-07-10 11:40:50 +01001910 int rv = stream->OnInitialResponseHeadersReceived(
1911 response_headers, response_time, recv_first_byte_time);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001912 if (rv < 0) {
1913 DCHECK_NE(rv, ERR_IO_PENDING);
Ben Murdocheb525c52013-07-10 11:40:50 +01001914 DCHECK(active_streams_.find(stream_id) == active_streams_.end());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001915 }
Ben Murdocheb525c52013-07-10 11:40:50 +01001916 return rv;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001917}
1918
1919void SpdySession::OnSynStream(SpdyStreamId stream_id,
1920 SpdyStreamId associated_stream_id,
1921 SpdyPriority priority,
1922 uint8 credential_slot,
1923 bool fin,
1924 bool unidirectional,
1925 const SpdyHeaderBlock& headers) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01001926 CHECK(in_io_loop_);
1927
1928 if (availability_state_ == STATE_CLOSED)
1929 return;
1930
Ben Murdocheb525c52013-07-10 11:40:50 +01001931 base::Time response_time = base::Time::Now();
Ben Murdochca12bfa2013-07-23 11:17:05 +01001932 base::TimeTicks recv_first_byte_time = time_func_();
Ben Murdocheb525c52013-07-10 11:40:50 +01001933
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001934 if (net_log_.IsLoggingAllEvents()) {
1935 net_log_.AddEvent(
1936 NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM,
1937 base::Bind(&NetLogSpdySynCallback,
1938 &headers, fin, unidirectional,
1939 stream_id, associated_stream_id));
1940 }
1941
1942 // Server-initiated streams should have even sequence numbers.
1943 if ((stream_id & 0x1) != 0) {
1944 LOG(WARNING) << "Received invalid OnSyn stream id " << stream_id;
1945 return;
1946 }
1947
1948 if (IsStreamActive(stream_id)) {
1949 LOG(WARNING) << "Received OnSyn for active stream " << stream_id;
1950 return;
1951 }
1952
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001953 RequestPriority request_priority =
1954 ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion());
1955
Ben Murdochca12bfa2013-07-23 11:17:05 +01001956 if (availability_state_ == STATE_GOING_AWAY) {
1957 // TODO(akalin): This behavior isn't in the SPDY spec, although it
1958 // probably should be.
Ben Murdochbbcdd452013-07-25 10:06:34 +01001959 EnqueueResetStreamFrame(stream_id, request_priority,
1960 RST_STREAM_REFUSED_STREAM,
1961 "OnSyn received when going away");
Ben Murdochca12bfa2013-07-23 11:17:05 +01001962 return;
1963 }
1964
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001965 if (associated_stream_id == 0) {
1966 std::string description = base::StringPrintf(
1967 "Received invalid OnSyn associated stream id %d for stream %d",
1968 associated_stream_id, stream_id);
Ben Murdochbbcdd452013-07-25 10:06:34 +01001969 EnqueueResetStreamFrame(stream_id, request_priority,
1970 RST_STREAM_REFUSED_STREAM, description);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001971 return;
1972 }
1973
1974 streams_pushed_count_++;
1975
1976 // TODO(mbelshe): DCHECK that this is a GET method?
1977
1978 // Verify that the response had a URL for us.
1979 GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true);
1980 if (!gurl.is_valid()) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01001981 EnqueueResetStreamFrame(
1982 stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR,
1983 "Pushed stream url was invalid: " + gurl.spec());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001984 return;
1985 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001986
1987 // Verify we have a valid stream association.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01001988 ActiveStreamMap::iterator associated_it =
1989 active_streams_.find(associated_stream_id);
1990 if (associated_it == active_streams_.end()) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01001991 EnqueueResetStreamFrame(
Ben Murdocheb525c52013-07-10 11:40:50 +01001992 stream_id, request_priority, RST_STREAM_INVALID_STREAM,
1993 base::StringPrintf(
1994 "Received OnSyn with inactive associated stream %d",
1995 associated_stream_id));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001996 return;
1997 }
1998
1999 // Check that the SYN advertises the same origin as its associated stream.
2000 // Bypass this check if and only if this session is with a SPDY proxy that
2001 // is trusted explicitly via the --trusted-spdy-proxy switch.
2002 if (trusted_spdy_proxy_.Equals(host_port_pair())) {
2003 // Disallow pushing of HTTPS content.
2004 if (gurl.SchemeIs("https")) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01002005 EnqueueResetStreamFrame(
Ben Murdocheb525c52013-07-10 11:40:50 +01002006 stream_id, request_priority, RST_STREAM_REFUSED_STREAM,
2007 base::StringPrintf(
2008 "Rejected push of Cross Origin HTTPS content %d",
2009 associated_stream_id));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002010 }
2011 } else {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002012 GURL associated_url(associated_it->second.stream->GetUrlFromHeaders());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002013 if (associated_url.GetOrigin() != gurl.GetOrigin()) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01002014 EnqueueResetStreamFrame(
Ben Murdocheb525c52013-07-10 11:40:50 +01002015 stream_id, request_priority, RST_STREAM_REFUSED_STREAM,
2016 base::StringPrintf(
2017 "Rejected Cross Origin Push Stream %d",
2018 associated_stream_id));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002019 return;
2020 }
2021 }
2022
2023 // There should not be an existing pushed stream with the same path.
Ben Murdochca12bfa2013-07-23 11:17:05 +01002024 PushedStreamMap::iterator pushed_it =
2025 unclaimed_pushed_streams_.lower_bound(gurl);
2026 if (pushed_it != unclaimed_pushed_streams_.end() &&
2027 pushed_it->first == gurl) {
Ben Murdochbbcdd452013-07-25 10:06:34 +01002028 EnqueueResetStreamFrame(
2029 stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR,
2030 "Received duplicate pushed stream with url: " +
2031 gurl.spec());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002032 return;
2033 }
2034
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002035 scoped_ptr<SpdyStream> stream(
Ben Murdochca12bfa2013-07-23 11:17:05 +01002036 new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002037 request_priority,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002038 stream_initial_send_window_size_,
2039 stream_initial_recv_window_size_,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002040 net_log_));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002041 stream->set_stream_id(stream_id);
2042
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002043 DeleteExpiredPushedStreams();
Ben Murdochca12bfa2013-07-23 11:17:05 +01002044 PushedStreamMap::iterator inserted_pushed_it =
2045 unclaimed_pushed_streams_.insert(
2046 pushed_it,
2047 std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_())));
2048 DCHECK(inserted_pushed_it != pushed_it);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002049
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002050 InsertActivatedStream(stream.Pass());
2051
Ben Murdochca12bfa2013-07-23 11:17:05 +01002052 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
2053 if (active_it == active_streams_.end()) {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002054 NOTREACHED();
2055 return;
2056 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002057
2058 // Parse the headers.
Ben Murdocheb525c52013-07-10 11:40:50 +01002059 if (OnInitialResponseHeadersReceived(
2060 headers, response_time,
Ben Murdochca12bfa2013-07-23 11:17:05 +01002061 recv_first_byte_time, active_it->second.stream) != OK)
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002062 return;
2063
2064 base::StatsCounter push_requests("spdy.pushed_streams");
2065 push_requests.Increment();
2066}
2067
2068void SpdySession::DeleteExpiredPushedStreams() {
2069 if (unclaimed_pushed_streams_.empty())
2070 return;
2071
2072 // Check that adequate time has elapsed since the last sweep.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002073 if (time_func_() < next_unclaimed_push_stream_sweep_time_)
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002074 return;
2075
Ben Murdocheb525c52013-07-10 11:40:50 +01002076 // Gather old streams to delete.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002077 base::TimeTicks minimum_freshness = time_func_() -
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002078 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
Ben Murdocheb525c52013-07-10 11:40:50 +01002079 std::vector<SpdyStreamId> streams_to_close;
2080 for (PushedStreamMap::iterator it = unclaimed_pushed_streams_.begin();
2081 it != unclaimed_pushed_streams_.end(); ++it) {
2082 if (minimum_freshness > it->second.creation_time)
2083 streams_to_close.push_back(it->second.stream_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002084 }
Ben Murdocheb525c52013-07-10 11:40:50 +01002085
Ben Murdochca12bfa2013-07-23 11:17:05 +01002086 for (std::vector<SpdyStreamId>::const_iterator to_close_it =
2087 streams_to_close.begin();
2088 to_close_it != streams_to_close.end(); ++to_close_it) {
2089 ActiveStreamMap::iterator active_it = active_streams_.find(*to_close_it);
2090 if (active_it == active_streams_.end())
Ben Murdocheb525c52013-07-10 11:40:50 +01002091 continue;
2092
Ben Murdochca12bfa2013-07-23 11:17:05 +01002093 LogAbandonedActiveStream(active_it, ERR_INVALID_SPDY_STREAM);
Ben Murdocheb525c52013-07-10 11:40:50 +01002094 // CloseActiveStreamIterator() will remove the stream from
2095 // |unclaimed_pushed_streams_|.
Ben Murdochca12bfa2013-07-23 11:17:05 +01002096 CloseActiveStreamIterator(active_it, ERR_INVALID_SPDY_STREAM);
Ben Murdocheb525c52013-07-10 11:40:50 +01002097 }
2098
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002099 next_unclaimed_push_stream_sweep_time_ = time_func_() +
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002100 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
2101}
2102
2103void SpdySession::OnSynReply(SpdyStreamId stream_id,
2104 bool fin,
2105 const SpdyHeaderBlock& headers) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002106 CHECK(in_io_loop_);
2107
2108 if (availability_state_ == STATE_CLOSED)
2109 return;
2110
Ben Murdocheb525c52013-07-10 11:40:50 +01002111 base::Time response_time = base::Time::Now();
Ben Murdochca12bfa2013-07-23 11:17:05 +01002112 base::TimeTicks recv_first_byte_time = time_func_();
Ben Murdocheb525c52013-07-10 11:40:50 +01002113
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002114 if (net_log().IsLoggingAllEvents()) {
2115 net_log().AddEvent(
2116 NetLog::TYPE_SPDY_SESSION_SYN_REPLY,
2117 base::Bind(&NetLogSpdySynCallback,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002118 &headers, fin, false, // not unidirectional
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002119 stream_id, 0));
2120 }
2121
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002122 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2123 if (it == active_streams_.end()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002124 // NOTE: it may just be that the stream was cancelled.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002125 return;
2126 }
2127
Ben Murdocheb525c52013-07-10 11:40:50 +01002128 SpdyStream* stream = it->second.stream;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002129 CHECK_EQ(stream->stream_id(), stream_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002130
Ben Murdocheb525c52013-07-10 11:40:50 +01002131 if (!it->second.waiting_for_syn_reply) {
2132 const std::string& error =
2133 "Received duplicate SYN_REPLY for stream.";
2134 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
2135 ResetStreamIterator(it, RST_STREAM_STREAM_IN_USE, error);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002136 return;
2137 }
Ben Murdocheb525c52013-07-10 11:40:50 +01002138 it->second.waiting_for_syn_reply = false;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002139
Ben Murdocheb525c52013-07-10 11:40:50 +01002140 ignore_result(OnInitialResponseHeadersReceived(
2141 headers, response_time, recv_first_byte_time, stream));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002142}
2143
2144void SpdySession::OnHeaders(SpdyStreamId stream_id,
2145 bool fin,
2146 const SpdyHeaderBlock& headers) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002147 CHECK(in_io_loop_);
2148
2149 if (availability_state_ == STATE_CLOSED)
2150 return;
2151
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002152 if (net_log().IsLoggingAllEvents()) {
2153 net_log().AddEvent(
2154 NetLog::TYPE_SPDY_SESSION_RECV_HEADERS,
2155 base::Bind(&NetLogSpdySynCallback,
2156 &headers, fin, /*unidirectional=*/false,
2157 stream_id, 0));
2158 }
2159
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002160 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2161 if (it == active_streams_.end()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002162 // NOTE: it may just be that the stream was cancelled.
2163 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id;
2164 return;
2165 }
2166
Ben Murdocheb525c52013-07-10 11:40:50 +01002167 SpdyStream* stream = it->second.stream;
2168 CHECK_EQ(stream->stream_id(), stream_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002169
Ben Murdocheb525c52013-07-10 11:40:50 +01002170 int rv = stream->OnAdditionalResponseHeadersReceived(headers);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002171 if (rv < 0) {
2172 DCHECK_NE(rv, ERR_IO_PENDING);
Ben Murdocheb525c52013-07-10 11:40:50 +01002173 DCHECK(active_streams_.find(stream_id) == active_streams_.end());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002174 }
2175}
2176
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002177void SpdySession::OnRstStream(SpdyStreamId stream_id,
2178 SpdyRstStreamStatus status) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002179 CHECK(in_io_loop_);
2180
2181 if (availability_state_ == STATE_CLOSED)
2182 return;
2183
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002184 std::string description;
2185 net_log().AddEvent(
2186 NetLog::TYPE_SPDY_SESSION_RST_STREAM,
2187 base::Bind(&NetLogSpdyRstCallback,
2188 stream_id, status, &description));
2189
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002190 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
2191 if (it == active_streams_.end()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002192 // NOTE: it may just be that the stream was cancelled.
2193 LOG(WARNING) << "Received RST for invalid stream" << stream_id;
2194 return;
2195 }
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002196
Ben Murdocheb525c52013-07-10 11:40:50 +01002197 CHECK_EQ(it->second.stream->stream_id(), stream_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002198
2199 if (status == 0) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002200 it->second.stream->OnDataReceived(scoped_ptr<SpdyBuffer>());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002201 } else if (status == RST_STREAM_REFUSED_STREAM) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002202 CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002203 } else {
2204 RecordProtocolErrorHistogram(
2205 PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM);
Ben Murdocheb525c52013-07-10 11:40:50 +01002206 it->second.stream->LogStreamError(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002207 ERR_SPDY_PROTOCOL_ERROR,
2208 base::StringPrintf("SPDY stream closed with status: %d", status));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002209 // TODO(mbelshe): Map from Spdy-protocol errors to something sensical.
2210 // For now, it doesn't matter much - it is a protocol error.
Ben Murdocheb525c52013-07-10 11:40:50 +01002211 CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002212 }
2213}
2214
2215void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
2216 SpdyGoAwayStatus status) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002217 CHECK(in_io_loop_);
2218
2219 if (availability_state_ == STATE_CLOSED)
2220 return;
2221
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002222 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY,
2223 base::Bind(&NetLogSpdyGoAwayCallback,
2224 last_accepted_stream_id,
2225 active_streams_.size(),
2226 unclaimed_pushed_streams_.size(),
2227 status));
Ben Murdochca12bfa2013-07-23 11:17:05 +01002228 if (availability_state_ < STATE_GOING_AWAY) {
2229 availability_state_ = STATE_GOING_AWAY;
2230 // |pool_| will be NULL when |InitializeWithSocket()| is in the
2231 // call stack.
2232 if (pool_)
2233 pool_->MakeSessionUnavailable(GetWeakPtr());
2234 }
2235 StartGoingAway(last_accepted_stream_id, ERR_ABORTED);
2236 // This is to handle the case when we already don't have any active
2237 // streams (i.e., StartGoingAway() did nothing). Otherwise, we have
2238 // active streams and so the last one being closed will finish the
2239 // going away process (see DeleteStream()).
2240 MaybeFinishGoingAway();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002241}
2242
2243void SpdySession::OnPing(uint32 unique_id) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002244 CHECK(in_io_loop_);
2245
2246 if (availability_state_ == STATE_CLOSED)
2247 return;
2248
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002249 net_log_.AddEvent(
2250 NetLog::TYPE_SPDY_SESSION_PING,
2251 base::Bind(&NetLogSpdyPingCallback, unique_id, "received"));
2252
2253 // Send response to a PING from server.
2254 if (unique_id % 2 == 0) {
2255 WritePingFrame(unique_id);
2256 return;
2257 }
2258
2259 --pings_in_flight_;
2260 if (pings_in_flight_ < 0) {
2261 RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002262 CloseSessionResult result =
2263 DoCloseSession(ERR_SPDY_PROTOCOL_ERROR, "pings_in_flight_ is < 0.");
2264 DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002265 pings_in_flight_ = 0;
2266 return;
2267 }
2268
2269 if (pings_in_flight_ > 0)
2270 return;
2271
2272 // We will record RTT in histogram when there are no more client sent
2273 // pings_in_flight_.
Ben Murdochca12bfa2013-07-23 11:17:05 +01002274 RecordPingRTTHistogram(time_func_() - last_ping_sent_time_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002275}
2276
2277void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002278 uint32 delta_window_size) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002279 CHECK(in_io_loop_);
2280
2281 if (availability_state_ == STATE_CLOSED)
2282 return;
2283
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002284 DCHECK_LE(delta_window_size, static_cast<uint32>(kint32max));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002285 net_log_.AddEvent(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002286 NetLog::TYPE_SPDY_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
2287 base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002288 stream_id, delta_window_size));
2289
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002290 if (stream_id == kSessionFlowControlStreamId) {
2291 // WINDOW_UPDATE for the session.
2292 if (flow_control_state_ < FLOW_CONTROL_STREAM_AND_SESSION) {
2293 LOG(WARNING) << "Received WINDOW_UPDATE for session when "
2294 << "session flow control is not turned on";
2295 // TODO(akalin): Record an error and close the session.
2296 return;
2297 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002298
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002299 if (delta_window_size < 1u) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002300 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002301 CloseSessionResult result = DoCloseSession(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002302 ERR_SPDY_PROTOCOL_ERROR,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002303 "Received WINDOW_UPDATE with an invalid delta_window_size " +
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002304 base::UintToString(delta_window_size));
Ben Murdochca12bfa2013-07-23 11:17:05 +01002305 DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002306 return;
2307 }
2308
2309 IncreaseSendWindowSize(static_cast<int32>(delta_window_size));
2310 } else {
2311 // WINDOW_UPDATE for a stream.
2312 if (flow_control_state_ < FLOW_CONTROL_STREAM) {
2313 // TODO(akalin): Record an error and close the session.
2314 LOG(WARNING) << "Received WINDOW_UPDATE for stream " << stream_id
2315 << " when flow control is not turned on";
2316 return;
2317 }
2318
Ben Murdocheb525c52013-07-10 11:40:50 +01002319 ActiveStreamMap::iterator it = active_streams_.find(stream_id);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002320
2321 if (it == active_streams_.end()) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002322 // NOTE: it may just be that the stream was cancelled.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002323 LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
2324 return;
2325 }
2326
Ben Murdocheb525c52013-07-10 11:40:50 +01002327 SpdyStream* stream = it->second.stream;
2328 CHECK_EQ(stream->stream_id(), stream_id);
2329
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002330 if (delta_window_size < 1u) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002331 ResetStreamIterator(it,
2332 RST_STREAM_FLOW_CONTROL_ERROR,
2333 base::StringPrintf(
2334 "Received WINDOW_UPDATE with an invalid "
2335 "delta_window_size %ud", delta_window_size));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002336 return;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002337 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002338
Ben Murdocheb525c52013-07-10 11:40:50 +01002339 CHECK_EQ(it->second.stream->stream_id(), stream_id);
2340 it->second.stream->IncreaseSendWindowSize(
2341 static_cast<int32>(delta_window_size));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002342 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002343}
2344
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01002345void SpdySession::OnPushPromise(SpdyStreamId stream_id,
2346 SpdyStreamId promised_stream_id) {
2347 // TODO(akalin): Handle PUSH_PROMISE frames.
2348}
2349
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002350void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id,
2351 uint32 delta_window_size) {
2352 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002353 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2354 CHECK(it != active_streams_.end());
Ben Murdocheb525c52013-07-10 11:40:50 +01002355 CHECK_EQ(it->second.stream->stream_id(), stream_id);
2356 SendWindowUpdateFrame(
2357 stream_id, delta_window_size, it->second.stream->priority());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002358}
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002359
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002360void SpdySession::SendInitialData() {
2361 DCHECK(enable_sending_initial_data_);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002362 DCHECK_NE(availability_state_, STATE_CLOSED);
2363
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002364 if (send_connection_header_prefix_) {
2365 DCHECK_EQ(protocol_, kProtoHTTP2Draft04);
2366 scoped_ptr<SpdyFrame> connection_header_prefix_frame(
2367 new SpdyFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
2368 kHttp2ConnectionHeaderPrefixSize,
2369 false /* take_ownership */));
2370 // Count the prefix as part of the subsequent SETTINGS frame.
2371 EnqueueSessionWrite(HIGHEST, SETTINGS,
2372 connection_header_prefix_frame.Pass());
2373 }
2374
Ben Murdocheb525c52013-07-10 11:40:50 +01002375 // First, notify the server about the settings they should use when
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002376 // communicating with us.
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002377 SettingsMap settings_map;
2378 // Create a new settings frame notifying the server of our
2379 // max concurrent streams and initial window size.
2380 settings_map[SETTINGS_MAX_CONCURRENT_STREAMS] =
2381 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
2382 if (flow_control_state_ >= FLOW_CONTROL_STREAM &&
2383 stream_initial_recv_window_size_ != kSpdyStreamInitialWindowSize) {
2384 settings_map[SETTINGS_INITIAL_WINDOW_SIZE] =
2385 SettingsFlagsAndValue(SETTINGS_FLAG_NONE,
2386 stream_initial_recv_window_size_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002387 }
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002388 SendSettings(settings_map);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002389
Ben Murdocheb525c52013-07-10 11:40:50 +01002390 // Next, notify the server about our initial recv window size.
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002391 if (flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002392 // Bump up the receive window size to the real initial value. This
2393 // has to go here since the WINDOW_UPDATE frame sent by
2394 // IncreaseRecvWindowSize() call uses |buffered_spdy_framer_|.
2395 DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_);
2396 // This condition implies that |kDefaultInitialRecvWindowSize| -
2397 // |session_recv_window_size_| doesn't overflow.
2398 DCHECK_GT(session_recv_window_size_, 0);
2399 IncreaseRecvWindowSize(
2400 kDefaultInitialRecvWindowSize - session_recv_window_size_);
2401 }
2402
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002403 // Finally, notify the server about the settings they have
2404 // previously told us to use when communicating with them (after
2405 // applying them).
2406 const SettingsMap& server_settings_map =
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002407 http_server_properties_->GetSpdySettings(host_port_pair());
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002408 if (server_settings_map.empty())
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002409 return;
2410
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002411 SettingsMap::const_iterator it =
2412 server_settings_map.find(SETTINGS_CURRENT_CWND);
2413 uint32 cwnd = (it != server_settings_map.end()) ? it->second.second : 0;
2414 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwndSent", cwnd, 1, 200, 100);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002415
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002416 for (SettingsMap::const_iterator it = server_settings_map.begin();
2417 it != server_settings_map.end(); ++it) {
2418 const SpdySettingsIds new_id = it->first;
2419 const uint32 new_val = it->second.second;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002420 HandleSetting(new_id, new_val);
2421 }
2422
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01002423 SendSettings(server_settings_map);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002424}
2425
2426
2427void SpdySession::SendSettings(const SettingsMap& settings) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002428 DCHECK_NE(availability_state_, STATE_CLOSED);
2429
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002430 net_log_.AddEvent(
2431 NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002432 base::Bind(&NetLogSpdySendSettingsCallback, &settings));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002433
2434 // Create the SETTINGS frame and send it.
2435 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002436 scoped_ptr<SpdyFrame> settings_frame(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002437 buffered_spdy_framer_->CreateSettings(settings));
2438 sent_settings_ = true;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002439 EnqueueSessionWrite(HIGHEST, SETTINGS, settings_frame.Pass());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002440}
2441
2442void SpdySession::HandleSetting(uint32 id, uint32 value) {
2443 switch (id) {
2444 case SETTINGS_MAX_CONCURRENT_STREAMS:
2445 max_concurrent_streams_ = std::min(static_cast<size_t>(value),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002446 kMaxConcurrentStreamLimit);
2447 ProcessPendingStreamRequests();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002448 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002449 case SETTINGS_INITIAL_WINDOW_SIZE: {
2450 if (flow_control_state_ < FLOW_CONTROL_STREAM) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002451 net_log().AddEvent(
2452 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_NO_FLOW_CONTROL);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002453 return;
2454 }
2455
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002456 if (value > static_cast<uint32>(kint32max)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002457 net_log().AddEvent(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002458 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002459 NetLog::IntegerCallback("initial_window_size", value));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002460 return;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002461 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002462
2463 // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002464 int32 delta_window_size =
2465 static_cast<int32>(value) - stream_initial_send_window_size_;
2466 stream_initial_send_window_size_ = static_cast<int32>(value);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002467 UpdateStreamsSendWindowSize(delta_window_size);
2468 net_log().AddEvent(
2469 NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
2470 NetLog::IntegerCallback("delta_window_size", delta_window_size));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002471 break;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002472 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002473 }
2474}
2475
2476void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002477 DCHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002478 for (ActiveStreamMap::iterator it = active_streams_.begin();
2479 it != active_streams_.end(); ++it) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002480 it->second.stream->AdjustSendWindowSize(delta_window_size);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002481 }
2482
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002483 for (CreatedStreamSet::const_iterator it = created_streams_.begin();
2484 it != created_streams_.end(); it++) {
2485 (*it)->AdjustSendWindowSize(delta_window_size);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002486 }
2487}
2488
2489void SpdySession::SendPrefacePingIfNoneInFlight() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002490 if (pings_in_flight_ || !enable_ping_based_connection_checking_)
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002491 return;
2492
Ben Murdochca12bfa2013-07-23 11:17:05 +01002493 base::TimeTicks now = time_func_();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002494 // If there is no activity in the session, then send a preface-PING.
2495 if ((now - last_activity_time_) > connection_at_risk_of_loss_time_)
2496 SendPrefacePing();
2497}
2498
2499void SpdySession::SendPrefacePing() {
2500 WritePingFrame(next_ping_id_);
2501}
2502
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002503void SpdySession::SendWindowUpdateFrame(SpdyStreamId stream_id,
2504 uint32 delta_window_size,
2505 RequestPriority priority) {
2506 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002507 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2508 if (it != active_streams_.end()) {
Ben Murdocheb525c52013-07-10 11:40:50 +01002509 CHECK_EQ(it->second.stream->stream_id(), stream_id);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002510 } else {
2511 CHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2512 CHECK_EQ(stream_id, kSessionFlowControlStreamId);
2513 }
2514
2515 net_log_.AddEvent(
2516 NetLog::TYPE_SPDY_SESSION_SENT_WINDOW_UPDATE_FRAME,
2517 base::Bind(&NetLogSpdyWindowUpdateFrameCallback,
2518 stream_id, delta_window_size));
2519
2520 DCHECK(buffered_spdy_framer_.get());
2521 scoped_ptr<SpdyFrame> window_update_frame(
2522 buffered_spdy_framer_->CreateWindowUpdate(stream_id, delta_window_size));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002523 EnqueueSessionWrite(priority, WINDOW_UPDATE, window_update_frame.Pass());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002524}
2525
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002526void SpdySession::WritePingFrame(uint32 unique_id) {
2527 DCHECK(buffered_spdy_framer_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002528 scoped_ptr<SpdyFrame> ping_frame(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002529 buffered_spdy_framer_->CreatePingFrame(unique_id));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002530 EnqueueSessionWrite(HIGHEST, PING, ping_frame.Pass());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002531
2532 if (net_log().IsLoggingAllEvents()) {
2533 net_log().AddEvent(
2534 NetLog::TYPE_SPDY_SESSION_PING,
2535 base::Bind(&NetLogSpdyPingCallback, unique_id, "sent"));
2536 }
2537 if (unique_id % 2 != 0) {
2538 next_ping_id_ += 2;
2539 ++pings_in_flight_;
2540 PlanToCheckPingStatus();
Ben Murdochca12bfa2013-07-23 11:17:05 +01002541 last_ping_sent_time_ = time_func_();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002542 }
2543}
2544
2545void SpdySession::PlanToCheckPingStatus() {
2546 if (check_ping_status_pending_)
2547 return;
2548
2549 check_ping_status_pending_ = true;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002550 base::MessageLoop::current()->PostDelayedTask(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002551 FROM_HERE,
2552 base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
Ben Murdochca12bfa2013-07-23 11:17:05 +01002553 time_func_()), hung_interval_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002554}
2555
2556void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002557 CHECK(!in_io_loop_);
2558 DCHECK_NE(availability_state_, STATE_CLOSED);
2559
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002560 // Check if we got a response back for all PINGs we had sent.
2561 if (pings_in_flight_ == 0) {
2562 check_ping_status_pending_ = false;
2563 return;
2564 }
2565
2566 DCHECK(check_ping_status_pending_);
2567
Ben Murdochca12bfa2013-07-23 11:17:05 +01002568 base::TimeTicks now = time_func_();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002569 base::TimeDelta delay = hung_interval_ - (now - last_activity_time_);
2570
2571 if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002572 // Track all failed PING messages in a separate bucket.
2573 const base::TimeDelta kFailedPing =
2574 base::TimeDelta::FromInternalValue(INT_MAX);
2575 RecordPingRTTHistogram(kFailedPing);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002576 CloseSessionResult result =
2577 DoCloseSession(ERR_SPDY_PING_FAILED, "Failed ping.");
2578 DCHECK_EQ(result, SESSION_CLOSED_AND_REMOVED);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002579 return;
2580 }
2581
2582 // Check the status of connection after a delay.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002583 base::MessageLoop::current()->PostDelayedTask(
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002584 FROM_HERE,
2585 base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
2586 now),
2587 delay);
2588}
2589
2590void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) {
2591 UMA_HISTOGRAM_TIMES("Net.SpdyPing.RTT", duration);
2592}
2593
2594void SpdySession::RecordProtocolErrorHistogram(
2595 SpdyProtocolErrorDetails details) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002596 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details,
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002597 NUM_SPDY_PROTOCOL_ERROR_DETAILS);
2598 if (EndsWith(host_port_pair().host(), "google.com", false)) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002599 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details,
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002600 NUM_SPDY_PROTOCOL_ERROR_DETAILS);
2601 }
2602}
2603
2604void SpdySession::RecordHistograms() {
2605 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
2606 streams_initiated_count_,
2607 0, 300, 50);
2608 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
2609 streams_pushed_count_,
2610 0, 300, 50);
2611 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
2612 streams_pushed_and_claimed_count_,
2613 0, 300, 50);
2614 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
2615 streams_abandoned_count_,
2616 0, 300, 50);
2617 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent",
2618 sent_settings_ ? 1 : 0, 2);
2619 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
2620 received_settings_ ? 1 : 0, 2);
2621 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamStallsPerSession",
2622 stalled_streams_,
2623 0, 300, 50);
2624 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionsWithStalls",
2625 stalled_streams_ > 0 ? 1 : 0, 2);
2626
2627 if (received_settings_) {
2628 // Enumerate the saved settings, and set histograms for it.
2629 const SettingsMap& settings_map =
2630 http_server_properties_->GetSpdySettings(host_port_pair());
2631
2632 SettingsMap::const_iterator it;
2633 for (it = settings_map.begin(); it != settings_map.end(); ++it) {
2634 const SpdySettingsIds id = it->first;
2635 const uint32 val = it->second.second;
2636 switch (id) {
2637 case SETTINGS_CURRENT_CWND:
2638 // Record several different histograms to see if cwnd converges
2639 // for larger volumes of data being sent.
2640 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd",
2641 val, 1, 200, 100);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002642 if (total_bytes_received_ > 10 * 1024) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002643 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K",
2644 val, 1, 200, 100);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002645 if (total_bytes_received_ > 25 * 1024) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002646 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K",
2647 val, 1, 200, 100);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002648 if (total_bytes_received_ > 50 * 1024) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002649 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K",
2650 val, 1, 200, 100);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002651 if (total_bytes_received_ > 100 * 1024) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002652 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K",
2653 val, 1, 200, 100);
2654 }
2655 }
2656 }
2657 }
2658 break;
2659 case SETTINGS_ROUND_TRIP_TIME:
2660 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT",
2661 val, 1, 1200, 100);
2662 break;
2663 case SETTINGS_DOWNLOAD_RETRANS_RATE:
2664 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate",
2665 val, 1, 100, 50);
2666 break;
2667 default:
2668 break;
2669 }
2670 }
2671 }
2672}
2673
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002674void SpdySession::CompleteStreamRequest(SpdyStreamRequest* pending_request) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01002675 CHECK(pending_request);
2676
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002677 PendingStreamRequestCompletionSet::iterator it =
2678 pending_stream_request_completions_.find(pending_request);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002679
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002680 // Abort if the request has already been cancelled.
2681 if (it == pending_stream_request_completions_.end())
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002682 return;
2683
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002684 base::WeakPtr<SpdyStream> stream;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002685 int rv = CreateStream(*pending_request, &stream);
2686 pending_stream_request_completions_.erase(it);
2687
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002688 if (rv == OK) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002689 DCHECK(stream.get());
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002690 pending_request->OnRequestCompleteSuccess(&stream);
2691 } else {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002692 DCHECK(!stream.get());
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002693 pending_request->OnRequestCompleteFailure(rv);
2694 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002695}
2696
2697SSLClientSocket* SpdySession::GetSSLClientSocket() const {
2698 if (!is_secure_)
2699 return NULL;
2700 SSLClientSocket* ssl_socket =
2701 reinterpret_cast<SSLClientSocket*>(connection_->socket());
2702 DCHECK(ssl_socket);
2703 return ssl_socket;
2704}
2705
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002706void SpdySession::OnWriteBufferConsumed(
2707 size_t frame_payload_size,
2708 size_t consume_size,
2709 SpdyBuffer::ConsumeSource consume_source) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002710 // We can be called with |in_io_loop_| set if a write SpdyBuffer is
2711 // deleted (e.g., a stream is closed due to incoming data).
2712
2713 if (availability_state_ == STATE_CLOSED)
2714 return;
2715
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002716 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002717
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002718 if (consume_source == SpdyBuffer::DISCARD) {
2719 // If we're discarding a frame or part of it, increase the send
2720 // window by the number of discarded bytes. (Although if we're
2721 // discarding part of a frame, it's probably because of a write
2722 // error and we'll be tearing down the session soon.)
2723 size_t remaining_payload_bytes = std::min(consume_size, frame_payload_size);
2724 DCHECK_GT(remaining_payload_bytes, 0u);
2725 IncreaseSendWindowSize(static_cast<int32>(remaining_payload_bytes));
2726 }
2727 // For consumed bytes, the send window is increased when we receive
2728 // a WINDOW_UPDATE frame.
2729}
2730
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002731void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002732 // We can be called with |in_io_loop_| set if a SpdyBuffer is
2733 // deleted (e.g., a stream is closed due to incoming data).
2734
2735 DCHECK_NE(availability_state_, STATE_CLOSED);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002736 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002737 DCHECK_GE(delta_window_size, 1);
2738
2739 // Check for overflow.
2740 int32 max_delta_window_size = kint32max - session_send_window_size_;
2741 if (delta_window_size > max_delta_window_size) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002742 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002743 CloseSessionResult result = DoCloseSession(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002744 ERR_SPDY_PROTOCOL_ERROR,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002745 "Received WINDOW_UPDATE [delta: " +
Ben Murdochca12bfa2013-07-23 11:17:05 +01002746 base::IntToString(delta_window_size) +
2747 "] for session overflows session_send_window_size_ [current: " +
2748 base::IntToString(session_send_window_size_) + "]");
2749 DCHECK_NE(result, SESSION_ALREADY_CLOSED);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002750 return;
2751 }
2752
2753 session_send_window_size_ += delta_window_size;
2754
2755 net_log_.AddEvent(
2756 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
2757 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2758 delta_window_size, session_send_window_size_));
2759
2760 DCHECK(!IsSendStalled());
2761 ResumeSendStalledStreams();
2762}
2763
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002764void SpdySession::DecreaseSendWindowSize(int32 delta_window_size) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002765 DCHECK_NE(availability_state_, STATE_CLOSED);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002766 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2767
2768 // We only call this method when sending a frame. Therefore,
2769 // |delta_window_size| should be within the valid frame size range.
2770 DCHECK_GE(delta_window_size, 1);
2771 DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
2772
2773 // |send_window_size_| should have been at least |delta_window_size| for
2774 // this call to happen.
2775 DCHECK_GE(session_send_window_size_, delta_window_size);
2776
2777 session_send_window_size_ -= delta_window_size;
2778
2779 net_log_.AddEvent(
2780 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
2781 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2782 -delta_window_size, session_send_window_size_));
2783}
2784
2785void SpdySession::OnReadBufferConsumed(
2786 size_t consume_size,
2787 SpdyBuffer::ConsumeSource consume_source) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002788 // We can be called with |in_io_loop_| set if a read SpdyBuffer is
2789 // deleted (e.g., discarded by a SpdyReadQueue).
2790
2791 if (availability_state_ == STATE_CLOSED)
2792 return;
2793
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002794 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2795 DCHECK_GE(consume_size, 1u);
2796 DCHECK_LE(consume_size, static_cast<size_t>(kint32max));
Ben Murdochca12bfa2013-07-23 11:17:05 +01002797
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002798 IncreaseRecvWindowSize(static_cast<int32>(consume_size));
2799}
2800
2801void SpdySession::IncreaseRecvWindowSize(int32 delta_window_size) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002802 DCHECK_NE(availability_state_, STATE_CLOSED);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002803 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2804 DCHECK_GE(session_unacked_recv_window_bytes_, 0);
2805 DCHECK_GE(session_recv_window_size_, session_unacked_recv_window_bytes_);
2806 DCHECK_GE(delta_window_size, 1);
2807 // Check for overflow.
2808 DCHECK_LE(delta_window_size, kint32max - session_recv_window_size_);
2809
2810 session_recv_window_size_ += delta_window_size;
2811 net_log_.AddEvent(
2812 NetLog::TYPE_SPDY_STREAM_UPDATE_RECV_WINDOW,
2813 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2814 delta_window_size, session_recv_window_size_));
2815
2816 session_unacked_recv_window_bytes_ += delta_window_size;
2817 if (session_unacked_recv_window_bytes_ > kSpdySessionInitialWindowSize / 2) {
2818 SendWindowUpdateFrame(kSessionFlowControlStreamId,
2819 session_unacked_recv_window_bytes_,
2820 HIGHEST);
2821 session_unacked_recv_window_bytes_ = 0;
2822 }
2823}
2824
2825void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) {
Ben Murdochca12bfa2013-07-23 11:17:05 +01002826 CHECK(in_io_loop_);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002827 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2828 DCHECK_GE(delta_window_size, 1);
2829
2830 // Since we never decrease the initial receive window size,
2831 // |delta_window_size| should never cause |recv_window_size_| to go
2832 // negative. If we do, the receive window isn't being respected.
2833 if (delta_window_size > session_recv_window_size_) {
2834 RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION);
Ben Murdochca12bfa2013-07-23 11:17:05 +01002835 CloseSessionResult result = DoCloseSession(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002836 ERR_SPDY_PROTOCOL_ERROR,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002837 "delta_window_size is " + base::IntToString(delta_window_size) +
2838 " in DecreaseRecvWindowSize, which is larger than the receive " +
2839 "window size of " + base::IntToString(session_recv_window_size_));
Ben Murdochca12bfa2013-07-23 11:17:05 +01002840 DCHECK_EQ(result, SESSION_CLOSED_BUT_NOT_REMOVED);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01002841 return;
2842 }
2843
2844 session_recv_window_size_ -= delta_window_size;
2845 net_log_.AddEvent(
2846 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW,
2847 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2848 -delta_window_size, session_recv_window_size_));
2849}
2850
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +01002851void SpdySession::QueueSendStalledStream(const SpdyStream& stream) {
2852 DCHECK(stream.send_stalled_by_flow_control());
2853 stream_send_unstall_queue_[stream.priority()].push_back(stream.stream_id());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002854}
2855
2856namespace {
2857
2858// Helper function to return the total size of an array of objects
2859// with .size() member functions.
2860template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
2861 size_t total_size = 0;
2862 for (size_t i = 0; i < N; ++i) {
2863 total_size += arr[i].size();
2864 }
2865 return total_size;
2866}
2867
2868} // namespace
2869
2870void SpdySession::ResumeSendStalledStreams() {
2871 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2872
2873 // We don't have to worry about new streams being queued, since
2874 // doing so would cause IsSendStalled() to return true. But we do
2875 // have to worry about streams being closed, as well as ourselves
2876 // being closed.
2877
Ben Murdochca12bfa2013-07-23 11:17:05 +01002878 while (availability_state_ != STATE_CLOSED && !IsSendStalled()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002879 size_t old_size = 0;
2880 if (DCHECK_IS_ON())
2881 old_size = GetTotalSize(stream_send_unstall_queue_);
2882
2883 SpdyStreamId stream_id = PopStreamToPossiblyResume();
2884 if (stream_id == 0)
2885 break;
2886 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2887 // The stream may actually still be send-stalled after this (due
2888 // to its own send window) but that's okay -- it'll then be
2889 // resumed once its send window increases.
2890 if (it != active_streams_.end())
Ben Murdocheb525c52013-07-10 11:40:50 +01002891 it->second.stream->PossiblyResumeIfSendStalled();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002892
2893 // The size should decrease unless we got send-stalled again.
2894 if (!IsSendStalled())
2895 DCHECK_LT(GetTotalSize(stream_send_unstall_queue_), old_size);
2896 }
2897}
2898
2899SpdyStreamId SpdySession::PopStreamToPossiblyResume() {
2900 for (int i = NUM_PRIORITIES - 1; i >= 0; --i) {
2901 std::deque<SpdyStreamId>* queue = &stream_send_unstall_queue_[i];
2902 if (!queue->empty()) {
2903 SpdyStreamId stream_id = queue->front();
2904 queue->pop_front();
2905 return stream_id;
2906 }
2907 }
2908 return 0;
2909}
2910
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002911} // namespace net