OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/linked_ptr.h" | 8 #include "base/linked_ptr.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 connection_(new ClientSocketHandle), | 149 connection_(new ClientSocketHandle), |
150 read_buffer_(new IOBuffer(kReadBufferSize)), | 150 read_buffer_(new IOBuffer(kReadBufferSize)), |
151 read_pending_(false), | 151 read_pending_(false), |
152 stream_hi_water_mark_(1), // Always start at 1 for the first stream id. | 152 stream_hi_water_mark_(1), // Always start at 1 for the first stream id. |
153 write_pending_(false), | 153 write_pending_(false), |
154 delayed_write_pending_(false), | 154 delayed_write_pending_(false), |
155 is_secure_(false), | 155 is_secure_(false), |
156 certificate_error_code_(OK), | 156 certificate_error_code_(OK), |
157 error_(OK), | 157 error_(OK), |
158 state_(IDLE), | 158 state_(IDLE), |
| 159 max_concurrent_streams_(kDefaultMaxConcurrentStreams), |
159 streams_initiated_count_(0), | 160 streams_initiated_count_(0), |
160 streams_pushed_count_(0), | 161 streams_pushed_count_(0), |
161 streams_pushed_and_claimed_count_(0), | 162 streams_pushed_and_claimed_count_(0), |
162 streams_abandoned_count_(0), | 163 streams_abandoned_count_(0), |
163 sent_settings_(false), | 164 sent_settings_(false), |
164 received_settings_(false), | 165 received_settings_(false), |
165 in_session_pool_(true), | 166 in_session_pool_(true), |
166 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { | 167 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { |
167 net_log_.BeginEvent( | 168 net_log_.BeginEvent( |
168 NetLog::TYPE_SPDY_SESSION, | 169 NetLog::TYPE_SPDY_SESSION, |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 it->second = *stream; | 286 it->second = *stream; |
286 return OK; | 287 return OK; |
287 } | 288 } |
288 return OK; | 289 return OK; |
289 } | 290 } |
290 | 291 |
291 int SpdySession::CreateStream( | 292 int SpdySession::CreateStream( |
292 const GURL& url, | 293 const GURL& url, |
293 RequestPriority priority, | 294 RequestPriority priority, |
294 scoped_refptr<SpdyStream>* spdy_stream, | 295 scoped_refptr<SpdyStream>* spdy_stream, |
| 296 const BoundNetLog& stream_net_log, |
| 297 CompletionCallback* callback, |
| 298 const SpdyHttpStream* spdy_http_stream) { |
| 299 if (!max_concurrent_streams_ || |
| 300 active_streams_.size() < max_concurrent_streams_) { |
| 301 return CreateStreamImpl(url, priority, spdy_stream, stream_net_log); |
| 302 } |
| 303 |
| 304 create_stream_queues_[priority].push( |
| 305 PendingCreateStream(url, priority, spdy_stream, |
| 306 stream_net_log, callback, spdy_http_stream)); |
| 307 return ERR_IO_PENDING; |
| 308 } |
| 309 |
| 310 void SpdySession::ProcessPendingCreateStreams() { |
| 311 while (!max_concurrent_streams_ || |
| 312 active_streams_.size() < max_concurrent_streams_) { |
| 313 bool no_pending_create_streams = true; |
| 314 for (int i = 0;i < NUM_PRIORITIES;++i) { |
| 315 if (!create_stream_queues_[i].empty()) { |
| 316 PendingCreateStream& pending_create = create_stream_queues_[i].front(); |
| 317 no_pending_create_streams = false; |
| 318 int error = CreateStreamImpl(*pending_create.url, |
| 319 pending_create.priority, |
| 320 pending_create.spdy_stream, |
| 321 *pending_create.stream_net_log); |
| 322 pending_create.callback->Run(error); |
| 323 create_stream_queues_[i].pop(); |
| 324 break; |
| 325 } |
| 326 } |
| 327 if (no_pending_create_streams) |
| 328 return; // there were no streams in any queue |
| 329 } |
| 330 } |
| 331 |
| 332 void SpdySession::CancelPendingCreateStreams( |
| 333 const SpdyHttpStream *const spdy_http_stream) { |
| 334 for (int i = 0;i < NUM_PRIORITIES;++i) { |
| 335 PendingCreateStreamQueue tmp; |
| 336 // Make a copy removing this trans |
| 337 while (!create_stream_queues_[i].empty()) { |
| 338 PendingCreateStream& pending_create = create_stream_queues_[i].front(); |
| 339 if (pending_create.spdy_http_stream != spdy_http_stream) |
| 340 tmp.push(pending_create); |
| 341 create_stream_queues_[i].pop(); |
| 342 } |
| 343 // Now copy it back |
| 344 while (!tmp.empty()) { |
| 345 create_stream_queues_[i].push(tmp.front()); |
| 346 tmp.pop(); |
| 347 } |
| 348 } |
| 349 } |
| 350 |
| 351 int SpdySession::CreateStreamImpl( |
| 352 const GURL& url, |
| 353 RequestPriority priority, |
| 354 scoped_refptr<SpdyStream>* spdy_stream, |
295 const BoundNetLog& stream_net_log) { | 355 const BoundNetLog& stream_net_log) { |
296 // Make sure that we don't try to send https/wss over an unauthenticated, but | 356 // Make sure that we don't try to send https/wss over an unauthenticated, but |
297 // encrypted SSL socket. | 357 // encrypted SSL socket. |
298 if (is_secure_ && certificate_error_code_ != OK && | 358 if (is_secure_ && certificate_error_code_ != OK && |
299 (url.SchemeIs("https") || url.SchemeIs("wss"))) { | 359 (url.SchemeIs("https") || url.SchemeIs("wss"))) { |
300 LOG(DFATAL) << "Tried to create spdy stream for secure content over an " | 360 LOG(DFATAL) << "Tried to create spdy stream for secure content over an " |
301 << "unauthenticated session."; | 361 << "unauthenticated session."; |
302 return certificate_error_code_; | 362 return certificate_error_code_; |
303 } | 363 } |
304 | 364 |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 static StatsCounter abandoned_streams("spdy.abandoned_streams"); | 760 static StatsCounter abandoned_streams("spdy.abandoned_streams"); |
701 static StatsCounter abandoned_push_streams("spdy.abandoned_push_streams"); | 761 static StatsCounter abandoned_push_streams("spdy.abandoned_push_streams"); |
702 | 762 |
703 if (!active_streams_.empty()) | 763 if (!active_streams_.empty()) |
704 abandoned_streams.Add(active_streams_.size()); | 764 abandoned_streams.Add(active_streams_.size()); |
705 if (!pushed_streams_.empty()) { | 765 if (!pushed_streams_.empty()) { |
706 streams_abandoned_count_ += pushed_streams_.size(); | 766 streams_abandoned_count_ += pushed_streams_.size(); |
707 abandoned_push_streams.Add(pushed_streams_.size()); | 767 abandoned_push_streams.Add(pushed_streams_.size()); |
708 } | 768 } |
709 | 769 |
| 770 for (int i = 0;i < NUM_PRIORITIES;++i) { |
| 771 while (!create_stream_queues_[i].empty()) { |
| 772 PendingCreateStream& pending_create = create_stream_queues_[i].front(); |
| 773 pending_create.callback->Run(ERR_ABORTED); |
| 774 create_stream_queues_[i].pop(); |
| 775 } |
| 776 } |
| 777 |
710 while (!active_streams_.empty()) { | 778 while (!active_streams_.empty()) { |
711 ActiveStreamMap::iterator it = active_streams_.begin(); | 779 ActiveStreamMap::iterator it = active_streams_.begin(); |
712 const scoped_refptr<SpdyStream>& stream = it->second; | 780 const scoped_refptr<SpdyStream>& stream = it->second; |
713 DCHECK(stream); | 781 DCHECK(stream); |
714 LOG(ERROR) << "ABANDONED (stream_id=" << stream->stream_id() | 782 LOG(ERROR) << "ABANDONED (stream_id=" << stream->stream_id() |
715 << "): " << stream->path(); | 783 << "): " << stream->path(); |
716 DeleteStream(stream->stream_id(), status); | 784 DeleteStream(stream->stream_id(), status); |
717 } | 785 } |
718 | 786 |
719 // TODO(erikchen): ideally stream->OnClose() is only ever called by | 787 // TODO(erikchen): ideally stream->OnClose() is only ever called by |
720 // DeleteStream, but pending streams fall into their own category for now. | 788 // DeleteStream, but pending streams fall into their own category for now. |
721 PendingStreamMap::iterator it; | 789 PendingStreamMap::iterator it; |
722 for (it = pending_streams_.begin(); it != pending_streams_.end(); ++it) | 790 for (it = pending_streams_.begin(); it != pending_streams_.end(); ++it) { |
723 { | |
724 const scoped_refptr<SpdyStream>& stream = it->second; | 791 const scoped_refptr<SpdyStream>& stream = it->second; |
725 if (stream) | 792 if (stream) |
726 stream->OnClose(ERR_ABORTED); | 793 stream->OnClose(ERR_ABORTED); |
727 } | 794 } |
728 pending_streams_.clear(); | 795 pending_streams_.clear(); |
729 | 796 |
730 // We also need to drain the queue. | 797 // We also need to drain the queue. |
731 while (queue_.size()) | 798 while (queue_.size()) |
732 queue_.pop(); | 799 queue_.pop(); |
733 } | 800 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 // The stream might have been deleted. | 859 // The stream might have been deleted. |
793 ActiveStreamMap::iterator it2 = active_streams_.find(id); | 860 ActiveStreamMap::iterator it2 = active_streams_.find(id); |
794 if (it2 == active_streams_.end()) | 861 if (it2 == active_streams_.end()) |
795 return; | 862 return; |
796 | 863 |
797 // If this is an active stream, call the callback. | 864 // If this is an active stream, call the callback. |
798 const scoped_refptr<SpdyStream> stream(it2->second); | 865 const scoped_refptr<SpdyStream> stream(it2->second); |
799 active_streams_.erase(it2); | 866 active_streams_.erase(it2); |
800 if (stream) | 867 if (stream) |
801 stream->OnClose(status); | 868 stream->OnClose(status); |
| 869 ProcessPendingCreateStreams(); |
802 } | 870 } |
803 | 871 |
804 void SpdySession::RemoveFromPool() { | 872 void SpdySession::RemoveFromPool() { |
805 if (in_session_pool_) { | 873 if (in_session_pool_) { |
806 session_->spdy_session_pool()->Remove(this); | 874 session_->spdy_session_pool()->Remove(this); |
807 in_session_pool_ = false; | 875 in_session_pool_ = false; |
808 } | 876 } |
809 } | 877 } |
810 | 878 |
811 scoped_refptr<SpdyStream> SpdySession::GetActivePushStream( | 879 scoped_refptr<SpdyStream> SpdySession::GetActivePushStream( |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1111 // |last_accepted_stream_id|. | 1179 // |last_accepted_stream_id|. |
1112 | 1180 |
1113 // Don't bother killing any streams that are still reading. They'll either | 1181 // Don't bother killing any streams that are still reading. They'll either |
1114 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is | 1182 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is |
1115 // closed. | 1183 // closed. |
1116 } | 1184 } |
1117 | 1185 |
1118 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) { | 1186 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) { |
1119 spdy::SpdySettings settings; | 1187 spdy::SpdySettings settings; |
1120 if (spdy_framer_.ParseSettings(&frame, &settings)) { | 1188 if (spdy_framer_.ParseSettings(&frame, &settings)) { |
| 1189 HandleSettings(settings); |
1121 SpdySettingsStorage* settings_storage = session_->mutable_spdy_settings(); | 1190 SpdySettingsStorage* settings_storage = session_->mutable_spdy_settings(); |
1122 settings_storage->Set(host_port_pair_, settings); | 1191 settings_storage->Set(host_port_pair_, settings); |
1123 } | 1192 } |
1124 | 1193 |
1125 received_settings_ = true; | 1194 received_settings_ = true; |
1126 | 1195 |
1127 net_log_.AddEvent( | 1196 net_log_.AddEvent( |
1128 NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS, | 1197 NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS, |
1129 new NetLogSpdySettingsParameter(settings)); | 1198 new NetLogSpdySettingsParameter(settings)); |
1130 } | 1199 } |
1131 | 1200 |
1132 void SpdySession::SendSettings() { | 1201 void SpdySession::SendSettings() { |
1133 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); | 1202 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); |
1134 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); | 1203 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); |
1135 if (settings.empty()) | 1204 if (settings.empty()) |
1136 return; | 1205 return; |
| 1206 HandleSettings(settings); |
1137 | 1207 |
1138 net_log_.AddEvent( | 1208 net_log_.AddEvent( |
1139 NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS, | 1209 NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS, |
1140 new NetLogSpdySettingsParameter(settings)); | 1210 new NetLogSpdySettingsParameter(settings)); |
1141 | 1211 |
1142 // Create the SETTINGS frame and send it. | 1212 // Create the SETTINGS frame and send it. |
1143 scoped_ptr<spdy::SpdySettingsControlFrame> settings_frame( | 1213 scoped_ptr<spdy::SpdySettingsControlFrame> settings_frame( |
1144 spdy_framer_.CreateSettings(settings)); | 1214 spdy_framer_.CreateSettings(settings)); |
1145 sent_settings_ = true; | 1215 sent_settings_ = true; |
1146 QueueFrame(settings_frame.get(), 0, NULL); | 1216 QueueFrame(settings_frame.get(), 0, NULL); |
1147 } | 1217 } |
1148 | 1218 |
| 1219 void SpdySession::HandleSettings(const spdy::SpdySettings& settings) { |
| 1220 for (spdy::SpdySettings::const_iterator i = settings.begin(), |
| 1221 end = settings.end(); i != end; ++i) { |
| 1222 const uint32 id = i->first.id(); |
| 1223 const uint32 val = i->second; |
| 1224 switch (id) { |
| 1225 case spdy::SETTINGS_MAX_CONCURRENT_STREAMS: |
| 1226 max_concurrent_streams_ = val; |
| 1227 ProcessPendingCreateStreams(); |
| 1228 break; |
| 1229 } |
| 1230 } |
| 1231 } |
| 1232 |
1149 void SpdySession::RecordHistograms() { | 1233 void SpdySession::RecordHistograms() { |
1150 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", | 1234 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", |
1151 streams_initiated_count_, | 1235 streams_initiated_count_, |
1152 0, 300, 50); | 1236 0, 300, 50); |
1153 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", | 1237 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", |
1154 streams_pushed_count_, | 1238 streams_pushed_count_, |
1155 0, 300, 50); | 1239 0, 300, 50); |
1156 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession", | 1240 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession", |
1157 streams_pushed_and_claimed_count_, | 1241 streams_pushed_and_claimed_count_, |
1158 0, 300, 50); | 1242 0, 300, 50); |
1159 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession", | 1243 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession", |
1160 streams_abandoned_count_, | 1244 streams_abandoned_count_, |
1161 0, 300, 50); | 1245 0, 300, 50); |
1162 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent", | 1246 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent", |
1163 sent_settings_ ? 1 : 0, 2); | 1247 sent_settings_ ? 1 : 0, 2); |
1164 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived", | 1248 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived", |
1165 received_settings_ ? 1 : 0, 2); | 1249 received_settings_ ? 1 : 0, 2); |
1166 | 1250 |
1167 if (received_settings_) { | 1251 if (received_settings_) { |
1168 // Enumerate the saved settings, and set histograms for it. | 1252 // Enumerate the saved settings, and set histograms for it. |
1169 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); | 1253 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); |
1170 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); | 1254 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); |
1171 if (settings.empty()) { | |
1172 NOTREACHED(); // If we lost our settings already, something is wrong! | |
1173 return; | |
1174 } | |
1175 | 1255 |
1176 spdy::SpdySettings::const_iterator it; | 1256 spdy::SpdySettings::const_iterator it; |
1177 for (it = settings.begin(); it != settings.end(); ++it) { | 1257 for (it = settings.begin(); it != settings.end(); ++it) { |
1178 const spdy::SpdySetting setting = *it; | 1258 const spdy::SpdySetting setting = *it; |
1179 switch (setting.first.id()) { | 1259 switch (setting.first.id()) { |
1180 case spdy::SETTINGS_CURRENT_CWND: | 1260 case spdy::SETTINGS_CURRENT_CWND: |
1181 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", | 1261 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", |
1182 setting.second, | 1262 setting.second, |
1183 1, 200, 100); | 1263 1, 200, 100); |
1184 break; | 1264 break; |
1185 case spdy::SETTINGS_ROUND_TRIP_TIME: | 1265 case spdy::SETTINGS_ROUND_TRIP_TIME: |
1186 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", | 1266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", |
1187 setting.second, | 1267 setting.second, |
1188 1, 1200, 100); | 1268 1, 1200, 100); |
1189 break; | 1269 break; |
1190 case spdy::SETTINGS_DOWNLOAD_RETRANS_RATE: | 1270 case spdy::SETTINGS_DOWNLOAD_RETRANS_RATE: |
1191 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate", | 1271 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate", |
1192 setting.second, | 1272 setting.second, |
1193 1, 100, 50); | 1273 1, 100, 50); |
1194 break; | 1274 break; |
1195 } | 1275 } |
1196 } | 1276 } |
1197 } | 1277 } |
1198 } | 1278 } |
1199 | 1279 |
1200 } // namespace net | 1280 } // namespace net |
OLD | NEW |