Chromium Code Reviews| 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 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 size_t max_concurrent_streams_limit, | 323 size_t max_concurrent_streams_limit, |
| 323 TimeFunc time_func, | 324 TimeFunc time_func, |
| 324 const HostPortPair& trusted_spdy_proxy, | 325 const HostPortPair& trusted_spdy_proxy, |
| 325 NetLog* net_log) | 326 NetLog* net_log) |
| 326 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 327 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| 327 host_port_proxy_pair_(host_port_proxy_pair), | 328 host_port_proxy_pair_(host_port_proxy_pair), |
| 328 spdy_session_pool_(spdy_session_pool), | 329 spdy_session_pool_(spdy_session_pool), |
| 329 http_server_properties_(http_server_properties), | 330 http_server_properties_(http_server_properties), |
| 330 connection_(new ClientSocketHandle), | 331 connection_(new ClientSocketHandle), |
| 331 read_buffer_(new IOBuffer(kReadBufferSize)), | 332 read_buffer_(new IOBuffer(kReadBufferSize)), |
| 332 read_pending_(false), | |
| 333 stream_hi_water_mark_(kFirstStreamId), | 333 stream_hi_water_mark_(kFirstStreamId), |
| 334 write_pending_(false), | 334 write_pending_(false), |
| 335 delayed_write_pending_(false), | 335 delayed_write_pending_(false), |
| 336 is_secure_(false), | 336 is_secure_(false), |
| 337 certificate_error_code_(OK), | 337 certificate_error_code_(OK), |
| 338 error_(OK), | 338 error_(OK), |
| 339 state_(IDLE), | 339 state_(STATE_IDLE), |
| 340 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? | 340 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? |
| 341 kInitialMaxConcurrentStreams : | 341 kInitialMaxConcurrentStreams : |
| 342 initial_max_concurrent_streams), | 342 initial_max_concurrent_streams), |
| 343 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? | 343 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? |
| 344 kMaxConcurrentStreamLimit : | 344 kMaxConcurrentStreamLimit : |
| 345 max_concurrent_streams_limit), | 345 max_concurrent_streams_limit), |
| 346 streams_initiated_count_(0), | 346 streams_initiated_count_(0), |
| 347 streams_pushed_count_(0), | 347 streams_pushed_count_(0), |
| 348 streams_pushed_and_claimed_count_(0), | 348 streams_pushed_and_claimed_count_(0), |
| 349 streams_abandoned_count_(0), | 349 streams_abandoned_count_(0), |
| 350 bytes_received_(0), | 350 total_bytes_received_(0), |
| 351 bytes_read_(0), | |
| 351 sent_settings_(false), | 352 sent_settings_(false), |
| 352 received_settings_(false), | 353 received_settings_(false), |
| 353 stalled_streams_(0), | 354 stalled_streams_(0), |
| 354 pings_in_flight_(0), | 355 pings_in_flight_(0), |
| 355 next_ping_id_(1), | 356 next_ping_id_(1), |
| 356 last_activity_time_(base::TimeTicks::Now()), | 357 last_activity_time_(base::TimeTicks::Now()), |
| 357 check_ping_status_pending_(false), | 358 check_ping_status_pending_(false), |
| 358 flow_control_state_(FLOW_CONTROL_NONE), | 359 flow_control_state_(FLOW_CONTROL_NONE), |
| 359 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), | 360 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), |
| 360 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? | 361 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 381 DCHECK(HttpStreamFactory::spdy_enabled()); | 382 DCHECK(HttpStreamFactory::spdy_enabled()); |
| 382 net_log_.BeginEvent( | 383 net_log_.BeginEvent( |
| 383 NetLog::TYPE_SPDY_SESSION, | 384 NetLog::TYPE_SPDY_SESSION, |
| 384 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair_)); | 385 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair_)); |
| 385 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 386 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
| 386 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); | 387 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
| 387 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. | 388 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. |
| 388 } | 389 } |
| 389 | 390 |
| 390 SpdySession::~SpdySession() { | 391 SpdySession::~SpdySession() { |
| 391 if (state_ != CLOSED) { | 392 if (state_ != STATE_CLOSED) { |
| 392 state_ = CLOSED; | 393 state_ = STATE_CLOSED; |
| 393 | 394 |
| 394 // Cleanup all the streams. | 395 // Cleanup all the streams. |
| 395 CloseAllStreams(net::ERR_ABORTED); | 396 CloseAllStreams(net::ERR_ABORTED); |
| 396 } | 397 } |
| 397 | 398 |
| 398 if (connection_->is_initialized()) { | 399 if (connection_->is_initialized()) { |
| 399 // With SPDY we can't recycle sockets. | 400 // With SPDY we can't recycle sockets. |
| 400 connection_->socket()->Disconnect(); | 401 connection_->socket()->Disconnect(); |
| 401 } | 402 } |
| 402 | 403 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 414 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION); | 415 net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION); |
| 415 } | 416 } |
| 416 | 417 |
| 417 net::Error SpdySession::InitializeWithSocket( | 418 net::Error SpdySession::InitializeWithSocket( |
| 418 ClientSocketHandle* connection, | 419 ClientSocketHandle* connection, |
| 419 bool is_secure, | 420 bool is_secure, |
| 420 int certificate_error_code) { | 421 int certificate_error_code) { |
| 421 base::StatsCounter spdy_sessions("spdy.sessions"); | 422 base::StatsCounter spdy_sessions("spdy.sessions"); |
| 422 spdy_sessions.Increment(); | 423 spdy_sessions.Increment(); |
| 423 | 424 |
| 424 state_ = CONNECTED; | 425 state_ = STATE_DO_READ; |
| 425 connection_.reset(connection); | 426 connection_.reset(connection); |
| 426 is_secure_ = is_secure; | 427 is_secure_ = is_secure; |
| 427 certificate_error_code_ = certificate_error_code; | 428 certificate_error_code_ = certificate_error_code; |
| 428 | 429 |
| 429 NextProto protocol = default_protocol_; | 430 NextProto protocol = default_protocol_; |
| 430 NextProto protocol_negotiated = connection->socket()->GetNegotiatedProtocol(); | 431 NextProto protocol_negotiated = connection->socket()->GetNegotiatedProtocol(); |
| 431 if (protocol_negotiated != kProtoUnknown) { | 432 if (protocol_negotiated != kProtoUnknown) { |
| 432 protocol = protocol_negotiated; | 433 protocol = protocol_negotiated; |
| 433 } | 434 } |
| 434 | 435 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 465 DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_); | 466 DCHECK_GT(kDefaultInitialRecvWindowSize, session_recv_window_size_); |
| 466 // This condition implies that |kDefaultInitialRecvWindowSize| - | 467 // This condition implies that |kDefaultInitialRecvWindowSize| - |
| 467 // |session_recv_window_size_| doesn't overflow. | 468 // |session_recv_window_size_| doesn't overflow. |
| 468 DCHECK_GT(session_recv_window_size_, 0); | 469 DCHECK_GT(session_recv_window_size_, 0); |
| 469 IncreaseRecvWindowSize( | 470 IncreaseRecvWindowSize( |
| 470 kDefaultInitialRecvWindowSize - session_recv_window_size_); | 471 kDefaultInitialRecvWindowSize - session_recv_window_size_); |
| 471 } | 472 } |
| 472 | 473 |
| 473 // Write out any data that we might have to send, such as the settings frame. | 474 // Write out any data that we might have to send, such as the settings frame. |
| 474 WriteSocketLater(); | 475 WriteSocketLater(); |
| 475 net::Error error = ReadSocket(); | 476 int error = DoLoop(OK); |
| 476 if (error == ERR_IO_PENDING) | 477 if (error == ERR_IO_PENDING) |
| 477 return OK; | 478 return OK; |
| 478 return error; | 479 return static_cast<net::Error>(error); |
| 479 } | 480 } |
| 480 | 481 |
| 481 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { | 482 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { |
| 482 if (!verify_domain_authentication_) | 483 if (!verify_domain_authentication_) |
| 483 return true; | 484 return true; |
| 484 | 485 |
| 485 if (state_ != CONNECTED) | 486 if (!IsConnected()) |
| 486 return false; | 487 return false; |
| 487 | 488 |
| 488 SSLInfo ssl_info; | 489 SSLInfo ssl_info; |
| 489 bool was_npn_negotiated; | 490 bool was_npn_negotiated; |
| 490 NextProto protocol_negotiated = kProtoUnknown; | 491 NextProto protocol_negotiated = kProtoUnknown; |
| 491 if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated)) | 492 if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated)) |
| 492 return true; // This is not a secure session, so all domains are okay. | 493 return true; // This is not a secure session, so all domains are okay. |
| 493 | 494 |
| 494 return !ssl_info.client_cert_sent && | 495 return !ssl_info.client_cert_sent && |
| 495 (enable_credential_frames_ || !ssl_info.channel_id_sent || | 496 (enable_credential_frames_ || !ssl_info.channel_id_sent || |
| 496 ServerBoundCertService::GetDomainForHost(domain) == | 497 ServerBoundCertService::GetDomainForHost(domain) == |
| 497 ServerBoundCertService::GetDomainForHost( | 498 ServerBoundCertService::GetDomainForHost( |
| 498 host_port_proxy_pair_.first.host())) && | 499 host_port_proxy_pair_.first.host())) && |
| 499 ssl_info.cert->VerifyNameMatch(domain); | 500 ssl_info.cert->VerifyNameMatch(domain); |
| 500 } | 501 } |
| 501 | 502 |
| 502 void SpdySession::SetStreamHasWriteAvailable(SpdyStream* stream, | 503 void SpdySession::SetStreamHasWriteAvailable(SpdyStream* stream, |
| 503 SpdyIOBufferProducer* producer) { | 504 SpdyIOBufferProducer* producer) { |
| 504 write_queue_.push(producer); | 505 write_queue_.push(producer); |
| 505 stream_producers_[producer] = stream; | 506 stream_producers_[producer] = stream; |
| 506 WriteSocketLater(); | 507 WriteSocketLater(); |
| 507 } | 508 } |
| 508 | 509 |
| 509 int SpdySession::GetPushStream( | 510 int SpdySession::GetPushStream( |
| 510 const GURL& url, | 511 const GURL& url, |
| 511 scoped_refptr<SpdyStream>* stream, | 512 scoped_refptr<SpdyStream>* stream, |
| 512 const BoundNetLog& stream_net_log) { | 513 const BoundNetLog& stream_net_log) { |
| 513 CHECK_NE(state_, CLOSED); | 514 CHECK_NE(state_, STATE_CLOSED); |
| 514 | 515 |
| 515 *stream = NULL; | 516 *stream = NULL; |
| 516 | 517 |
| 517 // Don't allow access to secure push streams over an unauthenticated, but | 518 // Don't allow access to secure push streams over an unauthenticated, but |
| 518 // encrypted SSL socket. | 519 // encrypted SSL socket. |
| 519 if (is_secure_ && certificate_error_code_ != OK && | 520 if (is_secure_ && certificate_error_code_ != OK && |
| 520 (url.SchemeIs("https") || url.SchemeIs("wss"))) { | 521 (url.SchemeIs("https") || url.SchemeIs("wss"))) { |
| 521 RecordProtocolErrorHistogram( | 522 RecordProtocolErrorHistogram( |
| 522 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); | 523 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION); |
| 523 CloseSessionOnError( | 524 CloseSessionOnError( |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 return ContainsKey(active_streams_, stream_id); | 874 return ContainsKey(active_streams_, stream_id); |
| 874 } | 875 } |
| 875 | 876 |
| 876 LoadState SpdySession::GetLoadState() const { | 877 LoadState SpdySession::GetLoadState() const { |
| 877 // NOTE: The application only queries the LoadState via the | 878 // NOTE: The application only queries the LoadState via the |
| 878 // SpdyNetworkTransaction, and details are only needed when | 879 // SpdyNetworkTransaction, and details are only needed when |
| 879 // we're in the process of connecting. | 880 // we're in the process of connecting. |
| 880 | 881 |
| 881 // If we're connecting, defer to the connection to give us the actual | 882 // If we're connecting, defer to the connection to give us the actual |
| 882 // LoadState. | 883 // LoadState. |
| 883 if (state_ == CONNECTING) | 884 if (state_ == STATE_CONNECTING) |
| 884 return connection_->GetLoadState(); | 885 return connection_->GetLoadState(); |
| 885 | 886 |
| 886 // Just report that we're idle since the session could be doing | 887 // Just report that we're idle since the session could be doing |
| 887 // many things concurrently. | 888 // many things concurrently. |
| 888 return LOAD_STATE_IDLE; | 889 return LOAD_STATE_IDLE; |
| 889 } | 890 } |
| 890 | 891 |
| 891 void SpdySession::OnReadComplete(int bytes_read) { | 892 void SpdySession::OnReadComplete(int bytes_read) { |
| 892 // Parse a frame. For now this code requires that the frame fit into our | 893 DCHECK_NE(state_, STATE_DO_READ); |
| 893 // buffer (32KB). | 894 DoLoop(bytes_read); |
| 894 // TODO(mbelshe): support arbitrarily large frames! | 895 } |
| 895 | 896 |
| 896 read_pending_ = false; | 897 void SpdySession::StartRead() { |
| 898 DCHECK_NE(state_, STATE_DO_READ_COMPLETE); | |
| 899 DoLoop(OK); | |
| 900 } | |
| 897 | 901 |
| 898 if (bytes_read <= 0) { | 902 int SpdySession::DoLoop(int result) { |
| 899 // Session is tearing down. | 903 bytes_read_ = 0; |
| 900 net::Error error = static_cast<net::Error>(bytes_read); | |
| 901 if (bytes_read == 0) | |
| 902 error = ERR_CONNECTION_CLOSED; | |
| 903 CloseSessionOnError(error, true, "bytes_read is <= 0."); | |
| 904 return; | |
| 905 } | |
| 906 | |
| 907 bytes_received_ += bytes_read; | |
| 908 | |
| 909 last_activity_time_ = base::TimeTicks::Now(); | |
| 910 | 904 |
| 911 // The SpdyFramer will use callbacks onto |this| as it parses frames. | 905 // The SpdyFramer will use callbacks onto |this| as it parses frames. |
| 912 // When errors occur, those callbacks can lead to teardown of all references | 906 // When errors occur, those callbacks can lead to teardown of all references |
| 913 // to |this|, so maintain a reference to self during this call for safe | 907 // to |this|, so maintain a reference to self during this call for safe |
| 914 // cleanup. | 908 // cleanup. |
| 915 scoped_refptr<SpdySession> self(this); | 909 scoped_refptr<SpdySession> self(this); |
| 916 | 910 |
| 911 do { | |
| 912 switch (state_) { | |
| 913 case STATE_DO_READ: | |
| 914 DCHECK_EQ(result, OK); | |
| 915 result = DoRead(); | |
| 916 break; | |
| 917 case STATE_DO_READ_COMPLETE: | |
| 918 result = DoReadComplete(result); | |
| 919 break; | |
| 920 case STATE_CLOSED: | |
| 921 result = ERR_CONNECTION_CLOSED; | |
| 922 break; | |
| 923 default: | |
| 924 NOTREACHED() << "state_: " << state_; | |
| 925 break; | |
| 926 } | |
| 927 } while (result != ERR_IO_PENDING && state_ != STATE_CLOSED); | |
| 928 | |
| 929 return result; | |
| 930 } | |
| 931 | |
| 932 int SpdySession::DoRead() { | |
| 933 if (bytes_read_ > kMaxReadBytes) { | |
| 934 state_ = STATE_DO_READ; | |
| 935 MessageLoop::current()->PostTask( | |
| 936 FROM_HERE, | |
| 937 base::Bind(&SpdySession::StartRead, | |
| 938 weak_factory_.GetWeakPtr())); | |
| 939 return ERR_IO_PENDING; | |
| 940 } | |
| 941 | |
| 942 CHECK(connection_.get()); | |
| 943 CHECK(connection_->socket()); | |
| 944 state_ = STATE_DO_READ_COMPLETE; | |
| 945 return connection_->socket()->Read( | |
| 946 read_buffer_.get(), | |
| 947 kReadBufferSize, | |
| 948 base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr())); | |
| 949 } | |
| 950 | |
| 951 int SpdySession::DoReadComplete(int result) { | |
| 952 // Parse a frame. For now this code requires that the frame fit into our | |
| 953 // buffer (32KB). | |
| 954 // TODO(mbelshe): support arbitrarily large frames! | |
| 955 | |
| 956 if (result <= 0) { | |
| 957 // Session is tearing down. | |
| 958 net::Error error = static_cast<net::Error>(result); | |
| 959 if (result == 0) { | |
| 960 UMA_HISTOGRAM_COUNTS("Net.SpdySession.BytesRead.EOF", | |
| 961 total_bytes_received_); | |
| 962 error = ERR_CONNECTION_CLOSED; | |
| 963 } | |
| 964 CloseSessionOnError(error, true, "result is <= 0."); | |
| 965 return ERR_CONNECTION_CLOSED; | |
| 966 } | |
| 967 | |
| 968 total_bytes_received_ += result; | |
| 969 bytes_read_ += result; | |
| 970 | |
| 971 last_activity_time_ = base::TimeTicks::Now(); | |
| 972 | |
| 917 DCHECK(buffered_spdy_framer_.get()); | 973 DCHECK(buffered_spdy_framer_.get()); |
| 918 char* data = read_buffer_->data(); | 974 char* data = read_buffer_->data(); |
| 919 while (bytes_read && | 975 while (result && |
| 920 buffered_spdy_framer_->error_code() == | 976 buffered_spdy_framer_->error_code() == |
| 921 SpdyFramer::SPDY_NO_ERROR) { | 977 SpdyFramer::SPDY_NO_ERROR) { |
| 922 uint32 bytes_processed = | 978 uint32 bytes_processed = |
| 923 buffered_spdy_framer_->ProcessInput(data, bytes_read); | 979 buffered_spdy_framer_->ProcessInput(data, result); |
| 924 bytes_read -= bytes_processed; | 980 result -= bytes_processed; |
| 925 data += bytes_processed; | 981 data += bytes_processed; |
| 926 } | 982 } |
| 927 | 983 |
| 928 if (state_ != CLOSED) | 984 if (IsConnected()) |
| 929 ReadSocket(); | 985 state_ = STATE_DO_READ; |
| 986 return OK; | |
| 930 } | 987 } |
| 931 | 988 |
| 932 void SpdySession::OnWriteComplete(int result) { | 989 void SpdySession::OnWriteComplete(int result) { |
| 933 DCHECK(write_pending_); | 990 DCHECK(write_pending_); |
| 934 DCHECK(in_flight_write_.size()); | 991 DCHECK(in_flight_write_.size()); |
| 935 | 992 |
| 936 last_activity_time_ = base::TimeTicks::Now(); | 993 last_activity_time_ = base::TimeTicks::Now(); |
| 937 write_pending_ = false; | 994 write_pending_ = false; |
| 938 | 995 |
| 939 scoped_refptr<SpdyStream> stream = in_flight_write_.stream(); | 996 scoped_refptr<SpdyStream> stream = in_flight_write_.stream(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 976 WriteSocketLater(); | 1033 WriteSocketLater(); |
| 977 } else { | 1034 } else { |
| 978 in_flight_write_.release(); | 1035 in_flight_write_.release(); |
| 979 | 1036 |
| 980 // The stream is now errored. Close it down. | 1037 // The stream is now errored. Close it down. |
| 981 CloseSessionOnError( | 1038 CloseSessionOnError( |
| 982 static_cast<net::Error>(result), true, "The stream has errored."); | 1039 static_cast<net::Error>(result), true, "The stream has errored."); |
| 983 } | 1040 } |
| 984 } | 1041 } |
| 985 | 1042 |
| 986 net::Error SpdySession::ReadSocket() { | |
| 987 if (read_pending_) | |
| 988 return OK; | |
| 989 | |
| 990 if (state_ == CLOSED) { | |
| 991 NOTREACHED(); | |
| 992 return ERR_UNEXPECTED; | |
| 993 } | |
| 994 | |
| 995 CHECK(connection_.get()); | |
| 996 CHECK(connection_->socket()); | |
| 997 int bytes_read = connection_->socket()->Read( | |
| 998 read_buffer_.get(), | |
| 999 kReadBufferSize, | |
| 1000 base::Bind(&SpdySession::OnReadComplete, base::Unretained(this))); | |
| 1001 switch (bytes_read) { | |
| 1002 case 0: | |
| 1003 // Socket is closed! | |
| 1004 CloseSessionOnError(ERR_CONNECTION_CLOSED, true, "bytes_read is 0."); | |
| 1005 return ERR_CONNECTION_CLOSED; | |
| 1006 case net::ERR_IO_PENDING: | |
| 1007 // Waiting for data. Nothing to do now. | |
| 1008 read_pending_ = true; | |
| 1009 return ERR_IO_PENDING; | |
| 1010 default: | |
| 1011 // Data was read, process it. | |
| 1012 // Schedule the work through the message loop to avoid recursive | |
| 1013 // callbacks. | |
| 1014 read_pending_ = true; | |
| 1015 MessageLoop::current()->PostTask( | |
| 1016 FROM_HERE, | |
| 1017 base::Bind(&SpdySession::OnReadComplete, | |
| 1018 weak_factory_.GetWeakPtr(), bytes_read)); | |
| 1019 break; | |
| 1020 } | |
| 1021 return OK; | |
| 1022 } | |
| 1023 | |
| 1024 void SpdySession::WriteSocketLater() { | 1043 void SpdySession::WriteSocketLater() { |
| 1025 if (delayed_write_pending_) | 1044 if (delayed_write_pending_) |
| 1026 return; | 1045 return; |
| 1027 | 1046 |
| 1028 if (state_ < CONNECTED) | 1047 if (!IsConnected()) |
| 1029 return; | 1048 return; |
| 1030 | 1049 |
| 1031 delayed_write_pending_ = true; | 1050 delayed_write_pending_ = true; |
| 1032 MessageLoop::current()->PostTask( | 1051 MessageLoop::current()->PostTask( |
| 1033 FROM_HERE, | 1052 FROM_HERE, |
| 1034 base::Bind(&SpdySession::WriteSocket, weak_factory_.GetWeakPtr())); | 1053 base::Bind(&SpdySession::WriteSocket, weak_factory_.GetWeakPtr())); |
| 1035 } | 1054 } |
| 1036 | 1055 |
| 1037 void SpdySession::WriteSocket() { | 1056 void SpdySession::WriteSocket() { |
| 1038 // This function should only be called via WriteSocketLater. | 1057 // This function should only be called via WriteSocketLater. |
| 1039 DCHECK(delayed_write_pending_); | 1058 DCHECK(delayed_write_pending_); |
| 1040 delayed_write_pending_ = false; | 1059 delayed_write_pending_ = false; |
| 1041 | 1060 |
| 1042 // If the socket isn't connected yet, just wait; we'll get called | 1061 // If the socket isn't connected yet, just wait; we'll get called |
| 1043 // again when the socket connection completes. If the socket is | 1062 // again when the socket connection completes. If the socket is |
| 1044 // closed, just return. | 1063 // closed, just return. |
| 1045 if (state_ < CONNECTED || state_ == CLOSED) | 1064 if (!IsConnected()) |
| 1046 return; | 1065 return; |
| 1047 | 1066 |
| 1048 if (write_pending_) // Another write is in progress still. | 1067 if (write_pending_) // Another write is in progress still. |
| 1049 return; | 1068 return; |
| 1050 | 1069 |
| 1051 // Loop sending frames until we've sent everything or until the write | 1070 // Loop sending frames until we've sent everything or until the write |
| 1052 // returns error (or ERR_IO_PENDING). | 1071 // returns error (or ERR_IO_PENDING). |
| 1053 DCHECK(buffered_spdy_framer_.get()); | 1072 DCHECK(buffered_spdy_framer_.get()); |
| 1054 while (in_flight_write_.buffer() || !write_queue_.empty()) { | 1073 while (in_flight_write_.buffer() || !write_queue_.empty()) { |
| 1055 if (!in_flight_write_.buffer()) { | 1074 if (!in_flight_write_.buffer()) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1158 scoped_refptr<SpdySession> self(this); | 1177 scoped_refptr<SpdySession> self(this); |
| 1159 | 1178 |
| 1160 DCHECK_LT(err, OK); | 1179 DCHECK_LT(err, OK); |
| 1161 net_log_.AddEvent( | 1180 net_log_.AddEvent( |
| 1162 NetLog::TYPE_SPDY_SESSION_CLOSE, | 1181 NetLog::TYPE_SPDY_SESSION_CLOSE, |
| 1163 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); | 1182 base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); |
| 1164 | 1183 |
| 1165 // Don't close twice. This can occur because we can have both | 1184 // Don't close twice. This can occur because we can have both |
| 1166 // a read and a write outstanding, and each can complete with | 1185 // a read and a write outstanding, and each can complete with |
| 1167 // an error. | 1186 // an error. |
| 1168 if (state_ != CLOSED) { | 1187 if (!IsClosed()) { |
| 1169 state_ = CLOSED; | 1188 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError.Error", -err); |
|
Ryan Hamilton
2013/04/16 19:54:47
jar: how slowly is slowly?
Ryan Hamilton
2013/04/16 19:54:47
nit: I think I would drop the trailing .Error sinc
ramant (doing other things)
2013/04/16 21:45:15
Done.
| |
| 1189 UMA_HISTOGRAM_COUNTS("Net.SpdySession.BytesRead.OtherErrors", | |
| 1190 total_bytes_received_); | |
| 1191 state_ = STATE_CLOSED; | |
| 1170 error_ = err; | 1192 error_ = err; |
| 1171 if (remove_from_pool) | 1193 if (remove_from_pool) |
| 1172 RemoveFromPool(); | 1194 RemoveFromPool(); |
| 1173 CloseAllStreams(err); | 1195 CloseAllStreams(err); |
| 1174 } | 1196 } |
| 1175 } | 1197 } |
| 1176 | 1198 |
| 1177 base::Value* SpdySession::GetInfoAsValue() const { | 1199 base::Value* SpdySession::GetInfoAsValue() const { |
| 1178 base::DictionaryValue* dict = new base::DictionaryValue(); | 1200 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 1179 | 1201 |
| (...skipping 936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2116 SettingsMap::const_iterator it; | 2138 SettingsMap::const_iterator it; |
| 2117 for (it = settings_map.begin(); it != settings_map.end(); ++it) { | 2139 for (it = settings_map.begin(); it != settings_map.end(); ++it) { |
| 2118 const SpdySettingsIds id = it->first; | 2140 const SpdySettingsIds id = it->first; |
| 2119 const uint32 val = it->second.second; | 2141 const uint32 val = it->second.second; |
| 2120 switch (id) { | 2142 switch (id) { |
| 2121 case SETTINGS_CURRENT_CWND: | 2143 case SETTINGS_CURRENT_CWND: |
| 2122 // Record several different histograms to see if cwnd converges | 2144 // Record several different histograms to see if cwnd converges |
| 2123 // for larger volumes of data being sent. | 2145 // for larger volumes of data being sent. |
| 2124 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", | 2146 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", |
| 2125 val, 1, 200, 100); | 2147 val, 1, 200, 100); |
| 2126 if (bytes_received_ > 10 * 1024) { | 2148 if (total_bytes_received_ > 10 * 1024) { |
| 2127 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K", | 2149 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K", |
| 2128 val, 1, 200, 100); | 2150 val, 1, 200, 100); |
| 2129 if (bytes_received_ > 25 * 1024) { | 2151 if (total_bytes_received_ > 25 * 1024) { |
| 2130 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K", | 2152 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K", |
| 2131 val, 1, 200, 100); | 2153 val, 1, 200, 100); |
| 2132 if (bytes_received_ > 50 * 1024) { | 2154 if (total_bytes_received_ > 50 * 1024) { |
| 2133 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K", | 2155 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K", |
| 2134 val, 1, 200, 100); | 2156 val, 1, 200, 100); |
| 2135 if (bytes_received_ > 100 * 1024) { | 2157 if (total_bytes_received_ > 100 * 1024) { |
| 2136 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K", | 2158 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K", |
| 2137 val, 1, 200, 100); | 2159 val, 1, 200, 100); |
| 2138 } | 2160 } |
| 2139 } | 2161 } |
| 2140 } | 2162 } |
| 2141 } | 2163 } |
| 2142 break; | 2164 break; |
| 2143 case SETTINGS_ROUND_TRIP_TIME: | 2165 case SETTINGS_ROUND_TRIP_TIME: |
| 2144 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", | 2166 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", |
| 2145 val, 1, 1200, 100); | 2167 val, 1, 1200, 100); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2304 } | 2326 } |
| 2305 | 2327 |
| 2306 session_recv_window_size_ -= delta_window_size; | 2328 session_recv_window_size_ -= delta_window_size; |
| 2307 net_log_.AddEvent( | 2329 net_log_.AddEvent( |
| 2308 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, | 2330 NetLog::TYPE_SPDY_SESSION_UPDATE_RECV_WINDOW, |
| 2309 base::Bind(&NetLogSpdySessionWindowUpdateCallback, | 2331 base::Bind(&NetLogSpdySessionWindowUpdateCallback, |
| 2310 -delta_window_size, session_recv_window_size_)); | 2332 -delta_window_size, session_recv_window_size_)); |
| 2311 } | 2333 } |
| 2312 | 2334 |
| 2313 } // namespace net | 2335 } // namespace net |
| OLD | NEW |