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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |