| 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/stats_counters.h" | 18 #include "base/metrics/stats_counters.h" |
| 18 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| 19 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 20 #include "base/string_util.h" | 21 #include "base/string_util.h" |
| 21 #include "base/stringprintf.h" | 22 #include "base/stringprintf.h" |
| 22 #include "base/time.h" | 23 #include "base/time.h" |
| 23 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
| 24 #include "base/values.h" | 25 #include "base/values.h" |
| 25 #include "crypto/ec_private_key.h" | 26 #include "crypto/ec_private_key.h" |
| 26 #include "crypto/ec_signature_creator.h" | 27 #include "crypto/ec_signature_creator.h" |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 size_t max_concurrent_streams_limit, | 302 size_t max_concurrent_streams_limit, |
| 302 TimeFunc time_func, | 303 TimeFunc time_func, |
| 303 const HostPortPair& trusted_spdy_proxy, | 304 const HostPortPair& trusted_spdy_proxy, |
| 304 NetLog* net_log) | 305 NetLog* net_log) |
| 305 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 306 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| 306 host_port_proxy_pair_(host_port_proxy_pair), | 307 host_port_proxy_pair_(host_port_proxy_pair), |
| 307 spdy_session_pool_(spdy_session_pool), | 308 spdy_session_pool_(spdy_session_pool), |
| 308 http_server_properties_(http_server_properties), | 309 http_server_properties_(http_server_properties), |
| 309 connection_(new ClientSocketHandle), | 310 connection_(new ClientSocketHandle), |
| 310 read_buffer_(new IOBuffer(kReadBufferSize)), | 311 read_buffer_(new IOBuffer(kReadBufferSize)), |
| 311 read_pending_(false), | |
| 312 stream_hi_water_mark_(kFirstStreamId), | 312 stream_hi_water_mark_(kFirstStreamId), |
| 313 write_pending_(false), | 313 write_pending_(false), |
| 314 in_flight_write_frame_type_(DATA), | 314 in_flight_write_frame_type_(DATA), |
| 315 delayed_write_pending_(false), | 315 delayed_write_pending_(false), |
| 316 is_secure_(false), | 316 is_secure_(false), |
| 317 certificate_error_code_(OK), | 317 certificate_error_code_(OK), |
| 318 error_(OK), | 318 error_(OK), |
| 319 state_(IDLE), | 319 state_(STATE_IDLE), |
| 320 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? | 320 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? |
| 321 kInitialMaxConcurrentStreams : | 321 kInitialMaxConcurrentStreams : |
| 322 initial_max_concurrent_streams), | 322 initial_max_concurrent_streams), |
| 323 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? | 323 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? |
| 324 kMaxConcurrentStreamLimit : | 324 kMaxConcurrentStreamLimit : |
| 325 max_concurrent_streams_limit), | 325 max_concurrent_streams_limit), |
| 326 streams_initiated_count_(0), | 326 streams_initiated_count_(0), |
| 327 streams_pushed_count_(0), | 327 streams_pushed_count_(0), |
| 328 streams_pushed_and_claimed_count_(0), | 328 streams_pushed_and_claimed_count_(0), |
| 329 streams_abandoned_count_(0), | 329 streams_abandoned_count_(0), |
| 330 bytes_received_(0), | 330 total_bytes_received_(0), |
| 331 bytes_read_(0), |
| 331 sent_settings_(false), | 332 sent_settings_(false), |
| 332 received_settings_(false), | 333 received_settings_(false), |
| 333 stalled_streams_(0), | 334 stalled_streams_(0), |
| 334 pings_in_flight_(0), | 335 pings_in_flight_(0), |
| 335 next_ping_id_(1), | 336 next_ping_id_(1), |
| 336 last_activity_time_(base::TimeTicks::Now()), | 337 last_activity_time_(base::TimeTicks::Now()), |
| 337 check_ping_status_pending_(false), | 338 check_ping_status_pending_(false), |
| 338 flow_control_state_(FLOW_CONTROL_NONE), | 339 flow_control_state_(FLOW_CONTROL_NONE), |
| 339 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), | 340 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), |
| 340 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? | 341 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? |
| (...skipping 20 matching lines...) Expand all Loading... |
| 361 DCHECK(HttpStreamFactory::spdy_enabled()); | 362 DCHECK(HttpStreamFactory::spdy_enabled()); |
| 362 net_log_.BeginEvent( | 363 net_log_.BeginEvent( |
| 363 NetLog::TYPE_SPDY_SESSION, | 364 NetLog::TYPE_SPDY_SESSION, |
| 364 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair_)); | 365 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair_)); |
| 365 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 366 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
| 366 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); | 367 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
| 367 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. | 368 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. |
| 368 } | 369 } |
| 369 | 370 |
| 370 SpdySession::~SpdySession() { | 371 SpdySession::~SpdySession() { |
| 371 if (state_ != CLOSED) { | 372 if (state_ != STATE_CLOSED) { |
| 372 state_ = CLOSED; | 373 state_ = STATE_CLOSED; |
| 373 | 374 |
| 374 // Cleanup all the streams. | 375 // Cleanup all the streams. |
| 375 CloseAllStreams(net::ERR_ABORTED); | 376 CloseAllStreams(net::ERR_ABORTED); |
| 376 } | 377 } |
| 377 | 378 |
| 378 if (connection_->is_initialized()) { | 379 if (connection_->is_initialized()) { |
| 379 // With SPDY we can't recycle sockets. | 380 // With SPDY we can't recycle sockets. |
| 380 connection_->socket()->Disconnect(); | 381 connection_->socket()->Disconnect(); |
| 381 } | 382 } |
| 382 | 383 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 394 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION); | 395 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION); |
| 395 } | 396 } |
| 396 | 397 |
| 397 net::Error SpdySession::InitializeWithSocket( | 398 net::Error SpdySession::InitializeWithSocket( |
| 398 ClientSocketHandle* connection, | 399 ClientSocketHandle* connection, |
| 399 bool is_secure, | 400 bool is_secure, |
| 400 int certificate_error_code) { | 401 int certificate_error_code) { |
| 401 base::StatsCounter spdy_sessions("spdy.sessions"); | 402 base::StatsCounter spdy_sessions("spdy.sessions"); |
| 402 spdy_sessions.Increment(); | 403 spdy_sessions.Increment(); |
| 403 | 404 |
| 404 state_ = CONNECTED; | 405 state_ = STATE_DO_READ; |
| 405 connection_.reset(connection); | 406 connection_.reset(connection); |
| 406 is_secure_ = is_secure; | 407 is_secure_ = is_secure; |
| 407 certificate_error_code_ = certificate_error_code; | 408 certificate_error_code_ = certificate_error_code; |
| 408 | 409 |
| 409 NextProto protocol = default_protocol_; | 410 NextProto protocol = default_protocol_; |
| 410 NextProto protocol_negotiated = connection->socket()->GetNegotiatedProtocol(); | 411 NextProto protocol_negotiated = connection->socket()->GetNegotiatedProtocol(); |
| 411 if (protocol_negotiated != kProtoUnknown) { | 412 if (protocol_negotiated != kProtoUnknown) { |
| 412 protocol = protocol_negotiated; | 413 protocol = protocol_negotiated; |
| 413 } | 414 } |
| 414 | 415 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 445 DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_); | 446 DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_); |
| 446 // This condition implies that |kDefaultInitialRecvWindowSize| - | 447 // This condition implies that |kDefaultInitialRecvWindowSize| - |
| 447 // |session_recv_window_size_| doesn't overflow. | 448 // |session_recv_window_size_| doesn't overflow. |
| 448 DCHECK_GT(session_recv_window_size_, 0); | 449 DCHECK_GT(session_recv_window_size_, 0); |
| 449 IncreaseRecvWindowSize( | 450 IncreaseRecvWindowSize( |
| 450 kDefaultInitialRecvWindowSize - session_recv_window_size_); | 451 kDefaultInitialRecvWindowSize - session_recv_window_size_); |
| 451 } | 452 } |
| 452 | 453 |
| 453 // Write out any data that we might have to send, such as the settings frame. | 454 // Write out any data that we might have to send, such as the settings frame. |
| 454 WriteSocketLater(); | 455 WriteSocketLater(); |
| 455 net::Error error = ReadSocket(); | 456 int error = DoLoop(OK); |
| 456 if (error == ERR_IO_PENDING) | 457 if (error == ERR_IO_PENDING) |
| 457 return OK; | 458 return OK; |
| 458 return error; | 459 return static_cast<net::Error>(error); |
| 459 } | 460 } |
| 460 | 461 |
| 461 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { | 462 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { |
| 462 if (!verify_domain_authentication_) | 463 if (!verify_domain_authentication_) |
| 463 return true; | 464 return true; |
| 464 | 465 |
| 465 if (state_ != CONNECTED) | 466 if (!IsConnected()) |
| 466 return false; | 467 return false; |
| 467 | 468 |
| 468 SSLInfo ssl_info; | 469 SSLInfo ssl_info; |
| 469 bool was_npn_negotiated; | 470 bool was_npn_negotiated; |
| 470 NextProto protocol_negotiated = kProtoUnknown; | 471 NextProto protocol_negotiated = kProtoUnknown; |
| 471 if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated)) | 472 if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated)) |
| 472 return true; // This is not a secure session, so all domains are okay. | 473 return true; // This is not a secure session, so all domains are okay. |
| 473 | 474 |
| 474 return !ssl_info.client_cert_sent && | 475 return !ssl_info.client_cert_sent && |
| 475 (enable_credential_frames_ || !ssl_info.channel_id_sent || | 476 (enable_credential_frames_ || !ssl_info.channel_id_sent || |
| 476 ServerBoundCertService::GetDomainForHost(domain) == | 477 ServerBoundCertService::GetDomainForHost(domain) == |
| 477 ServerBoundCertService::GetDomainForHost( | 478 ServerBoundCertService::GetDomainForHost( |
| 478 host_port_proxy_pair_.first.host())) && | 479 host_port_proxy_pair_.first.host())) && |
| 479 ssl_info.cert->VerifyNameMatch(domain); | 480 ssl_info.cert->VerifyNameMatch(domain); |
| 480 } | 481 } |
| 481 | 482 |
| 482 int SpdySession::GetPushStream( | 483 int SpdySession::GetPushStream( |
| 483 const GURL& url, | 484 const GURL& url, |
| 484 scoped_refptr<SpdyStream>* stream, | 485 scoped_refptr<SpdyStream>* stream, |
| 485 const BoundNetLog& stream_net_log) { | 486 const BoundNetLog& stream_net_log) { |
| 486 CHECK_NE(state_, CLOSED); | 487 CHECK_NE(state_, STATE_CLOSED); |
| 487 | 488 |
| 488 *stream = NULL; | 489 *stream = NULL; |
| 489 | 490 |
| 490 // Don't allow access to secure push streams over an unauthenticated, but | 491 // Don't allow access to secure push streams over an unauthenticated, but |
| 491 // encrypted SSL socket. | 492 // encrypted SSL socket. |
| 492 if (is_secure_ && certificate_error_code_ != OK && | 493 if (is_secure_ && certificate_error_code_ != OK && |
| 493 (url.SchemeIs("https") || url.SchemeIs("wss"))) { | 494 (url.SchemeIs("https") || url.SchemeIs("wss"))) { |
| 494 RecordProtocolErrorHistogram( | 495 RecordProtocolErrorHistogram( |
| 495 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); | 496 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); |
| 496 CloseSessionOnError( | 497 CloseSessionOnError( |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 return ContainsKey(active_streams_, stream_id); | 860 return ContainsKey(active_streams_, stream_id); |
| 860 } | 861 } |
| 861 | 862 |
| 862 LoadState SpdySession::GetLoadState() const { | 863 LoadState SpdySession::GetLoadState() const { |
| 863 // NOTE: The application only queries the LoadState via the | 864 // NOTE: The application only queries the LoadState via the |
| 864 // SpdyNetworkTransaction, and details are only needed when | 865 // SpdyNetworkTransaction, and details are only needed when |
| 865 // we're in the process of connecting. | 866 // we're in the process of connecting. |
| 866 | 867 |
| 867 // If we're connecting, defer to the connection to give us the actual | 868 // If we're connecting, defer to the connection to give us the actual |
| 868 // LoadState. | 869 // LoadState. |
| 869 if (state_ == CONNECTING) | 870 if (state_ == STATE_CONNECTING) |
| 870 return connection_->GetLoadState(); | 871 return connection_->GetLoadState(); |
| 871 | 872 |
| 872 // Just report that we're idle since the session could be doing | 873 // Just report that we're idle since the session could be doing |
| 873 // many things concurrently. | 874 // many things concurrently. |
| 874 return LOAD_STATE_IDLE; | 875 return LOAD_STATE_IDLE; |
| 875 } | 876 } |
| 876 | 877 |
| 877 void SpdySession::OnReadComplete(int bytes_read) { | 878 void SpdySession::OnReadComplete(int bytes_read) { |
| 878 // Parse a frame. For now this code requires that the frame fit into our | 879 DCHECK_NE(state_, STATE_DO_READ); |
| 879 // buffer (32KB). | 880 DoLoop(bytes_read); |
| 880 // TODO(mbelshe): support arbitrarily large frames! | 881 } |
| 881 | 882 |
| 882 read_pending_ = false; | 883 void SpdySession::StartRead() { |
| 884 DCHECK_NE(state_, STATE_DO_READ_COMPLETE); |
| 885 DoLoop(OK); |
| 886 } |
| 883 | 887 |
| 884 if (bytes_read <= 0) { | 888 int SpdySession::DoLoop(int result) { |
| 885 // Session is tearing down. | 889 bytes_read_ = 0; |
| 886 net::Error error = static_cast<net::Error>(bytes_read); | |
| 887 if (bytes_read == 0) | |
| 888 error = ERR_CONNECTION_CLOSED; | |
| 889 CloseSessionOnError(error, true, "bytes_read is <= 0."); | |
| 890 return; | |
| 891 } | |
| 892 | |
| 893 bytes_received_ += bytes_read; | |
| 894 | |
| 895 last_activity_time_ = base::TimeTicks::Now(); | |
| 896 | 890 |
| 897 // The SpdyFramer will use callbacks onto |this| as it parses frames. | 891 // The SpdyFramer will use callbacks onto |this| as it parses frames. |
| 898 // When errors occur, those callbacks can lead to teardown of all references | 892 // When errors occur, those callbacks can lead to teardown of all references |
| 899 // to |this|, so maintain a reference to self during this call for safe | 893 // to |this|, so maintain a reference to self during this call for safe |
| 900 // cleanup. | 894 // cleanup. |
| 901 scoped_refptr<SpdySession> self(this); | 895 scoped_refptr<SpdySession> self(this); |
| 902 | 896 |
| 897 do { |
| 898 switch (state_) { |
| 899 case STATE_DO_READ: |
| 900 DCHECK_EQ(result, OK); |
| 901 result = DoRead(); |
| 902 break; |
| 903 case STATE_DO_READ_COMPLETE: |
| 904 result = DoReadComplete(result); |
| 905 break; |
| 906 case STATE_CLOSED: |
| 907 result = ERR_CONNECTION_CLOSED; |
| 908 break; |
| 909 default: |
| 910 NOTREACHED() << "state_: " << state_; |
| 911 break; |
| 912 } |
| 913 } while (result != ERR_IO_PENDING && state_ != STATE_CLOSED); |
| 914 DCHECK(result == ERR_IO_PENDING || result == ERR_CONNECTION_CLOSED); |
| 915 |
| 916 return result; |
| 917 } |
| 918 |
| 919 int SpdySession::DoRead() { |
| 920 if (bytes_read_ > kMaxReadBytes) { |
| 921 state_ = STATE_DO_READ; |
| 922 MessageLoop::current()->PostTask( |
| 923 FROM_HERE, |
| 924 base::Bind(&SpdySession::StartRead, |
| 925 weak_factory_.GetWeakPtr())); |
| 926 return ERR_IO_PENDING; |
| 927 } |
| 928 |
| 929 CHECK(connection_.get()); |
| 930 CHECK(connection_->socket()); |
| 931 state_ = STATE_DO_READ_COMPLETE; |
| 932 return connection_->socket()->Read( |
| 933 read_buffer_.get(), |
| 934 kReadBufferSize, |
| 935 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); |
| 936 } |
| 937 |
| 938 int SpdySession::DoReadComplete(int result) { |
| 939 // Parse a frame. For now this code requires that the frame fit into our |
| 940 // buffer (32KB). |
| 941 // TODO(mbelshe): support arbitrarily large frames! |
| 942 |
| 943 if (result <= 0) { |
| 944 // Session is tearing down. |
| 945 net::Error error = static_cast<net::Error>(result); |
| 946 if (result == 0) { |
| 947 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF", |
| 948 total_bytes_received_, 1, 100000000, 50); |
| 949 error = ERR_CONNECTION_CLOSED; |
| 950 } |
| 951 CloseSessionOnError(error, true, "result is <= 0."); |
| 952 return ERR_CONNECTION_CLOSED; |
| 953 } |
| 954 |
| 955 total_bytes_received_ += result; |
| 956 bytes_read_ += result; |
| 957 |
| 958 last_activity_time_ = base::TimeTicks::Now(); |
| 959 |
| 903 DCHECK(buffered_spdy_framer_.get()); | 960 DCHECK(buffered_spdy_framer_.get()); |
| 904 char* data = read_buffer_->data(); | 961 char* data = read_buffer_->data(); |
| 905 while (bytes_read && | 962 while (result && |
| 906 buffered_spdy_framer_->error_code() == | 963 buffered_spdy_framer_->error_code() == |
| 907 SpdyFramer::SPDY_NO_ERROR) { | 964 SpdyFramer::SPDY_NO_ERROR) { |
| 908 uint32 bytes_processed = | 965 uint32 bytes_processed = |
| 909 buffered_spdy_framer_->ProcessInput(data, bytes_read); | 966 buffered_spdy_framer_->ProcessInput(data, result); |
| 910 bytes_read -= bytes_processed; | 967 result -= bytes_processed; |
| 911 data += bytes_processed; | 968 data += bytes_processed; |
| 912 } | 969 } |
| 913 | 970 |
| 914 if (state_ != CLOSED) | 971 if (!IsConnected()) |
| 915 ReadSocket(); | 972 return ERR_CONNECTION_CLOSED; |
| 973 |
| 974 state_ = STATE_DO_READ; |
| 975 return OK; |
| 916 } | 976 } |
| 917 | 977 |
| 918 void SpdySession::OnWriteComplete(int result) { | 978 void SpdySession::OnWriteComplete(int result) { |
| 919 // Releasing the in-flight write can have a side-effect of dropping | 979 // Releasing the in-flight write can have a side-effect of dropping |
| 920 // the last reference to |this|. Hold a reference through this | 980 // the last reference to |this|. Hold a reference through this |
| 921 // function. | 981 // function. |
| 922 scoped_refptr<SpdySession> self(this); | 982 scoped_refptr<SpdySession> self(this); |
| 923 | 983 |
| 924 DCHECK(write_pending_); | 984 DCHECK(write_pending_); |
| 925 DCHECK_GT(in_flight_write_.buffer()->BytesRemaining(), 0); | 985 DCHECK_GT(in_flight_write_.buffer()->BytesRemaining(), 0); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 in_flight_write_.Release(); | 1019 in_flight_write_.Release(); |
| 960 in_flight_write_frame_type_ = DATA; | 1020 in_flight_write_frame_type_ = DATA; |
| 961 } | 1021 } |
| 962 | 1022 |
| 963 // Write more data. We're already in a continuation, so we can go | 1023 // Write more data. We're already in a continuation, so we can go |
| 964 // ahead and write it immediately (without going back to the message | 1024 // ahead and write it immediately (without going back to the message |
| 965 // loop). | 1025 // loop). |
| 966 WriteSocketLater(); | 1026 WriteSocketLater(); |
| 967 } | 1027 } |
| 968 | 1028 |
| 969 net::Error SpdySession::ReadSocket() { | |
| 970 if (read_pending_) | |
| 971 return OK; | |
| 972 | |
| 973 if (state_ == CLOSED) { | |
| 974 NOTREACHED(); | |
| 975 return ERR_UNEXPECTED; | |
| 976 } | |
| 977 | |
| 978 CHECK(connection_.get()); | |
| 979 CHECK(connection_->socket()); | |
| 980 int bytes_read = connection_->socket()->Read( | |
| 981 read_buffer_.get(), | |
| 982 kReadBufferSize, | |
| 983 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); | |
| 984 switch (bytes_read) { | |
| 985 case 0: | |
| 986 // Socket is closed! | |
| 987 CloseSessionOnError(ERR_CONNECTION_CLOSED, true, "bytes_read is 0."); | |
| 988 return ERR_CONNECTION_CLOSED; | |
| 989 case net::ERR_IO_PENDING: | |
| 990 // Waiting for data. Nothing to do now. | |
| 991 read_pending_ = true; | |
| 992 return ERR_IO_PENDING; | |
| 993 default: | |
| 994 // Data was read, process it. | |
| 995 // Schedule the work through the message loop to avoid recursive | |
| 996 // callbacks. | |
| 997 read_pending_ = true; | |
| 998 MessageLoop::current()->PostTask( | |
| 999 FROM_HERE, | |
| 1000 base::Bind(&SpdySession::OnReadComplete, | |
| 1001 weak_factory_.GetWeakPtr(), bytes_read)); | |
| 1002 break; | |
| 1003 } | |
| 1004 return OK; | |
| 1005 } | |
| 1006 | |
| 1007 void SpdySession::WriteSocketLater() { | 1029 void SpdySession::WriteSocketLater() { |
| 1008 if (delayed_write_pending_) | 1030 if (delayed_write_pending_) |
| 1009 return; | 1031 return; |
| 1010 | 1032 |
| 1011 if (state_ < CONNECTED) | 1033 if (!IsConnected()) |
| 1012 return; | 1034 return; |
| 1013 | 1035 |
| 1014 delayed_write_pending_ = true; | 1036 delayed_write_pending_ = true; |
| 1015 MessageLoop::current()->PostTask( | 1037 MessageLoop::current()->PostTask( |
| 1016 FROM_HERE, | 1038 FROM_HERE, |
| 1017 base::Bind(&SpdySession::WriteSocket, weak_factory_.GetWeakPtr())); | 1039 base::Bind(&SpdySession::WriteSocket, weak_factory_.GetWeakPtr())); |
| 1018 } | 1040 } |
| 1019 | 1041 |
| 1020 void SpdySession::WriteSocket() { | 1042 void SpdySession::WriteSocket() { |
| 1021 // This function should only be called via WriteSocketLater. | 1043 // This function should only be called via WriteSocketLater. |
| 1022 DCHECK(delayed_write_pending_); | 1044 DCHECK(delayed_write_pending_); |
| 1023 delayed_write_pending_ = false; | 1045 delayed_write_pending_ = false; |
| 1024 | 1046 |
| 1025 // If the socket isn't connected yet, just wait; we'll get called | 1047 // If the socket isn't connected yet, just wait; we'll get called |
| 1026 // again when the socket connection completes. If the socket is | 1048 // again when the socket connection completes. If the socket is |
| 1027 // closed, just return. | 1049 // closed, just return. |
| 1028 if (state_ < CONNECTED || state_ == CLOSED) | 1050 if (!IsConnected()) |
| 1029 return; | 1051 return; |
| 1030 | 1052 |
| 1031 if (write_pending_) // Another write is in progress still. | 1053 if (write_pending_) // Another write is in progress still. |
| 1032 return; | 1054 return; |
| 1033 | 1055 |
| 1034 // Loop sending frames until we've sent everything or until the write | 1056 // Loop sending frames until we've sent everything or until the write |
| 1035 // returns error (or ERR_IO_PENDING). | 1057 // returns error (or ERR_IO_PENDING). |
| 1036 DCHECK(buffered_spdy_framer_.get()); | 1058 DCHECK(buffered_spdy_framer_.get()); |
| 1037 while (true) { | 1059 while (true) { |
| 1038 if (in_flight_write_.buffer()) { | 1060 if (in_flight_write_.buffer()) { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 scoped_refptr<SpdySession> self(this); | 1183 scoped_refptr<SpdySession> self(this); |
| 1162 | 1184 |
| 1163 DCHECK_LT(err, OK); | 1185 DCHECK_LT(err, OK); |
| 1164 net_log_.AddEvent( | 1186 net_log_.AddEvent( |
| 1165 NetLog::TYPE_SPDY_SESSION_CLOSE, | 1187 NetLog::TYPE_SPDY_SESSION_CLOSE, |
| 1166 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); | 1188 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); |
| 1167 | 1189 |
| 1168 // Don't close twice. This can occur because we can have both | 1190 // Don't close twice. This can occur because we can have both |
| 1169 // a read and a write outstanding, and each can complete with | 1191 // a read and a write outstanding, and each can complete with |
| 1170 // an error. | 1192 // an error. |
| 1171 if (state_ != CLOSED) { | 1193 if (!IsClosed()) { |
| 1172 state_ = CLOSED; | 1194 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err); |
| 1195 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.OtherErrors", |
| 1196 total_bytes_received_, 1, 100000000, 50); |
| 1197 state_ = STATE_CLOSED; |
| 1173 error_ = err; | 1198 error_ = err; |
| 1174 if (remove_from_pool) | 1199 if (remove_from_pool) |
| 1175 RemoveFromPool(); | 1200 RemoveFromPool(); |
| 1176 CloseAllStreams(err); | 1201 CloseAllStreams(err); |
| 1177 } | 1202 } |
| 1178 } | 1203 } |
| 1179 | 1204 |
| 1180 base::Value* SpdySession::GetInfoAsValue() const { | 1205 base::Value* SpdySession::GetInfoAsValue() const { |
| 1181 base::DictionaryValue* dict = new base::DictionaryValue(); | 1206 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 1182 | 1207 |
| (...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2097 SettingsMap::const_iterator it; | 2122 SettingsMap::const_iterator it; |
| 2098 for (it = settings_map.begin(); it != settings_map.end(); ++it) { | 2123 for (it = settings_map.begin(); it != settings_map.end(); ++it) { |
| 2099 const SpdySettingsIds id = it->first; | 2124 const SpdySettingsIds id = it->first; |
| 2100 const uint32 val = it->second.second; | 2125 const uint32 val = it->second.second; |
| 2101 switch (id) { | 2126 switch (id) { |
| 2102 case SETTINGS_CURRENT_CWND: | 2127 case SETTINGS_CURRENT_CWND: |
| 2103 // Record several different histograms to see if cwnd converges | 2128 // Record several different histograms to see if cwnd converges |
| 2104 // for larger volumes of data being sent. | 2129 // for larger volumes of data being sent. |
| 2105 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", | 2130 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", |
| 2106 val, 1, 200, 100); | 2131 val, 1, 200, 100); |
| 2107 if (bytes_received_ > 10 * 1024) { | 2132 if (total_bytes_received_ > 10 * 1024) { |
| 2108 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K", | 2133 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K", |
| 2109 val, 1, 200, 100); | 2134 val, 1, 200, 100); |
| 2110 if (bytes_received_ > 25 * 1024) { | 2135 if (total_bytes_received_ > 25 * 1024) { |
| 2111 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K", | 2136 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K", |
| 2112 val, 1, 200, 100); | 2137 val, 1, 200, 100); |
| 2113 if (bytes_received_ > 50 * 1024) { | 2138 if (total_bytes_received_ > 50 * 1024) { |
| 2114 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K", | 2139 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K", |
| 2115 val, 1, 200, 100); | 2140 val, 1, 200, 100); |
| 2116 if (bytes_received_ > 100 * 1024) { | 2141 if (total_bytes_received_ > 100 * 1024) { |
| 2117 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K", | 2142 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K", |
| 2118 val, 1, 200, 100); | 2143 val, 1, 200, 100); |
| 2119 } | 2144 } |
| 2120 } | 2145 } |
| 2121 } | 2146 } |
| 2122 } | 2147 } |
| 2123 break; | 2148 break; |
| 2124 case SETTINGS_ROUND_TRIP_TIME: | 2149 case SETTINGS_ROUND_TRIP_TIME: |
| 2125 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", | 2150 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", |
| 2126 val, 1, 1200, 100); | 2151 val, 1, 1200, 100); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 } | 2310 } |
| 2286 | 2311 |
| 2287 session_recv_window_size_ -= delta_window_size; | 2312 session_recv_window_size_ -= delta_window_size; |
| 2288 net_log_.AddEvent( | 2313 net_log_.AddEvent( |
| 2289 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, | 2314 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, |
| 2290 base::Bind(&NetLogSpdySessionWindowUpdateCallback, | 2315 base::Bind(&NetLogSpdySessionWindowUpdateCallback, |
| 2291 -delta_window_size, session_recv_window_size_)); | 2316 -delta_window_size, session_recv_window_size_)); |
| 2292 } | 2317 } |
| 2293 | 2318 |
| 2294 } // namespace net | 2319 } // namespace net |
| OLD | NEW |