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 <map> | 7 #include <map> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 CHECK_NE(state_, CLOSED); | 490 CHECK_NE(state_, CLOSED); |
491 | 491 |
492 *stream = NULL; | 492 *stream = NULL; |
493 | 493 |
494 // Don't allow access to secure push streams over an unauthenticated, but | 494 // Don't allow access to secure push streams over an unauthenticated, but |
495 // encrypted SSL socket. | 495 // encrypted SSL socket. |
496 if (is_secure_ && certificate_error_code_ != OK && | 496 if (is_secure_ && certificate_error_code_ != OK && |
497 (url.SchemeIs("https") || url.SchemeIs("wss"))) { | 497 (url.SchemeIs("https") || url.SchemeIs("wss"))) { |
498 CloseSessionOnError( | 498 CloseSessionOnError( |
499 static_cast<net::Error>(certificate_error_code_), | 499 static_cast<net::Error>(certificate_error_code_), |
| 500 REQUST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION, |
500 true, | 501 true, |
501 "Tried to get SPDY stream for secure content over an unauthenticated " | 502 "Tried to get SPDY stream for secure content over an unauthenticated " |
502 "session."); | 503 "session."); |
503 return ERR_SPDY_PROTOCOL_ERROR; | 504 return ERR_SPDY_PROTOCOL_ERROR; |
504 } | 505 } |
505 | 506 |
506 *stream = GetActivePushStream(url.spec()); | 507 *stream = GetActivePushStream(url.spec()); |
507 if (stream->get()) { | 508 if (stream->get()) { |
508 DCHECK(streams_pushed_and_claimed_count_ < streams_pushed_count_); | 509 DCHECK(streams_pushed_and_claimed_count_ < streams_pushed_count_); |
509 streams_pushed_and_claimed_count_++; | 510 streams_pushed_and_claimed_count_++; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 const BoundNetLog& stream_net_log) { | 593 const BoundNetLog& stream_net_log) { |
593 DCHECK_GE(priority, MINIMUM_PRIORITY); | 594 DCHECK_GE(priority, MINIMUM_PRIORITY); |
594 DCHECK_LT(priority, NUM_PRIORITIES); | 595 DCHECK_LT(priority, NUM_PRIORITIES); |
595 | 596 |
596 // Make sure that we don't try to send https/wss over an unauthenticated, but | 597 // Make sure that we don't try to send https/wss over an unauthenticated, but |
597 // encrypted SSL socket. | 598 // encrypted SSL socket. |
598 if (is_secure_ && certificate_error_code_ != OK && | 599 if (is_secure_ && certificate_error_code_ != OK && |
599 (url.SchemeIs("https") || url.SchemeIs("wss"))) { | 600 (url.SchemeIs("https") || url.SchemeIs("wss"))) { |
600 CloseSessionOnError( | 601 CloseSessionOnError( |
601 static_cast<net::Error>(certificate_error_code_), | 602 static_cast<net::Error>(certificate_error_code_), |
| 603 REQUST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION, |
602 true, | 604 true, |
603 "Tried to create SPDY stream for secure content over an " | 605 "Tried to create SPDY stream for secure content over an " |
604 "unauthenticated session."); | 606 "unauthenticated session."); |
605 return ERR_SPDY_PROTOCOL_ERROR; | 607 return ERR_SPDY_PROTOCOL_ERROR; |
606 } | 608 } |
607 | 609 |
608 const std::string& path = url.PathForRequest(); | 610 const std::string& path = url.PathForRequest(); |
609 | 611 |
610 const SpdyStreamId stream_id = GetNewStreamId(); | 612 const SpdyStreamId stream_id = GetNewStreamId(); |
611 | 613 |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
869 // buffer (32KB). | 871 // buffer (32KB). |
870 // TODO(mbelshe): support arbitrarily large frames! | 872 // TODO(mbelshe): support arbitrarily large frames! |
871 | 873 |
872 read_pending_ = false; | 874 read_pending_ = false; |
873 | 875 |
874 if (bytes_read <= 0) { | 876 if (bytes_read <= 0) { |
875 // Session is tearing down. | 877 // Session is tearing down. |
876 net::Error error = static_cast<net::Error>(bytes_read); | 878 net::Error error = static_cast<net::Error>(bytes_read); |
877 if (bytes_read == 0) | 879 if (bytes_read == 0) |
878 error = ERR_CONNECTION_CLOSED; | 880 error = ERR_CONNECTION_CLOSED; |
879 CloseSessionOnError(error, true, "bytes_read is <= 0."); | 881 CloseSessionOnError(error, READ_FAILED, true, |
| 882 "bytes_read is <= 0."); |
880 return; | 883 return; |
881 } | 884 } |
882 | 885 |
883 bytes_received_ += bytes_read; | 886 bytes_received_ += bytes_read; |
884 | 887 |
885 received_data_time_ = base::TimeTicks::Now(); | 888 received_data_time_ = base::TimeTicks::Now(); |
886 | 889 |
887 // The SpdyFramer will use callbacks onto |this| as it parses frames. | 890 // The SpdyFramer will use callbacks onto |this| as it parses frames. |
888 // When errors occur, those callbacks can lead to teardown of all references | 891 // When errors occur, those callbacks can lead to teardown of all references |
889 // to |this|, so maintain a reference to self during this call for safe | 892 // to |this|, so maintain a reference to self during this call for safe |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 | 950 |
948 // Write more data. We're already in a continuation, so we can | 951 // Write more data. We're already in a continuation, so we can |
949 // go ahead and write it immediately (without going back to the | 952 // go ahead and write it immediately (without going back to the |
950 // message loop). | 953 // message loop). |
951 WriteSocketLater(); | 954 WriteSocketLater(); |
952 } else { | 955 } else { |
953 in_flight_write_.release(); | 956 in_flight_write_.release(); |
954 | 957 |
955 // The stream is now errored. Close it down. | 958 // The stream is now errored. Close it down. |
956 CloseSessionOnError( | 959 CloseSessionOnError( |
957 static_cast<net::Error>(result), true, "The stream has errored."); | 960 static_cast<net::Error>(result), WRITE_FAILED, true, |
| 961 "The stream has errored."); |
958 } | 962 } |
959 } | 963 } |
960 | 964 |
961 net::Error SpdySession::ReadSocket() { | 965 net::Error SpdySession::ReadSocket() { |
962 if (read_pending_) | 966 if (read_pending_) |
963 return OK; | 967 return OK; |
964 | 968 |
965 if (state_ == CLOSED) { | 969 if (state_ == CLOSED) { |
966 NOTREACHED(); | 970 NOTREACHED(); |
967 return ERR_UNEXPECTED; | 971 return ERR_UNEXPECTED; |
968 } | 972 } |
969 | 973 |
970 CHECK(connection_.get()); | 974 CHECK(connection_.get()); |
971 CHECK(connection_->socket()); | 975 CHECK(connection_->socket()); |
972 int bytes_read = connection_->socket()->Read( | 976 int bytes_read = connection_->socket()->Read( |
973 read_buffer_.get(), | 977 read_buffer_.get(), |
974 kReadBufferSize, | 978 kReadBufferSize, |
975 base::Bind(&SpdySession::OnReadComplete, base::Unretained(this))); | 979 base::Bind(&SpdySession::OnReadComplete, base::Unretained(this))); |
976 switch (bytes_read) { | 980 switch (bytes_read) { |
977 case 0: | 981 case 0: |
978 // Socket is closed! | 982 // Socket is closed! |
979 CloseSessionOnError(ERR_CONNECTION_CLOSED, true, "bytes_read is 0."); | 983 CloseSessionOnError(ERR_CONNECTION_CLOSED, READ_FAILED, true, |
| 984 "bytes_read is 0."); |
980 return ERR_CONNECTION_CLOSED; | 985 return ERR_CONNECTION_CLOSED; |
981 case net::ERR_IO_PENDING: | 986 case net::ERR_IO_PENDING: |
982 // Waiting for data. Nothing to do now. | 987 // Waiting for data. Nothing to do now. |
983 read_pending_ = true; | 988 read_pending_ = true; |
984 return ERR_IO_PENDING; | 989 return ERR_IO_PENDING; |
985 default: | 990 default: |
986 // Data was read, process it. | 991 // Data was read, process it. |
987 // Schedule the work through the message loop to avoid recursive | 992 // Schedule the work through the message loop to avoid recursive |
988 // callbacks. | 993 // callbacks. |
989 read_pending_ = true; | 994 read_pending_ = true; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1036 // which is now. At this time, we don't compress our data frames. | 1041 // which is now. At this time, we don't compress our data frames. |
1037 SpdyFrame uncompressed_frame(next_buffer.buffer()->data(), false); | 1042 SpdyFrame uncompressed_frame(next_buffer.buffer()->data(), false); |
1038 size_t size; | 1043 size_t size; |
1039 if (buffered_spdy_framer_->IsCompressible(uncompressed_frame)) { | 1044 if (buffered_spdy_framer_->IsCompressible(uncompressed_frame)) { |
1040 DCHECK(uncompressed_frame.is_control_frame()); | 1045 DCHECK(uncompressed_frame.is_control_frame()); |
1041 scoped_ptr<SpdyFrame> compressed_frame( | 1046 scoped_ptr<SpdyFrame> compressed_frame( |
1042 buffered_spdy_framer_->CompressControlFrame( | 1047 buffered_spdy_framer_->CompressControlFrame( |
1043 reinterpret_cast<const SpdyControlFrame&>(uncompressed_frame))); | 1048 reinterpret_cast<const SpdyControlFrame&>(uncompressed_frame))); |
1044 if (!compressed_frame.get()) { | 1049 if (!compressed_frame.get()) { |
1045 CloseSessionOnError( | 1050 CloseSessionOnError( |
1046 net::ERR_SPDY_PROTOCOL_ERROR, true, "SPDY Compression failure."); | 1051 net::ERR_SPDY_PROTOCOL_ERROR, SPDY_COMPRESSION_FAILURE, true, |
| 1052 "SPDY Compression failure."); |
1047 return; | 1053 return; |
1048 } | 1054 } |
1049 | 1055 |
1050 size = compressed_frame->length() + SpdyFrame::kHeaderSize; | 1056 size = compressed_frame->length() + SpdyFrame::kHeaderSize; |
1051 | 1057 |
1052 DCHECK_GT(size, 0u); | 1058 DCHECK_GT(size, 0u); |
1053 | 1059 |
1054 // TODO(mbelshe): We have too much copying of data here. | 1060 // TODO(mbelshe): We have too much copying of data here. |
1055 IOBufferWithSize* buffer = new IOBufferWithSize(size); | 1061 IOBufferWithSize* buffer = new IOBufferWithSize(size); |
1056 memcpy(buffer->data(), compressed_frame->data(), size); | 1062 memcpy(buffer->data(), compressed_frame->data(), size); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1133 SpdyStream* stream) { | 1139 SpdyStream* stream) { |
1134 int length = SpdyFrame::kHeaderSize + frame->length(); | 1140 int length = SpdyFrame::kHeaderSize + frame->length(); |
1135 IOBuffer* buffer = new IOBuffer(length); | 1141 IOBuffer* buffer = new IOBuffer(length); |
1136 memcpy(buffer->data(), frame->data(), length); | 1142 memcpy(buffer->data(), frame->data(), length); |
1137 queue_.push(SpdyIOBuffer(buffer, length, priority, stream)); | 1143 queue_.push(SpdyIOBuffer(buffer, length, priority, stream)); |
1138 | 1144 |
1139 WriteSocketLater(); | 1145 WriteSocketLater(); |
1140 } | 1146 } |
1141 | 1147 |
1142 void SpdySession::CloseSessionOnError(net::Error err, | 1148 void SpdySession::CloseSessionOnError(net::Error err, |
| 1149 SpdySessionErrorDetails details, |
1143 bool remove_from_pool, | 1150 bool remove_from_pool, |
1144 const std::string& description) { | 1151 const std::string& description) { |
| 1152 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails", details, |
| 1153 NUM_SPDY_SESSION_ERROR_DETAILS); |
| 1154 if (EndsWith(host_port_pair().host(), "google.com", false)) { |
| 1155 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google", details, |
| 1156 NUM_SPDY_SESSION_ERROR_DETAILS); |
| 1157 } |
1145 // Closing all streams can have a side-effect of dropping the last reference | 1158 // Closing all streams can have a side-effect of dropping the last reference |
1146 // to |this|. Hold a reference through this function. | 1159 // to |this|. Hold a reference through this function. |
1147 scoped_refptr<SpdySession> self(this); | 1160 scoped_refptr<SpdySession> self(this); |
1148 | 1161 |
1149 DCHECK_LT(err, OK); | 1162 DCHECK_LT(err, OK); |
1150 net_log_.AddEvent( | 1163 net_log_.AddEvent( |
1151 NetLog::TYPE_SPDY_SESSION_CLOSE, | 1164 NetLog::TYPE_SPDY_SESSION_CLOSE, |
1152 make_scoped_refptr( | 1165 make_scoped_refptr( |
1153 new NetLogSpdySessionCloseParameter(err, description))); | 1166 new NetLogSpdySessionCloseParameter(err, description))); |
1154 | 1167 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1315 return NULL; | 1328 return NULL; |
1316 return GetSSLClientSocket()->GetServerBoundCertService(); | 1329 return GetSSLClientSocket()->GetServerBoundCertService(); |
1317 } | 1330 } |
1318 | 1331 |
1319 SSLClientCertType SpdySession::GetDomainBoundCertType() const { | 1332 SSLClientCertType SpdySession::GetDomainBoundCertType() const { |
1320 if (!is_secure_) | 1333 if (!is_secure_) |
1321 return CLIENT_CERT_INVALID_TYPE; | 1334 return CLIENT_CERT_INVALID_TYPE; |
1322 return GetSSLClientSocket()->domain_bound_cert_type(); | 1335 return GetSSLClientSocket()->domain_bound_cert_type(); |
1323 } | 1336 } |
1324 | 1337 |
1325 void SpdySession::OnError(int error_code) { | 1338 void SpdySession::OnError(SpdyFramer::SpdyError error_code) { |
1326 std::string description = base::StringPrintf( | 1339 std::string description = base::StringPrintf( |
1327 "SPDY_ERROR error_code: %d.", error_code); | 1340 "SPDY_ERROR error_code: %d.", error_code); |
1328 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true, description); | 1341 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, |
| 1342 static_cast<SpdySessionErrorDetails>(error_code), |
| 1343 true, description); |
1329 } | 1344 } |
1330 | 1345 |
1331 void SpdySession::OnStreamError(SpdyStreamId stream_id, | 1346 void SpdySession::OnStreamError(SpdyStreamId stream_id, |
1332 const std::string& description) { | 1347 const std::string& description) { |
1333 if (IsStreamActive(stream_id)) | 1348 if (IsStreamActive(stream_id)) |
1334 ResetStream(stream_id, PROTOCOL_ERROR, description); | 1349 ResetStream(stream_id, PROTOCOL_ERROR, description); |
1335 } | 1350 } |
1336 | 1351 |
1337 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, | 1352 void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, |
1338 const char* data, | 1353 const char* data, |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1614 | 1629 |
1615 // Send response to a PING from server. | 1630 // Send response to a PING from server. |
1616 if (frame.unique_id() % 2 == 0) { | 1631 if (frame.unique_id() % 2 == 0) { |
1617 WritePingFrame(frame.unique_id()); | 1632 WritePingFrame(frame.unique_id()); |
1618 return; | 1633 return; |
1619 } | 1634 } |
1620 | 1635 |
1621 --pings_in_flight_; | 1636 --pings_in_flight_; |
1622 if (pings_in_flight_ < 0) { | 1637 if (pings_in_flight_ < 0) { |
1623 CloseSessionOnError( | 1638 CloseSessionOnError( |
1624 net::ERR_SPDY_PROTOCOL_ERROR, true, "pings_in_flight_ is < 0."); | 1639 net::ERR_SPDY_PROTOCOL_ERROR, UNEXPECTED_PING, true, |
| 1640 "pings_in_flight_ is < 0."); |
1625 return; | 1641 return; |
1626 } | 1642 } |
1627 | 1643 |
1628 if (pings_in_flight_ > 0) | 1644 if (pings_in_flight_ > 0) |
1629 return; | 1645 return; |
1630 | 1646 |
1631 // We will record RTT in histogram when there are no more client sent | 1647 // We will record RTT in histogram when there are no more client sent |
1632 // pings_in_flight_. | 1648 // pings_in_flight_. |
1633 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_); | 1649 RecordPingRTTHistogram(base::TimeTicks::Now() - last_ping_sent_time_); |
1634 | 1650 |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1854 check_ping_status_pending_ = false; | 1870 check_ping_status_pending_ = false; |
1855 return; | 1871 return; |
1856 } | 1872 } |
1857 | 1873 |
1858 DCHECK(check_ping_status_pending_); | 1874 DCHECK(check_ping_status_pending_); |
1859 | 1875 |
1860 base::TimeTicks now = base::TimeTicks::Now(); | 1876 base::TimeTicks now = base::TimeTicks::Now(); |
1861 base::TimeDelta delay = hung_interval_ - (now - received_data_time_); | 1877 base::TimeDelta delay = hung_interval_ - (now - received_data_time_); |
1862 | 1878 |
1863 if (delay.InMilliseconds() < 0 || received_data_time_ < last_check_time) { | 1879 if (delay.InMilliseconds() < 0 || received_data_time_ < last_check_time) { |
1864 CloseSessionOnError(net::ERR_SPDY_PING_FAILED, true, "Failed ping."); | 1880 CloseSessionOnError(net::ERR_SPDY_PING_FAILED, PING_FAILED, true, |
| 1881 "Failed ping."); |
1865 // Track all failed PING messages in a separate bucket. | 1882 // Track all failed PING messages in a separate bucket. |
1866 const base::TimeDelta kFailedPing = | 1883 const base::TimeDelta kFailedPing = |
1867 base::TimeDelta::FromInternalValue(INT_MAX); | 1884 base::TimeDelta::FromInternalValue(INT_MAX); |
1868 RecordPingRTTHistogram(kFailedPing); | 1885 RecordPingRTTHistogram(kFailedPing); |
1869 return; | 1886 return; |
1870 } | 1887 } |
1871 | 1888 |
1872 // Check the status of connection after a delay. | 1889 // Check the status of connection after a delay. |
1873 MessageLoop::current()->PostDelayedTask( | 1890 MessageLoop::current()->PostDelayedTask( |
1874 FROM_HERE, | 1891 FROM_HERE, |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1968 SSLClientSocket* SpdySession::GetSSLClientSocket() const { | 1985 SSLClientSocket* SpdySession::GetSSLClientSocket() const { |
1969 if (!is_secure_) | 1986 if (!is_secure_) |
1970 return NULL; | 1987 return NULL; |
1971 SSLClientSocket* ssl_socket = | 1988 SSLClientSocket* ssl_socket = |
1972 reinterpret_cast<SSLClientSocket*>(connection_->socket()); | 1989 reinterpret_cast<SSLClientSocket*>(connection_->socket()); |
1973 DCHECK(ssl_socket); | 1990 DCHECK(ssl_socket); |
1974 return ssl_socket; | 1991 return ssl_socket; |
1975 } | 1992 } |
1976 | 1993 |
1977 } // namespace net | 1994 } // namespace net |
OLD | NEW |