Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(813)

Side by Side Diff: net/spdy/spdy_session.cc

Issue 14348012: [SPDY] Close SPDY sessions on session flow control errors (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_stream.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/spdy_session.h" 5 #include "net/spdy/spdy_session.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/message_loop.h" 14 #include "base/message_loop.h"
15 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
17 #include "base/metrics/sparse_histogram.h" 17 #include "base/metrics/sparse_histogram.h"
18 #include "base/metrics/stats_counters.h" 18 #include "base/metrics/stats_counters.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/string_number_conversions.h"
21 #include "base/string_util.h" 20 #include "base/string_util.h"
22 #include "base/stringprintf.h" 21 #include "base/stringprintf.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/time.h" 23 #include "base/time.h"
24 #include "base/utf_string_conversions.h" 24 #include "base/utf_string_conversions.h"
25 #include "base/values.h" 25 #include "base/values.h"
26 #include "crypto/ec_private_key.h" 26 #include "crypto/ec_private_key.h"
27 #include "crypto/ec_signature_creator.h" 27 #include "crypto/ec_signature_creator.h"
28 #include "net/base/connection_type_histograms.h" 28 #include "net/base/connection_type_histograms.h"
29 #include "net/base/net_log.h" 29 #include "net/base/net_log.h"
30 #include "net/base/net_util.h" 30 #include "net/base/net_util.h"
31 #include "net/cert/asn1_util.h" 31 #include "net/cert/asn1_util.h"
32 #include "net/http/http_network_session.h" 32 #include "net/http/http_network_session.h"
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 next_unclaimed_push_stream_sweep_time_ = time_func_() + 367 next_unclaimed_push_stream_sweep_time_ = time_func_() +
368 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); 368 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
369 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. 369 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
370 } 370 }
371 371
372 SpdySession::~SpdySession() { 372 SpdySession::~SpdySession() {
373 if (state_ != STATE_CLOSED) { 373 if (state_ != STATE_CLOSED) {
374 state_ = STATE_CLOSED; 374 state_ = STATE_CLOSED;
375 375
376 // Cleanup all the streams. 376 // Cleanup all the streams.
377 CloseAllStreams(net::ERR_ABORTED); 377 CloseAllStreams(ERR_ABORTED);
378 } 378 }
379 379
380 if (connection_->is_initialized()) { 380 if (connection_->is_initialized()) {
381 // With SPDY we can't recycle sockets. 381 // With SPDY we can't recycle sockets.
382 connection_->socket()->Disconnect(); 382 connection_->socket()->Disconnect();
383 } 383 }
384 384
385 // Streams should all be gone now. 385 // Streams should all be gone now.
386 DCHECK_EQ(0u, num_active_streams()); 386 DCHECK_EQ(0u, num_active_streams());
387 DCHECK_EQ(0u, num_unclaimed_pushed_streams()); 387 DCHECK_EQ(0u, num_unclaimed_pushed_streams());
388 388
389 for (int i = 0; i < NUM_PRIORITIES; ++i) { 389 for (int i = 0; i < NUM_PRIORITIES; ++i) {
390 DCHECK(pending_create_stream_queues_[i].empty()); 390 DCHECK(pending_create_stream_queues_[i].empty());
391 } 391 }
392 DCHECK(pending_stream_request_completions_.empty()); 392 DCHECK(pending_stream_request_completions_.empty());
393 393
394 RecordHistograms(); 394 RecordHistograms();
395 395
396 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION); 396 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION);
397 } 397 }
398 398
399 net::Error SpdySession::InitializeWithSocket( 399 Error SpdySession::InitializeWithSocket(
400 ClientSocketHandle* connection, 400 ClientSocketHandle* connection,
401 bool is_secure, 401 bool is_secure,
402 int certificate_error_code) { 402 int certificate_error_code) {
403 base::StatsCounter spdy_sessions("spdy.sessions"); 403 base::StatsCounter spdy_sessions("spdy.sessions");
404 spdy_sessions.Increment(); 404 spdy_sessions.Increment();
405 405
406 state_ = STATE_DO_READ; 406 state_ = STATE_DO_READ;
407 connection_.reset(connection); 407 connection_.reset(connection);
408 is_secure_ = is_secure; 408 is_secure_ = is_secure;
409 certificate_error_code_ = certificate_error_code; 409 certificate_error_code_ = certificate_error_code;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 DCHECK_GT(session_recv_window_size_, 0); 450 DCHECK_GT(session_recv_window_size_, 0);
451 IncreaseRecvWindowSize( 451 IncreaseRecvWindowSize(
452 kDefaultInitialRecvWindowSize - session_recv_window_size_); 452 kDefaultInitialRecvWindowSize - session_recv_window_size_);
453 } 453 }
454 454
455 // Write out any data that we might have to send, such as the settings frame. 455 // Write out any data that we might have to send, such as the settings frame.
456 WriteSocketLater(); 456 WriteSocketLater();
457 int error = DoLoop(OK); 457 int error = DoLoop(OK);
458 if (error == ERR_IO_PENDING) 458 if (error == ERR_IO_PENDING)
459 return OK; 459 return OK;
460 return static_cast<net::Error>(error); 460 return static_cast<Error>(error);
461 } 461 }
462 462
463 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { 463 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
464 if (!verify_domain_authentication_) 464 if (!verify_domain_authentication_)
465 return true; 465 return true;
466 466
467 if (!IsConnected()) 467 if (!IsConnected())
468 return false; 468 return false;
469 469
470 SSLInfo ssl_info; 470 SSLInfo ssl_info;
(...skipping 18 matching lines...) Expand all
489 489
490 *stream = NULL; 490 *stream = NULL;
491 491
492 // Don't allow access to secure push streams over an unauthenticated, but 492 // Don't allow access to secure push streams over an unauthenticated, but
493 // encrypted SSL socket. 493 // encrypted SSL socket.
494 if (is_secure_ && certificate_error_code_ != OK && 494 if (is_secure_ && certificate_error_code_ != OK &&
495 (url.SchemeIs("https") || url.SchemeIs("wss"))) { 495 (url.SchemeIs("https") || url.SchemeIs("wss"))) {
496 RecordProtocolErrorHistogram( 496 RecordProtocolErrorHistogram(
497 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); 497 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
498 CloseSessionOnError( 498 CloseSessionOnError(
499 static_cast<net::Error>(certificate_error_code_), 499 static_cast<Error>(certificate_error_code_),
500 true, 500 true,
501 "Tried to get SPDY stream for secure content over an unauthenticated " 501 "Tried to get SPDY stream for secure content over an unauthenticated "
502 "session."); 502 "session.");
503 return ERR_SPDY_PROTOCOL_ERROR; 503 return ERR_SPDY_PROTOCOL_ERROR;
504 } 504 }
505 505
506 *stream = GetActivePushStream(url.spec()); 506 *stream = GetActivePushStream(url.spec());
507 if (stream->get()) { 507 if (stream->get()) {
508 DCHECK(streams_pushed_and_claimed_count_ < streams_pushed_count_); 508 DCHECK(streams_pushed_and_claimed_count_ < streams_pushed_count_);
509 streams_pushed_and_claimed_count_++; 509 streams_pushed_and_claimed_count_++;
(...skipping 20 matching lines...) Expand all
530 DCHECK_GE(request.priority(), MINIMUM_PRIORITY); 530 DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
531 DCHECK_LT(request.priority(), NUM_PRIORITIES); 531 DCHECK_LT(request.priority(), NUM_PRIORITIES);
532 532
533 // Make sure that we don't try to send https/wss over an unauthenticated, but 533 // Make sure that we don't try to send https/wss over an unauthenticated, but
534 // encrypted SSL socket. 534 // encrypted SSL socket.
535 if (is_secure_ && certificate_error_code_ != OK && 535 if (is_secure_ && certificate_error_code_ != OK &&
536 (request.url().SchemeIs("https") || request.url().SchemeIs("wss"))) { 536 (request.url().SchemeIs("https") || request.url().SchemeIs("wss"))) {
537 RecordProtocolErrorHistogram( 537 RecordProtocolErrorHistogram(
538 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); 538 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
539 CloseSessionOnError( 539 CloseSessionOnError(
540 static_cast<net::Error>(certificate_error_code_), 540 static_cast<Error>(certificate_error_code_),
541 true, 541 true,
542 "Tried to create SPDY stream for secure content over an " 542 "Tried to create SPDY stream for secure content over an "
543 "unauthenticated session."); 543 "unauthenticated session.");
544 return ERR_SPDY_PROTOCOL_ERROR; 544 return ERR_SPDY_PROTOCOL_ERROR;
545 } 545 }
546 546
547 const std::string& path = request.url().PathForRequest(); 547 const std::string& path = request.url().PathForRequest();
548 *stream = new SpdyStream(this, path, request.priority(), 548 *stream = new SpdyStream(this, path, request.priority(),
549 stream_initial_send_window_size_, 549 stream_initial_send_window_size_,
550 stream_initial_recv_window_size_, 550 stream_initial_recv_window_size_,
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 net_log().AddEvent( 733 net_log().AddEvent(
734 NetLog::TYPE_SPDY_SESSION_SEND_HEADERS, 734 NetLog::TYPE_SPDY_SESSION_SEND_HEADERS,
735 base::Bind(&NetLogSpdySynCallback, 735 base::Bind(&NetLogSpdySynCallback,
736 &headers, fin, /*unidirectional=*/false, 736 &headers, fin, /*unidirectional=*/false,
737 stream_id, 0)); 737 stream_id, 0));
738 } 738 }
739 return frame.Pass(); 739 return frame.Pass();
740 } 740 }
741 741
742 scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id, 742 scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id,
743 net::IOBuffer* data, 743 IOBuffer* data,
744 int len, 744 int len,
745 SpdyDataFlags flags) { 745 SpdyDataFlags flags) {
746 // Find our stream. 746 // Find our stream.
747 CHECK(IsStreamActive(stream_id)); 747 CHECK(IsStreamActive(stream_id));
748 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; 748 scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
749 CHECK_EQ(stream->stream_id(), stream_id); 749 CHECK_EQ(stream->stream_id(), stream_id);
750 750
751 if (len < 0) { 751 if (len < 0) {
752 NOTREACHED(); 752 NOTREACHED();
753 return scoped_ptr<SpdyBuffer>(); 753 return scoped_ptr<SpdyBuffer>();
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
846 const std::string& description) { 846 const std::string& description) {
847 net_log().AddEvent( 847 net_log().AddEvent(
848 NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM, 848 NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM,
849 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description)); 849 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
850 850
851 DCHECK(buffered_spdy_framer_.get()); 851 DCHECK(buffered_spdy_framer_.get());
852 scoped_ptr<SpdyFrame> rst_frame( 852 scoped_ptr<SpdyFrame> rst_frame(
853 buffered_spdy_framer_->CreateRstStream(stream_id, status)); 853 buffered_spdy_framer_->CreateRstStream(stream_id, status));
854 854
855 // Default to lowest priority unless we know otherwise. 855 // Default to lowest priority unless we know otherwise.
856 RequestPriority priority = net::IDLE; 856 RequestPriority priority = IDLE;
857 if (IsStreamActive(stream_id)) { 857 if (IsStreamActive(stream_id)) {
858 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; 858 scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
859 priority = stream->priority(); 859 priority = stream->priority();
860 } 860 }
861 EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass()); 861 EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass());
862 RecordProtocolErrorHistogram( 862 RecordProtocolErrorHistogram(
863 static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID)); 863 static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID));
864 DeleteStream(stream_id, ERR_SPDY_PROTOCOL_ERROR); 864 DeleteStream(stream_id, ERR_SPDY_PROTOCOL_ERROR);
865 } 865 }
866 866
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); 943 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr()));
944 } 944 }
945 945
946 int SpdySession::DoReadComplete(int result) { 946 int SpdySession::DoReadComplete(int result) {
947 // Parse a frame. For now this code requires that the frame fit into our 947 // Parse a frame. For now this code requires that the frame fit into our
948 // buffer (32KB). 948 // buffer (32KB).
949 // TODO(mbelshe): support arbitrarily large frames! 949 // TODO(mbelshe): support arbitrarily large frames!
950 950
951 if (result <= 0) { 951 if (result <= 0) {
952 // Session is tearing down. 952 // Session is tearing down.
953 net::Error error = static_cast<net::Error>(result); 953 Error error = static_cast<Error>(result);
954 if (result == 0) { 954 if (result == 0) {
955 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF", 955 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
956 total_bytes_received_, 1, 100000000, 50); 956 total_bytes_received_, 1, 100000000, 50);
957 error = ERR_CONNECTION_CLOSED; 957 error = ERR_CONNECTION_CLOSED;
958 } 958 }
959 CloseSessionOnError(error, true, "result is <= 0."); 959 CloseSessionOnError(error, true, "result is <= 0.");
960 return ERR_CONNECTION_CLOSED; 960 return ERR_CONNECTION_CLOSED;
961 } 961 }
962 962
963 total_bytes_received_ += result; 963 total_bytes_received_ += result;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 // It should not be possible to have written more bytes than our 1007 // It should not be possible to have written more bytes than our
1008 // in_flight_write_. 1008 // in_flight_write_.
1009 DCHECK_LE(static_cast<size_t>(result), 1009 DCHECK_LE(static_cast<size_t>(result),
1010 in_flight_write_->GetRemainingSize()); 1010 in_flight_write_->GetRemainingSize());
1011 1011
1012 if (result > 0) { 1012 if (result > 0) {
1013 in_flight_write_->Consume(static_cast<size_t>(result)); 1013 in_flight_write_->Consume(static_cast<size_t>(result));
1014 1014
1015 // We only notify the stream when we've fully written the pending frame. 1015 // We only notify the stream when we've fully written the pending frame.
1016 if (in_flight_write_->GetRemainingSize() == 0) { 1016 if (in_flight_write_->GetRemainingSize() == 0) {
1017 // It is possible that the stream was cancelled while we were 1017 // It is possible that the stream was cancelled while we were
1018 // writing to the socket. 1018 // writing to the socket.
1019 if (in_flight_write_stream_ && !in_flight_write_stream_->cancelled()) { 1019 if (in_flight_write_stream_ && !in_flight_write_stream_->cancelled()) {
1020 DCHECK_GT(in_flight_write_frame_size_, 0u); 1020 DCHECK_GT(in_flight_write_frame_size_, 0u);
1021 in_flight_write_stream_->OnFrameWriteComplete( 1021 in_flight_write_stream_->OnFrameWriteComplete(
1022 in_flight_write_frame_type_, 1022 in_flight_write_frame_type_,
1023 in_flight_write_frame_size_); 1023 in_flight_write_frame_size_);
1024 } 1024 }
1025 1025
1026 // Cleanup the write which just completed. 1026 // Cleanup the write which just completed.
1027 in_flight_write_.reset(); 1027 in_flight_write_.reset();
1028 in_flight_write_frame_type_ = DATA; 1028 in_flight_write_frame_type_ = DATA;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1104 } 1104 }
1105 in_flight_write_frame_type_ = frame_type; 1105 in_flight_write_frame_type_ = frame_type;
1106 in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize(); 1106 in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
1107 DCHECK_GE(in_flight_write_frame_size_, 1107 DCHECK_GE(in_flight_write_frame_size_,
1108 buffered_spdy_framer_->GetFrameMinimumSize()); 1108 buffered_spdy_framer_->GetFrameMinimumSize());
1109 in_flight_write_stream_ = stream; 1109 in_flight_write_stream_ = stream;
1110 } 1110 }
1111 1111
1112 write_pending_ = true; 1112 write_pending_ = true;
1113 // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems 1113 // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
1114 // with net::Socket implementations that don't store their 1114 // with Socket implementations that don't store their IOBuffer
1115 // IOBuffer argument in a scoped_refptr<IOBuffer> (see 1115 // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
1116 // crbug.com/232345).
1117 scoped_refptr<IOBuffer> write_io_buffer = 1116 scoped_refptr<IOBuffer> write_io_buffer =
1118 in_flight_write_->GetIOBufferForRemainingData(); 1117 in_flight_write_->GetIOBufferForRemainingData();
1119 // We keep |in_flight_write_| alive until OnWriteComplete(), so 1118 // We keep |in_flight_write_| alive until OnWriteComplete(), so
1120 // it's okay to use GetIOBufferForRemainingData() since the socket 1119 // it's okay to use GetIOBufferForRemainingData() since the socket
1121 // doesn't use the IOBuffer past OnWriteComplete(). 1120 // doesn't use the IOBuffer past OnWriteComplete().
1122 int rv = connection_->socket()->Write( 1121 int rv = connection_->socket()->Write(
1123 write_io_buffer, 1122 write_io_buffer,
1124 in_flight_write_->GetRemainingSize(), 1123 in_flight_write_->GetRemainingSize(),
1125 base::Bind(&SpdySession::OnWriteComplete, weak_factory_.GetWeakPtr())); 1124 base::Bind(&SpdySession::OnWriteComplete, weak_factory_.GetWeakPtr()));
1126 // Avoid persisting |write_io_buffer| past |in_flight_write_|'s 1125 // Avoid persisting |write_io_buffer| past |in_flight_write_|'s
1127 // lifetime (which will end if OnWriteComplete() is called below). 1126 // lifetime (which will end if OnWriteComplete() is called below).
1128 write_io_buffer = NULL; 1127 write_io_buffer = NULL;
1129 if (rv == net::ERR_IO_PENDING) 1128 if (rv == ERR_IO_PENDING)
1130 break; 1129 break;
1131 1130
1132 // We sent the frame successfully. 1131 // We sent the frame successfully.
1133 OnWriteComplete(rv); 1132 OnWriteComplete(rv);
1134 1133
1135 // TODO(mbelshe): Test this error case. Maybe we should mark the socket 1134 // TODO(mbelshe): Test this error case. Maybe we should mark the socket
1136 // as in an error state. 1135 // as in an error state.
1137 if (rv < 0) 1136 if (rv < 0)
1138 break; 1137 break;
1139 } 1138 }
1140 } 1139 }
1141 1140
1142 void SpdySession::CloseAllStreams(net::Error status) { 1141 void SpdySession::CloseAllStreams(Error status) {
1143 base::StatsCounter abandoned_streams("spdy.abandoned_streams"); 1142 base::StatsCounter abandoned_streams("spdy.abandoned_streams");
1144 base::StatsCounter abandoned_push_streams( 1143 base::StatsCounter abandoned_push_streams(
1145 "spdy.abandoned_push_streams"); 1144 "spdy.abandoned_push_streams");
1146 1145
1147 if (!active_streams_.empty()) 1146 if (!active_streams_.empty())
1148 abandoned_streams.Add(active_streams_.size()); 1147 abandoned_streams.Add(active_streams_.size());
1149 if (!unclaimed_pushed_streams_.empty()) { 1148 if (!unclaimed_pushed_streams_.empty()) {
1150 streams_abandoned_count_ += unclaimed_pushed_streams_.size(); 1149 streams_abandoned_count_ += unclaimed_pushed_streams_.size();
1151 abandoned_push_streams.Add(unclaimed_pushed_streams_.size()); 1150 abandoned_push_streams.Add(unclaimed_pushed_streams_.size());
1152 unclaimed_pushed_streams_.clear(); 1151 unclaimed_pushed_streams_.clear();
(...skipping 20 matching lines...) Expand all
1173 const scoped_refptr<SpdyStream> stream = *it; 1172 const scoped_refptr<SpdyStream> stream = *it;
1174 created_streams_.erase(it); 1173 created_streams_.erase(it);
1175 LogAbandonedStream(stream, status); 1174 LogAbandonedStream(stream, status);
1176 stream->OnClose(status); 1175 stream->OnClose(status);
1177 } 1176 }
1178 1177
1179 write_queue_.Clear(); 1178 write_queue_.Clear();
1180 } 1179 }
1181 1180
1182 void SpdySession::LogAbandonedStream(const scoped_refptr<SpdyStream>& stream, 1181 void SpdySession::LogAbandonedStream(const scoped_refptr<SpdyStream>& stream,
1183 net::Error status) { 1182 Error status) {
1184 DCHECK(stream); 1183 DCHECK(stream);
1185 std::string description = base::StringPrintf( 1184 std::string description = base::StringPrintf(
1186 "ABANDONED (stream_id=%d): ", stream->stream_id()) + stream->path(); 1185 "ABANDONED (stream_id=%d): ", stream->stream_id()) + stream->path();
1187 stream->LogStreamError(status, description); 1186 stream->LogStreamError(status, description);
1188 } 1187 }
1189 1188
1190 int SpdySession::GetNewStreamId() { 1189 int SpdySession::GetNewStreamId() {
1191 int id = stream_hi_water_mark_; 1190 int id = stream_hi_water_mark_;
1192 stream_hi_water_mark_ += 2; 1191 stream_hi_water_mark_ += 2;
1193 if (stream_hi_water_mark_ > 0x7fff) 1192 if (stream_hi_water_mark_ > 0x7fff)
1194 stream_hi_water_mark_ = 1; 1193 stream_hi_water_mark_ = 1;
1195 return id; 1194 return id;
1196 } 1195 }
1197 1196
1198 void SpdySession::CloseSessionOnError(net::Error err, 1197 void SpdySession::CloseSessionOnError(Error err,
1199 bool remove_from_pool, 1198 bool remove_from_pool,
1200 const std::string& description) { 1199 const std::string& description) {
1201 // Closing all streams can have a side-effect of dropping the last reference 1200 // Closing all streams can have a side-effect of dropping the last reference
1202 // to |this|. Hold a reference through this function. 1201 // to |this|. Hold a reference through this function.
1203 scoped_refptr<SpdySession> self(this); 1202 scoped_refptr<SpdySession> self(this);
1204 1203
1205 DCHECK_LT(err, OK); 1204 DCHECK_LT(err, OK);
1206 net_log_.AddEvent( 1205 net_log_.AddEvent(
1207 NetLog::TYPE_SPDY_SESSION_CLOSE, 1206 NetLog::TYPE_SPDY_SESSION_CLOSE,
1208 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); 1207 base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
1413 if (!is_secure_) 1412 if (!is_secure_)
1414 return NULL; 1413 return NULL;
1415 return GetSSLClientSocket()->GetServerBoundCertService(); 1414 return GetSSLClientSocket()->GetServerBoundCertService();
1416 } 1415 }
1417 1416
1418 void SpdySession::OnError(SpdyFramer::SpdyError error_code) { 1417 void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
1419 RecordProtocolErrorHistogram( 1418 RecordProtocolErrorHistogram(
1420 static_cast<SpdyProtocolErrorDetails>(error_code)); 1419 static_cast<SpdyProtocolErrorDetails>(error_code));
1421 std::string description = base::StringPrintf( 1420 std::string description = base::StringPrintf(
1422 "SPDY_ERROR error_code: %d.", error_code); 1421 "SPDY_ERROR error_code: %d.", error_code);
1423 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true, description); 1422 CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, true, description);
1424 } 1423 }
1425 1424
1426 void SpdySession::OnStreamError(SpdyStreamId stream_id, 1425 void SpdySession::OnStreamError(SpdyStreamId stream_id,
1427 const std::string& description) { 1426 const std::string& description) {
1428 if (IsStreamActive(stream_id)) 1427 if (IsStreamActive(stream_id))
1429 ResetStream(stream_id, RST_STREAM_PROTOCOL_ERROR, description); 1428 ResetStream(stream_id, RST_STREAM_PROTOCOL_ERROR, description);
1430 } 1429 }
1431 1430
1432 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, 1431 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
1433 const char* data, 1432 const char* data,
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
1746 1745
1747 void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, 1746 void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
1748 SpdyGoAwayStatus status) { 1747 SpdyGoAwayStatus status) {
1749 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY, 1748 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY,
1750 base::Bind(&NetLogSpdyGoAwayCallback, 1749 base::Bind(&NetLogSpdyGoAwayCallback,
1751 last_accepted_stream_id, 1750 last_accepted_stream_id,
1752 active_streams_.size(), 1751 active_streams_.size(),
1753 unclaimed_pushed_streams_.size(), 1752 unclaimed_pushed_streams_.size(),
1754 status)); 1753 status));
1755 RemoveFromPool(); 1754 RemoveFromPool();
1756 CloseAllStreams(net::ERR_ABORTED); 1755 CloseAllStreams(ERR_ABORTED);
1757 1756
1758 // TODO(willchan): Cancel any streams that are past the GoAway frame's 1757 // TODO(willchan): Cancel any streams that are past the GoAway frame's
1759 // |last_accepted_stream_id|. 1758 // |last_accepted_stream_id|.
1760 1759
1761 // Don't bother killing any streams that are still reading. They'll either 1760 // Don't bother killing any streams that are still reading. They'll either
1762 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is 1761 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is
1763 // closed. 1762 // closed.
1764 } 1763 }
1765 1764
1766 void SpdySession::OnPing(uint32 unique_id) { 1765 void SpdySession::OnPing(uint32 unique_id) {
1767 net_log_.AddEvent( 1766 net_log_.AddEvent(
1768 NetLog::TYPE_SPDY_SESSION_PING, 1767 NetLog::TYPE_SPDY_SESSION_PING,
1769 base::Bind(&NetLogSpdyPingCallback, unique_id, "received")); 1768 base::Bind(&NetLogSpdyPingCallback, unique_id, "received"));
1770 1769
1771 // Send response to a PING from server. 1770 // Send response to a PING from server.
1772 if (unique_id % 2 == 0) { 1771 if (unique_id % 2 == 0) {
1773 WritePingFrame(unique_id); 1772 WritePingFrame(unique_id);
1774 return; 1773 return;
1775 } 1774 }
1776 1775
1777 --pings_in_flight_; 1776 --pings_in_flight_;
1778 if (pings_in_flight_ < 0) { 1777 if (pings_in_flight_ < 0) {
1779 RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING); 1778 RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING);
1780 CloseSessionOnError( 1779 CloseSessionOnError(
1781 net::ERR_SPDY_PROTOCOL_ERROR, true, "pings_in_flight_ is < 0."); 1780 ERR_SPDY_PROTOCOL_ERROR, true, "pings_in_flight_ is < 0.");
1782 pings_in_flight_ = 0; 1781 pings_in_flight_ = 0;
1783 return; 1782 return;
1784 } 1783 }
1785 1784
1786 if (pings_in_flight_ > 0) 1785 if (pings_in_flight_ > 0)
1787 return; 1786 return;
1788 1787
1789 // We will record RTT in histogram when there are no more client sent 1788 // We will record RTT in histogram when there are no more client sent
1790 // pings_in_flight_. 1789 // pings_in_flight_.
1791 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_); 1790 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_);
(...skipping 21 matching lines...) Expand all
1813 } 1812 }
1814 1813
1815 if ((stream_id != kSessionFlowControlStreamId) && 1814 if ((stream_id != kSessionFlowControlStreamId) &&
1816 !IsStreamActive(stream_id)) { 1815 !IsStreamActive(stream_id)) {
1817 LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; 1816 LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
1818 return; 1817 return;
1819 } 1818 }
1820 1819
1821 if (delta_window_size < 1u) { 1820 if (delta_window_size < 1u) {
1822 if (stream_id == kSessionFlowControlStreamId) { 1821 if (stream_id == kSessionFlowControlStreamId) {
1823 LOG(WARNING) << "Received session WINDOW_UPDATE with an " 1822 // TODO(akalin): Also send a GOAWAY frame.
1824 << "invalid delta_window_size " << delta_window_size; 1823 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
1825 // TODO(akalin): Figure out whether we should instead send a 1824 CloseSessionOnError(
1826 // GOAWAY and close the connection here. 1825 ERR_SPDY_PROTOCOL_ERROR,
1826 true,
1827 "Received WINDOW_UPDATE with an invalid delta_window_size " +
1828 base::UintToString(delta_window_size));
1827 } else { 1829 } else {
1828 ResetStream(stream_id, RST_STREAM_FLOW_CONTROL_ERROR, 1830 ResetStream(stream_id, RST_STREAM_FLOW_CONTROL_ERROR,
1829 base::StringPrintf( 1831 base::StringPrintf(
1830 "Received WINDOW_UPDATE with an invalid " 1832 "Received WINDOW_UPDATE with an invalid "
1831 "delta_window_size %ud", delta_window_size)); 1833 "delta_window_size %ud", delta_window_size));
1832 } 1834 }
1833 return; 1835 return;
1834 } 1836 }
1835 1837
1836 if (stream_id == kSessionFlowControlStreamId) { 1838 if (stream_id == kSessionFlowControlStreamId) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1940 1942
1941 void SpdySession::HandleSetting(uint32 id, uint32 value) { 1943 void SpdySession::HandleSetting(uint32 id, uint32 value) {
1942 switch (id) { 1944 switch (id) {
1943 case SETTINGS_MAX_CONCURRENT_STREAMS: 1945 case SETTINGS_MAX_CONCURRENT_STREAMS:
1944 max_concurrent_streams_ = std::min(static_cast<size_t>(value), 1946 max_concurrent_streams_ = std::min(static_cast<size_t>(value),
1945 kMaxConcurrentStreamLimit); 1947 kMaxConcurrentStreamLimit);
1946 ProcessPendingStreamRequests(); 1948 ProcessPendingStreamRequests();
1947 break; 1949 break;
1948 case SETTINGS_INITIAL_WINDOW_SIZE: { 1950 case SETTINGS_INITIAL_WINDOW_SIZE: {
1949 if (flow_control_state_ < FLOW_CONTROL_STREAM) { 1951 if (flow_control_state_ < FLOW_CONTROL_STREAM) {
1950 LOG(WARNING) << "SETTINGS_INITIAL_WINDOW_SIZE setting received " 1952 net_log().AddEvent(
1951 << "when flow control is turned off"; 1953 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_NO_FLOW_CONTROL);
1952 // TODO(akalin): Figure out whether we should instead send a
1953 // GOAWAY and close the connection here.
1954 return; 1954 return;
1955 } 1955 }
1956 1956
1957 if (static_cast<int32>(value) < 0) { 1957 if (value < static_cast<uint32>(kint32max)) {
1958 net_log().AddEvent( 1958 net_log().AddEvent(
1959 NetLog::TYPE_SPDY_SESSION_NEGATIVE_INITIAL_WINDOW_SIZE, 1959 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
1960 NetLog::IntegerCallback("initial_window_size", value)); 1960 NetLog::IntegerCallback("initial_window_size", value));
1961 return; 1961 return;
1962 } 1962 }
1963 1963
1964 // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only. 1964 // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only.
1965 int32 delta_window_size = value - stream_initial_send_window_size_; 1965 int32 delta_window_size =
1966 stream_initial_send_window_size_ = value; 1966 static_cast<int32>(value) - stream_initial_send_window_size_;
1967 stream_initial_send_window_size_ = static_cast<int32>(value);
1967 UpdateStreamsSendWindowSize(delta_window_size); 1968 UpdateStreamsSendWindowSize(delta_window_size);
1968 net_log().AddEvent( 1969 net_log().AddEvent(
1969 NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE, 1970 NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
1970 NetLog::IntegerCallback("delta_window_size", delta_window_size)); 1971 NetLog::IntegerCallback("delta_window_size", delta_window_size));
1971 break; 1972 break;
1972 } 1973 }
1973 } 1974 }
1974 } 1975 }
1975 1976
1976 void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) { 1977 void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
2062 check_ping_status_pending_ = false; 2063 check_ping_status_pending_ = false;
2063 return; 2064 return;
2064 } 2065 }
2065 2066
2066 DCHECK(check_ping_status_pending_); 2067 DCHECK(check_ping_status_pending_);
2067 2068
2068 base::TimeTicks now = base::TimeTicks::Now(); 2069 base::TimeTicks now = base::TimeTicks::Now();
2069 base::TimeDelta delay = hung_interval_ - (now - last_activity_time_); 2070 base::TimeDelta delay = hung_interval_ - (now - last_activity_time_);
2070 2071
2071 if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) { 2072 if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) {
2072 CloseSessionOnError(net::ERR_SPDY_PING_FAILED, true, "Failed ping."); 2073 CloseSessionOnError(ERR_SPDY_PING_FAILED, true, "Failed ping.");
2073 // Track all failed PING messages in a separate bucket. 2074 // Track all failed PING messages in a separate bucket.
2074 const base::TimeDelta kFailedPing = 2075 const base::TimeDelta kFailedPing =
2075 base::TimeDelta::FromInternalValue(INT_MAX); 2076 base::TimeDelta::FromInternalValue(INT_MAX);
2076 RecordPingRTTHistogram(kFailedPing); 2077 RecordPingRTTHistogram(kFailedPing);
2077 return; 2078 return;
2078 } 2079 }
2079 2080
2080 // Check the status of connection after a delay. 2081 // Check the status of connection after a delay.
2081 MessageLoop::current()->PostDelayedTask( 2082 MessageLoop::current()->PostDelayedTask(
2082 FROM_HERE, 2083 FROM_HERE,
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
2211 // a WINDOW_UPDATE frame. 2212 // a WINDOW_UPDATE frame.
2212 } 2213 }
2213 2214
2214 void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) { 2215 void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) {
2215 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); 2216 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2216 DCHECK_GE(delta_window_size, 1); 2217 DCHECK_GE(delta_window_size, 1);
2217 2218
2218 // Check for overflow. 2219 // Check for overflow.
2219 int32 max_delta_window_size = kint32max - session_send_window_size_; 2220 int32 max_delta_window_size = kint32max - session_send_window_size_;
2220 if (delta_window_size > max_delta_window_size) { 2221 if (delta_window_size > max_delta_window_size) {
2221 LOG(WARNING) << "Received WINDOW_UPDATE [delta: " 2222 // TODO(akalin): Also send a GOAWAY frame.
2222 << delta_window_size 2223 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE);
2223 << "] for session overflows session_send_window_size_ " 2224 CloseSessionOnError(
2224 << "[current: " << session_send_window_size_ << "]"; 2225 ERR_SPDY_PROTOCOL_ERROR,
2225 // TODO(akalin): Figure out whether we should instead send a 2226 true,
2226 // GOAWAY and close the connection here. 2227 "Received WINDOW_UPDATE [delta: " +
2228 base::IntToString(delta_window_size) +
2229 "] for session overflows session_send_window_size_ [current: " +
2230 base::IntToString(session_send_window_size_) + "]");
2227 return; 2231 return;
2228 } 2232 }
2229 2233
2230 session_send_window_size_ += delta_window_size; 2234 session_send_window_size_ += delta_window_size;
2231 2235
2232 net_log_.AddEvent( 2236 net_log_.AddEvent(
2233 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW, 2237 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW,
2234 base::Bind(&NetLogSpdySessionWindowUpdateCallback, 2238 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2235 delta_window_size, session_send_window_size_)); 2239 delta_window_size, session_send_window_size_));
2236 2240
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
2287 session_unacked_recv_window_bytes_, 2291 session_unacked_recv_window_bytes_,
2288 HIGHEST); 2292 HIGHEST);
2289 session_unacked_recv_window_bytes_ = 0; 2293 session_unacked_recv_window_bytes_ = 0;
2290 } 2294 }
2291 } 2295 }
2292 2296
2293 void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) { 2297 void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) {
2294 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); 2298 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
2295 DCHECK_GE(delta_window_size, 1); 2299 DCHECK_GE(delta_window_size, 1);
2296 2300
2297 // |delta_window_size| should never cause 2301 // Since we never decrease the initial receive window size,
2298 // |session_recv_window_size_| to go negative. If we do, it's a 2302 // |delta_window_size| should never cause |recv_window_size_| to go
2299 // client-side bug. 2303 // negative. If we do, the receive window isn't being respected.
2300 if (delta_window_size > session_recv_window_size_) { 2304 if (delta_window_size > session_recv_window_size_) {
2301 NOTREACHED() << "Received session WINDOW_UPDATE with an " 2305 // TODO(akalin): Also send a GOAWAY frame.
Ryan Hamilton 2013/04/19 03:59:19 perhaps this todo should move to close session on
akalin 2013/04/19 05:55:14 Done. Also everywhere else.
2302 << "invalid delta_window_size " << delta_window_size; 2306 RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION);
2303 // TODO(akalin): Figure out whether we should instead send a 2307 CloseSessionOnError(
2304 // GOAWAY and close the connection here. 2308 ERR_SPDY_PROTOCOL_ERROR,
2309 true,
2310 "delta_window_size is " + base::IntToString(delta_window_size) +
2311 " in DecreaseRecvWindowSize, which is larger than the receive " +
2312 "window size of " + base::IntToString(session_recv_window_size_));
2305 return; 2313 return;
2306 } 2314 }
2307 2315
2308 session_recv_window_size_ -= delta_window_size; 2316 session_recv_window_size_ -= delta_window_size;
2309 net_log_.AddEvent( 2317 net_log_.AddEvent(
2310 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, 2318 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW,
2311 base::Bind(&NetLogSpdySessionWindowUpdateCallback, 2319 base::Bind(&NetLogSpdySessionWindowUpdateCallback,
2312 -delta_window_size, session_recv_window_size_)); 2320 -delta_window_size, session_recv_window_size_));
2313 } 2321 }
2314 2322
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2367 if (!queue->empty()) { 2375 if (!queue->empty()) {
2368 SpdyStreamId stream_id = queue->front(); 2376 SpdyStreamId stream_id = queue->front();
2369 queue->pop_front(); 2377 queue->pop_front();
2370 return stream_id; 2378 return stream_id;
2371 } 2379 }
2372 } 2380 }
2373 return 0; 2381 return 0;
2374 } 2382 }
2375 2383
2376 } // namespace net 2384 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_stream.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698