| 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 |