OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
878 const std::string& description) { | 878 const std::string& description) { |
879 net_log().AddEvent( | 879 net_log().AddEvent( |
880 NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM, | 880 NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM, |
881 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description)); | 881 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description)); |
882 | 882 |
883 DCHECK(buffered_spdy_framer_.get()); | 883 DCHECK(buffered_spdy_framer_.get()); |
884 scoped_ptr<SpdyFrame> rst_frame( | 884 scoped_ptr<SpdyFrame> rst_frame( |
885 buffered_spdy_framer_->CreateRstStream(stream_id, status)); | 885 buffered_spdy_framer_->CreateRstStream(stream_id, status)); |
886 | 886 |
887 // Default to lowest priority unless we know otherwise. | 887 // Default to lowest priority unless we know otherwise. |
888 RequestPriority priority = net::IDLE; | 888 RequestPriority priority = IDLE; |
889 if (IsStreamActive(stream_id)) { | 889 if (IsStreamActive(stream_id)) { |
890 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; | 890 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; |
891 priority = stream->priority(); | 891 priority = stream->priority(); |
892 } | 892 } |
893 EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass()); | 893 EnqueueSessionWrite(priority, RST_STREAM, rst_frame.Pass()); |
894 RecordProtocolErrorHistogram( | 894 RecordProtocolErrorHistogram( |
895 static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID)); | 895 static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID)); |
896 DeleteStream(stream_id, ERR_SPDY_PROTOCOL_ERROR); | 896 DeleteStream(stream_id, ERR_SPDY_PROTOCOL_ERROR); |
897 } | 897 } |
898 | 898 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
975 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); | 975 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); |
976 } | 976 } |
977 | 977 |
978 int SpdySession::DoReadComplete(int result) { | 978 int SpdySession::DoReadComplete(int result) { |
979 // Parse a frame. For now this code requires that the frame fit into our | 979 // Parse a frame. For now this code requires that the frame fit into our |
980 // buffer (32KB). | 980 // buffer (32KB). |
981 // TODO(mbelshe): support arbitrarily large frames! | 981 // TODO(mbelshe): support arbitrarily large frames! |
982 | 982 |
983 if (result <= 0) { | 983 if (result <= 0) { |
984 // Session is tearing down. | 984 // Session is tearing down. |
985 net::Error error = static_cast<net::Error>(result); | 985 Error error = static_cast<Error>(result); |
986 if (result == 0) { | 986 if (result == 0) { |
987 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF", | 987 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF", |
988 total_bytes_received_, 1, 100000000, 50); | 988 total_bytes_received_, 1, 100000000, 50); |
989 error = ERR_CONNECTION_CLOSED; | 989 error = ERR_CONNECTION_CLOSED; |
990 } | 990 } |
991 CloseSessionOnError(error, true, "result is <= 0."); | 991 CloseSessionOnError(error, true, "result is <= 0."); |
992 return ERR_CONNECTION_CLOSED; | 992 return ERR_CONNECTION_CLOSED; |
993 } | 993 } |
994 | 994 |
995 total_bytes_received_ += result; | 995 total_bytes_received_ += result; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1039 // It should not be possible to have written more bytes than our | 1039 // It should not be possible to have written more bytes than our |
1040 // in_flight_write_. | 1040 // in_flight_write_. |
1041 DCHECK_LE(static_cast<size_t>(result), | 1041 DCHECK_LE(static_cast<size_t>(result), |
1042 in_flight_write_->GetRemainingSize()); | 1042 in_flight_write_->GetRemainingSize()); |
1043 | 1043 |
1044 if (result > 0) { | 1044 if (result > 0) { |
1045 in_flight_write_->Consume(static_cast<size_t>(result)); | 1045 in_flight_write_->Consume(static_cast<size_t>(result)); |
1046 | 1046 |
1047 // We only notify the stream when we've fully written the pending frame. | 1047 // We only notify the stream when we've fully written the pending frame. |
1048 if (in_flight_write_->GetRemainingSize() == 0) { | 1048 if (in_flight_write_->GetRemainingSize() == 0) { |
1049 // It is possible that the stream was cancelled while we were | 1049 // It is possible that the stream was cancelled while we were |
1050 // writing to the socket. | 1050 // writing to the socket. |
1051 if (in_flight_write_stream_ && !in_flight_write_stream_->cancelled()) { | 1051 if (in_flight_write_stream_ && !in_flight_write_stream_->cancelled()) { |
1052 DCHECK_GT(in_flight_write_frame_size_, 0u); | 1052 DCHECK_GT(in_flight_write_frame_size_, 0u); |
1053 in_flight_write_stream_->OnFrameWriteComplete( | 1053 in_flight_write_stream_->OnFrameWriteComplete( |
1054 in_flight_write_frame_type_, | 1054 in_flight_write_frame_type_, |
1055 in_flight_write_frame_size_); | 1055 in_flight_write_frame_size_); |
1056 } | 1056 } |
1057 | 1057 |
1058 // Cleanup the write which just completed. | 1058 // Cleanup the write which just completed. |
1059 in_flight_write_.reset(); | 1059 in_flight_write_.reset(); |
1060 in_flight_write_frame_type_ = DATA; | 1060 in_flight_write_frame_type_ = DATA; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1136 } | 1136 } |
1137 in_flight_write_frame_type_ = frame_type; | 1137 in_flight_write_frame_type_ = frame_type; |
1138 in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize(); | 1138 in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize(); |
1139 DCHECK_GE(in_flight_write_frame_size_, | 1139 DCHECK_GE(in_flight_write_frame_size_, |
1140 buffered_spdy_framer_->GetFrameMinimumSize()); | 1140 buffered_spdy_framer_->GetFrameMinimumSize()); |
1141 in_flight_write_stream_ = stream; | 1141 in_flight_write_stream_ = stream; |
1142 } | 1142 } |
1143 | 1143 |
1144 write_pending_ = true; | 1144 write_pending_ = true; |
1145 // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems | 1145 // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems |
1146 // with net::Socket implementations that don't store their | 1146 // with Socket implementations that don't store their IOBuffer |
1147 // IOBuffer argument in a scoped_refptr<IOBuffer> (see | 1147 // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345). |
1148 // crbug.com/232345). | |
1149 scoped_refptr<IOBuffer> write_io_buffer = | 1148 scoped_refptr<IOBuffer> write_io_buffer = |
1150 in_flight_write_->GetIOBufferForRemainingData(); | 1149 in_flight_write_->GetIOBufferForRemainingData(); |
1151 // We keep |in_flight_write_| alive until OnWriteComplete(), so | 1150 // We keep |in_flight_write_| alive until OnWriteComplete(), so |
1152 // it's okay to use GetIOBufferForRemainingData() since the socket | 1151 // it's okay to use GetIOBufferForRemainingData() since the socket |
1153 // doesn't use the IOBuffer past OnWriteComplete(). | 1152 // doesn't use the IOBuffer past OnWriteComplete(). |
1154 int rv = connection_->socket()->Write( | 1153 int rv = connection_->socket()->Write( |
1155 write_io_buffer, | 1154 write_io_buffer, |
1156 in_flight_write_->GetRemainingSize(), | 1155 in_flight_write_->GetRemainingSize(), |
1157 base::Bind(&SpdySession::OnWriteComplete, weak_factory_.GetWeakPtr())); | 1156 base::Bind(&SpdySession::OnWriteComplete, weak_factory_.GetWeakPtr())); |
1158 // Avoid persisting |write_io_buffer| past |in_flight_write_|'s | 1157 // Avoid persisting |write_io_buffer| past |in_flight_write_|'s |
1159 // lifetime (which will end if OnWriteComplete() is called below). | 1158 // lifetime (which will end if OnWriteComplete() is called below). |
1160 write_io_buffer = NULL; | 1159 write_io_buffer = NULL; |
1161 if (rv == net::ERR_IO_PENDING) | 1160 if (rv == ERR_IO_PENDING) |
1162 break; | 1161 break; |
1163 | 1162 |
1164 // We sent the frame successfully. | 1163 // We sent the frame successfully. |
1165 OnWriteComplete(rv); | 1164 OnWriteComplete(rv); |
1166 | 1165 |
1167 // TODO(mbelshe): Test this error case. Maybe we should mark the socket | 1166 // TODO(mbelshe): Test this error case. Maybe we should mark the socket |
1168 // as in an error state. | 1167 // as in an error state. |
1169 if (rv < 0) | 1168 if (rv < 0) |
1170 break; | 1169 break; |
1171 } | 1170 } |
1172 } | 1171 } |
1173 | 1172 |
1174 void SpdySession::CloseAllStreamsAfter(SpdyStreamId last_good_stream_id, | 1173 void SpdySession::CloseAllStreamsAfter(SpdyStreamId last_good_stream_id, |
1175 net::Error status) { | 1174 Error status) { |
1176 for (int i = 0; i < NUM_PRIORITIES; ++i) { | 1175 for (int i = 0; i < NUM_PRIORITIES; ++i) { |
1177 PendingStreamRequestQueue queue; | 1176 PendingStreamRequestQueue queue; |
1178 queue.swap(pending_create_stream_queues_[i]); | 1177 queue.swap(pending_create_stream_queues_[i]); |
1179 for (PendingStreamRequestQueue::const_iterator it = queue.begin(); | 1178 for (PendingStreamRequestQueue::const_iterator it = queue.begin(); |
1180 it != queue.end(); ++it) { | 1179 it != queue.end(); ++it) { |
1181 (*it)->OnRequestComplete(NULL, ERR_ABORTED); | 1180 (*it)->OnRequestComplete(NULL, ERR_ABORTED); |
1182 } | 1181 } |
1183 } | 1182 } |
1184 | 1183 |
1185 ActiveStreamMap::iterator it = | 1184 ActiveStreamMap::iterator it = |
(...skipping 10 matching lines...) Expand all Loading... | |
1196 CreatedStreamSet::iterator it = created_streams_.begin(); | 1195 CreatedStreamSet::iterator it = created_streams_.begin(); |
1197 const scoped_refptr<SpdyStream> stream = *it; | 1196 const scoped_refptr<SpdyStream> stream = *it; |
1198 created_streams_.erase(it); | 1197 created_streams_.erase(it); |
1199 LogAbandonedStream(stream, status); | 1198 LogAbandonedStream(stream, status); |
1200 stream->OnClose(status); | 1199 stream->OnClose(status); |
1201 } | 1200 } |
1202 | 1201 |
1203 write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id); | 1202 write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id); |
1204 } | 1203 } |
1205 | 1204 |
1206 void SpdySession::CloseAllStreams(net::Error status) { | 1205 void SpdySession::CloseAllStreams(Error status) { |
1207 base::StatsCounter abandoned_streams("spdy.abandoned_streams"); | 1206 base::StatsCounter abandoned_streams("spdy.abandoned_streams"); |
1208 base::StatsCounter abandoned_push_streams( | 1207 base::StatsCounter abandoned_push_streams( |
1209 "spdy.abandoned_push_streams"); | 1208 "spdy.abandoned_push_streams"); |
1210 | 1209 |
1211 if (!unclaimed_pushed_streams_.empty()) { | 1210 if (!unclaimed_pushed_streams_.empty()) { |
1212 streams_abandoned_count_ += unclaimed_pushed_streams_.size(); | 1211 streams_abandoned_count_ += unclaimed_pushed_streams_.size(); |
1213 abandoned_push_streams.Add(unclaimed_pushed_streams_.size()); | 1212 abandoned_push_streams.Add(unclaimed_pushed_streams_.size()); |
1214 unclaimed_pushed_streams_.clear(); | 1213 unclaimed_pushed_streams_.clear(); |
1215 } | 1214 } |
1216 | 1215 |
1217 CloseAllStreamsAfter(0, status); | 1216 CloseAllStreamsAfter(0, status); |
1218 write_queue_.Clear(); | 1217 write_queue_.Clear(); |
1219 } | 1218 } |
1220 | 1219 |
1221 void SpdySession::LogAbandonedStream(const scoped_refptr<SpdyStream>& stream, | 1220 void SpdySession::LogAbandonedStream(const scoped_refptr<SpdyStream>& stream, |
1222 net::Error status) { | 1221 Error status) { |
1223 DCHECK(stream); | 1222 DCHECK(stream); |
1224 std::string description = base::StringPrintf( | 1223 std::string description = base::StringPrintf( |
1225 "ABANDONED (stream_id=%d): ", stream->stream_id()) + stream->path(); | 1224 "ABANDONED (stream_id=%d): ", stream->stream_id()) + stream->path(); |
1226 stream->LogStreamError(status, description); | 1225 stream->LogStreamError(status, description); |
1227 } | 1226 } |
1228 | 1227 |
1229 int SpdySession::GetNewStreamId() { | 1228 int SpdySession::GetNewStreamId() { |
1230 int id = stream_hi_water_mark_; | 1229 int id = stream_hi_water_mark_; |
1231 stream_hi_water_mark_ += 2; | 1230 stream_hi_water_mark_ += 2; |
1232 if (stream_hi_water_mark_ > 0x7fff) | 1231 if (stream_hi_water_mark_ > 0x7fff) |
1233 stream_hi_water_mark_ = 1; | 1232 stream_hi_water_mark_ = 1; |
1234 return id; | 1233 return id; |
1235 } | 1234 } |
1236 | 1235 |
1237 void SpdySession::CloseSessionOnError(net::Error err, | 1236 void SpdySession::CloseSessionOnError(Error err, |
1238 bool remove_from_pool, | 1237 bool remove_from_pool, |
1239 const std::string& description) { | 1238 const std::string& description) { |
1240 // Closing all streams can have a side-effect of dropping the last reference | 1239 // Closing all streams can have a side-effect of dropping the last reference |
1241 // to |this|. Hold a reference through this function. | 1240 // to |this|. Hold a reference through this function. |
1242 scoped_refptr<SpdySession> self(this); | 1241 scoped_refptr<SpdySession> self(this); |
1243 | 1242 |
1244 DCHECK_LT(err, OK); | 1243 DCHECK_LT(err, OK); |
1245 net_log_.AddEvent( | 1244 net_log_.AddEvent( |
1246 NetLog::TYPE_SPDY_SESSION_CLOSE, | 1245 NetLog::TYPE_SPDY_SESSION_CLOSE, |
1247 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); | 1246 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1452 if (!is_secure_) | 1451 if (!is_secure_) |
1453 return NULL; | 1452 return NULL; |
1454 return GetSSLClientSocket()->GetServerBoundCertService(); | 1453 return GetSSLClientSocket()->GetServerBoundCertService(); |
1455 } | 1454 } |
1456 | 1455 |
1457 void SpdySession::OnError(SpdyFramer::SpdyError error_code) { | 1456 void SpdySession::OnError(SpdyFramer::SpdyError error_code) { |
1458 RecordProtocolErrorHistogram( | 1457 RecordProtocolErrorHistogram( |
1459 static_cast<SpdyProtocolErrorDetails>(error_code)); | 1458 static_cast<SpdyProtocolErrorDetails>(error_code)); |
1460 std::string description = base::StringPrintf( | 1459 std::string description = base::StringPrintf( |
1461 "SPDY_ERROR error_code: %d.", error_code); | 1460 "SPDY_ERROR error_code: %d.", error_code); |
1462 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true, description); | 1461 CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, true, description); |
1463 } | 1462 } |
1464 | 1463 |
1465 void SpdySession::OnStreamError(SpdyStreamId stream_id, | 1464 void SpdySession::OnStreamError(SpdyStreamId stream_id, |
1466 const std::string& description) { | 1465 const std::string& description) { |
1467 if (IsStreamActive(stream_id)) | 1466 if (IsStreamActive(stream_id)) |
1468 ResetStream(stream_id, RST_STREAM_PROTOCOL_ERROR, description); | 1467 ResetStream(stream_id, RST_STREAM_PROTOCOL_ERROR, description); |
1469 } | 1468 } |
1470 | 1469 |
1471 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, | 1470 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, |
1472 const char* data, | 1471 const char* data, |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1785 | 1784 |
1786 void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, | 1785 void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, |
1787 SpdyGoAwayStatus status) { | 1786 SpdyGoAwayStatus status) { |
1788 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY, | 1787 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY, |
1789 base::Bind(&NetLogSpdyGoAwayCallback, | 1788 base::Bind(&NetLogSpdyGoAwayCallback, |
1790 last_accepted_stream_id, | 1789 last_accepted_stream_id, |
1791 active_streams_.size(), | 1790 active_streams_.size(), |
1792 unclaimed_pushed_streams_.size(), | 1791 unclaimed_pushed_streams_.size(), |
1793 status)); | 1792 status)); |
1794 RemoveFromPool(); | 1793 RemoveFromPool(); |
1795 CloseAllStreamsAfter(last_accepted_stream_id, net::ERR_ABORTED); | 1794 CloseAllStreamsAfter(last_accepted_stream_id, ERR_ABORTED); |
1796 } | 1795 } |
1797 | 1796 |
1798 void SpdySession::OnPing(uint32 unique_id) { | 1797 void SpdySession::OnPing(uint32 unique_id) { |
1799 net_log_.AddEvent( | 1798 net_log_.AddEvent( |
1800 NetLog::TYPE_SPDY_SESSION_PING, | 1799 NetLog::TYPE_SPDY_SESSION_PING, |
1801 base::Bind(&NetLogSpdyPingCallback, unique_id, "received")); | 1800 base::Bind(&NetLogSpdyPingCallback, unique_id, "received")); |
1802 | 1801 |
1803 // Send response to a PING from server. | 1802 // Send response to a PING from server. |
1804 if (unique_id % 2 == 0) { | 1803 if (unique_id % 2 == 0) { |
1805 WritePingFrame(unique_id); | 1804 WritePingFrame(unique_id); |
1806 return; | 1805 return; |
1807 } | 1806 } |
1808 | 1807 |
1809 --pings_in_flight_; | 1808 --pings_in_flight_; |
1810 if (pings_in_flight_ < 0) { | 1809 if (pings_in_flight_ < 0) { |
1811 RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING); | 1810 RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING); |
1812 CloseSessionOnError( | 1811 CloseSessionOnError( |
1813 net::ERR_SPDY_PROTOCOL_ERROR, true, "pings_in_flight_ is < 0."); | 1812 ERR_SPDY_PROTOCOL_ERROR, true, "pings_in_flight_ is < 0."); |
1814 pings_in_flight_ = 0; | 1813 pings_in_flight_ = 0; |
1815 return; | 1814 return; |
1816 } | 1815 } |
1817 | 1816 |
1818 if (pings_in_flight_ > 0) | 1817 if (pings_in_flight_ > 0) |
1819 return; | 1818 return; |
1820 | 1819 |
1821 // We will record RTT in histogram when there are no more client sent | 1820 // We will record RTT in histogram when there are no more client sent |
1822 // pings_in_flight_. | 1821 // pings_in_flight_. |
1823 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_); | 1822 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_); |
(...skipping 21 matching lines...) Expand all Loading... | |
1845 } | 1844 } |
1846 | 1845 |
1847 if ((stream_id != kSessionFlowControlStreamId) && | 1846 if ((stream_id != kSessionFlowControlStreamId) && |
1848 !IsStreamActive(stream_id)) { | 1847 !IsStreamActive(stream_id)) { |
1849 LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; | 1848 LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; |
1850 return; | 1849 return; |
1851 } | 1850 } |
1852 | 1851 |
1853 if (delta_window_size < 1u) { | 1852 if (delta_window_size < 1u) { |
1854 if (stream_id == kSessionFlowControlStreamId) { | 1853 if (stream_id == kSessionFlowControlStreamId) { |
1855 LOG(WARNING) << "Received session WINDOW_UPDATE with an " | 1854 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE); |
1856 << "invalid delta_window_size " << delta_window_size; | 1855 CloseSessionOnError( |
1857 // TODO(akalin): Figure out whether we should instead send a | 1856 ERR_SPDY_PROTOCOL_ERROR, |
1858 // GOAWAY and close the connection here. | 1857 true, |
1858 "Received WINDOW_UPDATE with an invalid delta_window_size " + | |
1859 base::UintToString(delta_window_size)); | |
1859 } else { | 1860 } else { |
1860 ResetStream(stream_id, RST_STREAM_FLOW_CONTROL_ERROR, | 1861 ResetStream(stream_id, RST_STREAM_FLOW_CONTROL_ERROR, |
1861 base::StringPrintf( | 1862 base::StringPrintf( |
1862 "Received WINDOW_UPDATE with an invalid " | 1863 "Received WINDOW_UPDATE with an invalid " |
1863 "delta_window_size %ud", delta_window_size)); | 1864 "delta_window_size %ud", delta_window_size)); |
1864 } | 1865 } |
1865 return; | 1866 return; |
1866 } | 1867 } |
1867 | 1868 |
1868 if (stream_id == kSessionFlowControlStreamId) { | 1869 if (stream_id == kSessionFlowControlStreamId) { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1972 | 1973 |
1973 void SpdySession::HandleSetting(uint32 id, uint32 value) { | 1974 void SpdySession::HandleSetting(uint32 id, uint32 value) { |
1974 switch (id) { | 1975 switch (id) { |
1975 case SETTINGS_MAX_CONCURRENT_STREAMS: | 1976 case SETTINGS_MAX_CONCURRENT_STREAMS: |
1976 max_concurrent_streams_ = std::min(static_cast<size_t>(value), | 1977 max_concurrent_streams_ = std::min(static_cast<size_t>(value), |
1977 kMaxConcurrentStreamLimit); | 1978 kMaxConcurrentStreamLimit); |
1978 ProcessPendingStreamRequests(); | 1979 ProcessPendingStreamRequests(); |
1979 break; | 1980 break; |
1980 case SETTINGS_INITIAL_WINDOW_SIZE: { | 1981 case SETTINGS_INITIAL_WINDOW_SIZE: { |
1981 if (flow_control_state_ < FLOW_CONTROL_STREAM) { | 1982 if (flow_control_state_ < FLOW_CONTROL_STREAM) { |
1982 LOG(WARNING) << "SETTINGS_INITIAL_WINDOW_SIZE setting received " | 1983 net_log().AddEvent( |
1983 << "when flow control is turned off"; | 1984 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_NO_FLOW_CONTROL); |
1984 // TODO(akalin): Figure out whether we should instead send a | |
1985 // GOAWAY and close the connection here. | |
1986 return; | 1985 return; |
1987 } | 1986 } |
1988 | 1987 |
1989 if (static_cast<int32>(value) < 0) { | 1988 if (value > static_cast<uint32>(kint32max)) { |
1990 net_log().AddEvent( | 1989 net_log().AddEvent( |
1991 NetLog::TYPE_SPDY_SESSION_NEGATIVE_INITIAL_WINDOW_SIZE, | 1990 NetLog::TYPE_SPDY_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE, |
1992 NetLog::IntegerCallback("initial_window_size", value)); | 1991 NetLog::IntegerCallback("initial_window_size", value)); |
1993 return; | 1992 return; |
1994 } | 1993 } |
1995 | 1994 |
1996 // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only. | 1995 // SETTINGS_INITIAL_WINDOW_SIZE updates initial_send_window_size_ only. |
1997 int32 delta_window_size = value - stream_initial_send_window_size_; | 1996 int32 delta_window_size = |
1998 stream_initial_send_window_size_ = value; | 1997 static_cast<int32>(value) - stream_initial_send_window_size_; |
1998 stream_initial_send_window_size_ = static_cast<int32>(value); | |
1999 UpdateStreamsSendWindowSize(delta_window_size); | 1999 UpdateStreamsSendWindowSize(delta_window_size); |
2000 net_log().AddEvent( | 2000 net_log().AddEvent( |
2001 NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE, | 2001 NetLog::TYPE_SPDY_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE, |
2002 NetLog::IntegerCallback("delta_window_size", delta_window_size)); | 2002 NetLog::IntegerCallback("delta_window_size", delta_window_size)); |
2003 break; | 2003 break; |
2004 } | 2004 } |
2005 } | 2005 } |
2006 } | 2006 } |
2007 | 2007 |
2008 void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) { | 2008 void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2094 check_ping_status_pending_ = false; | 2094 check_ping_status_pending_ = false; |
2095 return; | 2095 return; |
2096 } | 2096 } |
2097 | 2097 |
2098 DCHECK(check_ping_status_pending_); | 2098 DCHECK(check_ping_status_pending_); |
2099 | 2099 |
2100 base::TimeTicks now = base::TimeTicks::Now(); | 2100 base::TimeTicks now = base::TimeTicks::Now(); |
2101 base::TimeDelta delay = hung_interval_ - (now - last_activity_time_); | 2101 base::TimeDelta delay = hung_interval_ - (now - last_activity_time_); |
2102 | 2102 |
2103 if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) { | 2103 if (delay.InMilliseconds() < 0 || last_activity_time_ < last_check_time) { |
2104 CloseSessionOnError(net::ERR_SPDY_PING_FAILED, true, "Failed ping."); | 2104 CloseSessionOnError(ERR_SPDY_PING_FAILED, true, "Failed ping."); |
2105 // Track all failed PING messages in a separate bucket. | 2105 // Track all failed PING messages in a separate bucket. |
2106 const base::TimeDelta kFailedPing = | 2106 const base::TimeDelta kFailedPing = |
2107 base::TimeDelta::FromInternalValue(INT_MAX); | 2107 base::TimeDelta::FromInternalValue(INT_MAX); |
2108 RecordPingRTTHistogram(kFailedPing); | 2108 RecordPingRTTHistogram(kFailedPing); |
2109 return; | 2109 return; |
2110 } | 2110 } |
2111 | 2111 |
2112 // Check the status of connection after a delay. | 2112 // Check the status of connection after a delay. |
2113 MessageLoop::current()->PostDelayedTask( | 2113 MessageLoop::current()->PostDelayedTask( |
2114 FROM_HERE, | 2114 FROM_HERE, |
2115 base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(), | 2115 base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(), |
2116 now), | 2116 now), |
2117 delay); | 2117 delay); |
2118 } | 2118 } |
2119 | 2119 |
2120 void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) { | 2120 void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) { |
2121 UMA_HISTOGRAM_TIMES("Net.SpdyPing.RTT", duration); | 2121 UMA_HISTOGRAM_TIMES("Net.SpdyPing.RTT", duration); |
2122 } | 2122 } |
2123 | 2123 |
2124 void SpdySession::RecordProtocolErrorHistogram( | 2124 void SpdySession::RecordProtocolErrorHistogram( |
2125 SpdyProtocolErrorDetails details) { | 2125 SpdyProtocolErrorDetails details) { |
2126 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails", details, | 2126 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details, |
2127 NUM_SPDY_PROTOCOL_ERROR_DETAILS); | 2127 NUM_SPDY_PROTOCOL_ERROR_DETAILS); |
2128 if (EndsWith(host_port_pair().host(), "google.com", false)) { | 2128 if (EndsWith(host_port_pair().host(), "google.com", false)) { |
2129 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google", details, | 2129 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details, |
2130 NUM_SPDY_PROTOCOL_ERROR_DETAILS); | 2130 NUM_SPDY_PROTOCOL_ERROR_DETAILS); |
2131 } | 2131 } |
2132 } | 2132 } |
2133 | 2133 |
2134 void SpdySession::RecordHistograms() { | 2134 void SpdySession::RecordHistograms() { |
2135 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", | 2135 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", |
2136 streams_initiated_count_, | 2136 streams_initiated_count_, |
2137 0, 300, 50); | 2137 0, 300, 50); |
2138 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", | 2138 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", |
2139 streams_pushed_count_, | 2139 streams_pushed_count_, |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2243 // a WINDOW_UPDATE frame. | 2243 // a WINDOW_UPDATE frame. |
2244 } | 2244 } |
2245 | 2245 |
2246 void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) { | 2246 void SpdySession::IncreaseSendWindowSize(int32 delta_window_size) { |
2247 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); | 2247 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); |
2248 DCHECK_GE(delta_window_size, 1); | 2248 DCHECK_GE(delta_window_size, 1); |
2249 | 2249 |
2250 // Check for overflow. | 2250 // Check for overflow. |
2251 int32 max_delta_window_size = kint32max - session_send_window_size_; | 2251 int32 max_delta_window_size = kint32max - session_send_window_size_; |
2252 if (delta_window_size > max_delta_window_size) { | 2252 if (delta_window_size > max_delta_window_size) { |
2253 LOG(WARNING) << "Received WINDOW_UPDATE [delta: " | 2253 RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE); |
2254 << delta_window_size | 2254 CloseSessionOnError( |
2255 << "] for session overflows session_send_window_size_ " | 2255 ERR_SPDY_PROTOCOL_ERROR, |
2256 << "[current: " << session_send_window_size_ << "]"; | 2256 true, |
2257 // TODO(akalin): Figure out whether we should instead send a | 2257 "Received WINDOW_UPDATE [delta: " + |
2258 // GOAWAY and close the connection here. | 2258 base::IntToString(delta_window_size) + |
jar (doing other things)
2013/04/19 23:12:38
nit: Probably indent this 4 more than the argument
| |
2259 "] for session overflows session_send_window_size_ [current: " + | |
2260 base::IntToString(session_send_window_size_) + "]"); | |
2259 return; | 2261 return; |
2260 } | 2262 } |
2261 | 2263 |
2262 session_send_window_size_ += delta_window_size; | 2264 session_send_window_size_ += delta_window_size; |
2263 | 2265 |
2264 net_log_.AddEvent( | 2266 net_log_.AddEvent( |
2265 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW, | 2267 NetLog::TYPE_SPDY_SESSION_UPDATE_SEND_WINDOW, |
2266 base::Bind(&NetLogSpdySessionWindowUpdateCallback, | 2268 base::Bind(&NetLogSpdySessionWindowUpdateCallback, |
2267 delta_window_size, session_send_window_size_)); | 2269 delta_window_size, session_send_window_size_)); |
2268 | 2270 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2319 session_unacked_recv_window_bytes_, | 2321 session_unacked_recv_window_bytes_, |
2320 HIGHEST); | 2322 HIGHEST); |
2321 session_unacked_recv_window_bytes_ = 0; | 2323 session_unacked_recv_window_bytes_ = 0; |
2322 } | 2324 } |
2323 } | 2325 } |
2324 | 2326 |
2325 void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) { | 2327 void SpdySession::DecreaseRecvWindowSize(int32 delta_window_size) { |
2326 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); | 2328 DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); |
2327 DCHECK_GE(delta_window_size, 1); | 2329 DCHECK_GE(delta_window_size, 1); |
2328 | 2330 |
2329 // |delta_window_size| should never cause | 2331 // Since we never decrease the initial receive window size, |
2330 // |session_recv_window_size_| to go negative. If we do, it's a | 2332 // |delta_window_size| should never cause |recv_window_size_| to go |
2331 // client-side bug. | 2333 // negative. If we do, the receive window isn't being respected. |
2332 if (delta_window_size > session_recv_window_size_) { | 2334 if (delta_window_size > session_recv_window_size_) { |
2333 NOTREACHED() << "Received session WINDOW_UPDATE with an " | 2335 RecordProtocolErrorHistogram(PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION); |
2334 << "invalid delta_window_size " << delta_window_size; | 2336 CloseSessionOnError( |
2335 // TODO(akalin): Figure out whether we should instead send a | 2337 ERR_SPDY_PROTOCOL_ERROR, |
2336 // GOAWAY and close the connection here. | 2338 true, |
2339 "delta_window_size is " + base::IntToString(delta_window_size) + | |
2340 " in DecreaseRecvWindowSize, which is larger than the receive " + | |
jar (doing other things)
2013/04/19 23:12:38
nit: indent 4 more?
same on line 1859
| |
2341 "window size of " + base::IntToString(session_recv_window_size_)); | |
2337 return; | 2342 return; |
2338 } | 2343 } |
2339 | 2344 |
2340 session_recv_window_size_ -= delta_window_size; | 2345 session_recv_window_size_ -= delta_window_size; |
2341 net_log_.AddEvent( | 2346 net_log_.AddEvent( |
2342 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, | 2347 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, |
2343 base::Bind(&NetLogSpdySessionWindowUpdateCallback, | 2348 base::Bind(&NetLogSpdySessionWindowUpdateCallback, |
2344 -delta_window_size, session_recv_window_size_)); | 2349 -delta_window_size, session_recv_window_size_)); |
2345 } | 2350 } |
2346 | 2351 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2399 if (!queue->empty()) { | 2404 if (!queue->empty()) { |
2400 SpdyStreamId stream_id = queue->front(); | 2405 SpdyStreamId stream_id = queue->front(); |
2401 queue->pop_front(); | 2406 queue->pop_front(); |
2402 return stream_id; | 2407 return stream_id; |
2403 } | 2408 } |
2404 } | 2409 } |
2405 return 0; | 2410 return 0; |
2406 } | 2411 } |
2407 | 2412 |
2408 } // namespace net | 2413 } // namespace net |
OLD | NEW |