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" |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 NetLog::LogLevel /* log_level */) { | 228 NetLog::LogLevel /* log_level */) { |
229 base::DictionaryValue* dict = new base::DictionaryValue(); | 229 base::DictionaryValue* dict = new base::DictionaryValue(); |
230 dict->SetInteger("last_accepted_stream_id", | 230 dict->SetInteger("last_accepted_stream_id", |
231 static_cast<int>(last_stream_id)); | 231 static_cast<int>(last_stream_id)); |
232 dict->SetInteger("active_streams", active_streams); | 232 dict->SetInteger("active_streams", active_streams); |
233 dict->SetInteger("unclaimed_streams", unclaimed_streams); | 233 dict->SetInteger("unclaimed_streams", unclaimed_streams); |
234 dict->SetInteger("status", static_cast<int>(status)); | 234 dict->SetInteger("status", static_cast<int>(status)); |
235 return dict; | 235 return dict; |
236 } | 236 } |
237 | 237 |
238 base::Value* NetLogSpdyPushPromiseReceivedCallback( | |
239 const SpdyHeaderBlock* headers, | |
240 SpdyStreamId stream_id, | |
241 SpdyStreamId promised_stream_id, | |
242 NetLog::LogLevel log_level) { | |
243 base::DictionaryValue* dict = new base::DictionaryValue(); | |
244 dict->Set("headers", | |
245 SpdyHeaderBlockToListValue(*headers, log_level).release()); | |
246 dict->SetInteger("id", stream_id); | |
247 dict->SetInteger("promised_stream_id", promised_stream_id); | |
248 return dict; | |
249 } | |
250 | |
238 // Helper function to return the total size of an array of objects | 251 // Helper function to return the total size of an array of objects |
239 // with .size() member functions. | 252 // with .size() member functions. |
240 template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) { | 253 template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) { |
241 size_t total_size = 0; | 254 size_t total_size = 0; |
242 for (size_t i = 0; i < N; ++i) { | 255 for (size_t i = 0; i < N; ++i) { |
243 total_size += arr[i].size(); | 256 total_size += arr[i].size(); |
244 } | 257 } |
245 return total_size; | 258 return total_size; |
246 } | 259 } |
247 | 260 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
494 net_log_ = BoundNetLog(); | 507 net_log_ = BoundNetLog(); |
495 callback_.Reset(); | 508 callback_.Reset(); |
496 } | 509 } |
497 | 510 |
498 SpdySession::ActiveStreamInfo::ActiveStreamInfo() | 511 SpdySession::ActiveStreamInfo::ActiveStreamInfo() |
499 : stream(NULL), | 512 : stream(NULL), |
500 waiting_for_syn_reply(false) {} | 513 waiting_for_syn_reply(false) {} |
501 | 514 |
502 SpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream) | 515 SpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream) |
503 : stream(stream), | 516 : stream(stream), |
504 waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {} | 517 waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM), |
518 reserved_remote(stream->type() == SPDY_PUSH_STREAM) { | |
519 } | |
505 | 520 |
506 SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {} | 521 SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {} |
507 | 522 |
508 SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {} | 523 SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {} |
509 | 524 |
510 SpdySession::PushedStreamInfo::PushedStreamInfo( | 525 SpdySession::PushedStreamInfo::PushedStreamInfo( |
511 SpdyStreamId stream_id, | 526 SpdyStreamId stream_id, |
512 base::TimeTicks creation_time) | 527 base::TimeTicks creation_time) |
513 : stream_id(stream_id), | 528 : stream_id(stream_id), |
514 creation_time(creation_time) {} | 529 creation_time(creation_time) {} |
(...skipping 13 matching lines...) Expand all Loading... | |
528 size_t max_concurrent_streams_limit, | 543 size_t max_concurrent_streams_limit, |
529 TimeFunc time_func, | 544 TimeFunc time_func, |
530 const HostPortPair& trusted_spdy_proxy, | 545 const HostPortPair& trusted_spdy_proxy, |
531 NetLog* net_log) | 546 NetLog* net_log) |
532 : in_io_loop_(false), | 547 : in_io_loop_(false), |
533 spdy_session_key_(spdy_session_key), | 548 spdy_session_key_(spdy_session_key), |
534 pool_(NULL), | 549 pool_(NULL), |
535 http_server_properties_(http_server_properties), | 550 http_server_properties_(http_server_properties), |
536 read_buffer_(new IOBuffer(kReadBufferSize)), | 551 read_buffer_(new IOBuffer(kReadBufferSize)), |
537 stream_hi_water_mark_(kFirstStreamId), | 552 stream_hi_water_mark_(kFirstStreamId), |
553 reserved_remote_stream_num_(0u), | |
538 in_flight_write_frame_type_(DATA), | 554 in_flight_write_frame_type_(DATA), |
539 in_flight_write_frame_size_(0), | 555 in_flight_write_frame_size_(0), |
540 is_secure_(false), | 556 is_secure_(false), |
541 certificate_error_code_(OK), | 557 certificate_error_code_(OK), |
542 availability_state_(STATE_AVAILABLE), | 558 availability_state_(STATE_AVAILABLE), |
543 read_state_(READ_STATE_DO_READ), | 559 read_state_(READ_STATE_DO_READ), |
544 write_state_(WRITE_STATE_IDLE), | 560 write_state_(WRITE_STATE_IDLE), |
545 error_on_close_(OK), | 561 error_on_close_(OK), |
546 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? | 562 max_concurrent_streams_(initial_max_concurrent_streams == 0 |
baranovich
2014/06/13 11:42:46
its not me, its git cl format=)
Johnny
2014/06/17 04:01:33
Yep, not a problem.
| |
547 kInitialMaxConcurrentStreams : | 563 ? kInitialMaxConcurrentStreams |
548 initial_max_concurrent_streams), | 564 : initial_max_concurrent_streams), |
549 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? | 565 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 |
550 kMaxConcurrentStreamLimit : | 566 ? kMaxConcurrentStreamLimit |
551 max_concurrent_streams_limit), | 567 : max_concurrent_streams_limit), |
552 streams_initiated_count_(0), | 568 streams_initiated_count_(0), |
553 streams_pushed_count_(0), | 569 streams_pushed_count_(0), |
554 streams_pushed_and_claimed_count_(0), | 570 streams_pushed_and_claimed_count_(0), |
555 streams_abandoned_count_(0), | 571 streams_abandoned_count_(0), |
556 total_bytes_received_(0), | 572 total_bytes_received_(0), |
557 sent_settings_(false), | 573 sent_settings_(false), |
558 received_settings_(false), | 574 received_settings_(false), |
559 stalled_streams_(0), | 575 stalled_streams_(0), |
560 pings_in_flight_(0), | 576 pings_in_flight_(0), |
561 next_ping_id_(1), | 577 next_ping_id_(1), |
562 last_activity_time_(time_func()), | 578 last_activity_time_(time_func()), |
563 last_compressed_frame_len_(0), | 579 last_compressed_frame_len_(0), |
564 check_ping_status_pending_(false), | 580 check_ping_status_pending_(false), |
565 send_connection_header_prefix_(false), | 581 send_connection_header_prefix_(false), |
566 flow_control_state_(FLOW_CONTROL_NONE), | 582 flow_control_state_(FLOW_CONTROL_NONE), |
567 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), | 583 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), |
568 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? | 584 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 |
569 kDefaultInitialRecvWindowSize : | 585 ? kDefaultInitialRecvWindowSize |
570 stream_initial_recv_window_size), | 586 : stream_initial_recv_window_size), |
571 session_send_window_size_(0), | 587 session_send_window_size_(0), |
572 session_recv_window_size_(0), | 588 session_recv_window_size_(0), |
573 session_unacked_recv_window_bytes_(0), | 589 session_unacked_recv_window_bytes_(0), |
574 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)), | 590 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)), |
575 verify_domain_authentication_(verify_domain_authentication), | 591 verify_domain_authentication_(verify_domain_authentication), |
576 enable_sending_initial_data_(enable_sending_initial_data), | 592 enable_sending_initial_data_(enable_sending_initial_data), |
577 enable_compression_(enable_compression), | 593 enable_compression_(enable_compression), |
578 enable_ping_based_connection_checking_( | 594 enable_ping_based_connection_checking_( |
579 enable_ping_based_connection_checking), | 595 enable_ping_based_connection_checking), |
580 protocol_(default_protocol), | 596 protocol_(default_protocol), |
581 connection_at_risk_of_loss_time_( | 597 connection_at_risk_of_loss_time_( |
582 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), | 598 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), |
583 hung_interval_( | 599 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), |
584 base::TimeDelta::FromSeconds(kHungIntervalSeconds)), | |
585 trusted_spdy_proxy_(trusted_spdy_proxy), | 600 trusted_spdy_proxy_(trusted_spdy_proxy), |
586 time_func_(time_func), | 601 time_func_(time_func), |
587 weak_factory_(this) { | 602 weak_factory_(this) { |
588 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); | 603 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); |
589 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); | 604 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); |
590 DCHECK(HttpStreamFactory::spdy_enabled()); | 605 DCHECK(HttpStreamFactory::spdy_enabled()); |
591 net_log_.BeginEvent( | 606 net_log_.BeginEvent( |
592 NetLog::TYPE_SPDY_SESSION, | 607 NetLog::TYPE_SPDY_SESSION, |
593 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); | 608 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); |
594 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 609 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
757 return ERR_FAILED; | 772 return ERR_FAILED; |
758 | 773 |
759 if (availability_state_ == STATE_DRAINING) | 774 if (availability_state_ == STATE_DRAINING) |
760 return ERR_CONNECTION_CLOSED; | 775 return ERR_CONNECTION_CLOSED; |
761 | 776 |
762 Error err = TryAccessStream(request->url()); | 777 Error err = TryAccessStream(request->url()); |
763 if (err != OK) | 778 if (err != OK) |
764 return err; | 779 return err; |
765 | 780 |
766 if (!max_concurrent_streams_ || | 781 if (!max_concurrent_streams_ || |
767 (active_streams_.size() + created_streams_.size() < | 782 (active_streams_.size() + created_streams_.size() - |
783 reserved_remote_stream_num_ < | |
baranovich
2014/06/13 11:42:46
This behavior should be tested. But it is incorrec
Johnny
2014/06/17 04:01:33
Agreed with your assessment. The current behavior
baranovich
2014/06/17 21:33:43
Done. Left this code intact
| |
768 max_concurrent_streams_)) { | 784 max_concurrent_streams_)) { |
769 return CreateStream(*request, stream); | 785 return CreateStream(*request, stream); |
770 } | 786 } |
771 | 787 |
772 stalled_streams_++; | 788 stalled_streams_++; |
773 net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS); | 789 net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS); |
774 RequestPriority priority = request->priority(); | 790 RequestPriority priority = request->priority(); |
775 CHECK_GE(priority, MINIMUM_PRIORITY); | 791 CHECK_GE(priority, MINIMUM_PRIORITY); |
776 CHECK_LE(priority, MAXIMUM_PRIORITY); | 792 CHECK_LE(priority, MAXIMUM_PRIORITY); |
777 pending_create_stream_queues_[priority].push_back(request); | 793 pending_create_stream_queues_[priority].push_back(request); |
(...skipping 1299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2077 } | 2093 } |
2078 | 2094 |
2079 void SpdySession::OnSynStream(SpdyStreamId stream_id, | 2095 void SpdySession::OnSynStream(SpdyStreamId stream_id, |
2080 SpdyStreamId associated_stream_id, | 2096 SpdyStreamId associated_stream_id, |
2081 SpdyPriority priority, | 2097 SpdyPriority priority, |
2082 bool fin, | 2098 bool fin, |
2083 bool unidirectional, | 2099 bool unidirectional, |
2084 const SpdyHeaderBlock& headers) { | 2100 const SpdyHeaderBlock& headers) { |
2085 CHECK(in_io_loop_); | 2101 CHECK(in_io_loop_); |
2086 | 2102 |
2103 if (GetProtocolVersion() >= SPDY4) { | |
2104 DCHECK_EQ(0u, associated_stream_id); | |
2105 OnHeaders(stream_id, fin, headers); | |
2106 return; | |
2107 } | |
2108 | |
2087 base::Time response_time = base::Time::Now(); | 2109 base::Time response_time = base::Time::Now(); |
2088 base::TimeTicks recv_first_byte_time = time_func_(); | 2110 base::TimeTicks recv_first_byte_time = time_func_(); |
2089 | 2111 |
2090 if (net_log_.IsLogging()) { | 2112 if (net_log_.IsLogging()) { |
2091 net_log_.AddEvent( | 2113 net_log_.AddEvent( |
2092 NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM, | 2114 NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM, |
2093 base::Bind(&NetLogSpdySynStreamReceivedCallback, | 2115 base::Bind(&NetLogSpdySynStreamReceivedCallback, |
2094 &headers, fin, unidirectional, priority, | 2116 &headers, fin, unidirectional, priority, |
2095 stream_id, associated_stream_id)); | 2117 stream_id, associated_stream_id)); |
2096 } | 2118 } |
2097 | 2119 |
2098 // Server-initiated streams should have even sequence numbers. | 2120 if (!TryCreatePushStream(stream_id, associated_stream_id, priority, headers)) |
2099 if ((stream_id & 0x1) != 0) { | |
2100 LOG(WARNING) << "Received invalid OnSyn stream id " << stream_id; | |
2101 return; | 2121 return; |
2102 } | |
2103 | |
2104 if (IsStreamActive(stream_id)) { | |
2105 LOG(WARNING) << "Received OnSyn for active stream " << stream_id; | |
2106 return; | |
2107 } | |
2108 | |
2109 RequestPriority request_priority = | |
2110 ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion()); | |
2111 | |
2112 if (availability_state_ == STATE_GOING_AWAY) { | |
2113 // TODO(akalin): This behavior isn't in the SPDY spec, although it | |
2114 // probably should be. | |
2115 EnqueueResetStreamFrame(stream_id, request_priority, | |
2116 RST_STREAM_REFUSED_STREAM, | |
2117 "OnSyn received when going away"); | |
2118 return; | |
2119 } | |
2120 | |
2121 // TODO(jgraettinger): SpdyFramer simulates OnSynStream() from HEADERS | |
2122 // frames, which don't convey associated stream ID. Disable this check | |
2123 // for now, and re-enable when PUSH_PROMISE is implemented properly. | |
2124 if (associated_stream_id == 0 && GetProtocolVersion() < SPDY4) { | |
2125 std::string description = base::StringPrintf( | |
2126 "Received invalid OnSyn associated stream id %d for stream %d", | |
2127 associated_stream_id, stream_id); | |
2128 EnqueueResetStreamFrame(stream_id, request_priority, | |
2129 RST_STREAM_REFUSED_STREAM, description); | |
2130 return; | |
2131 } | |
2132 | |
2133 streams_pushed_count_++; | |
2134 | |
2135 // TODO(mbelshe): DCHECK that this is a GET method? | |
2136 | |
2137 // Verify that the response had a URL for us. | |
2138 GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true); | |
2139 if (!gurl.is_valid()) { | |
2140 EnqueueResetStreamFrame( | |
2141 stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR, | |
2142 "Pushed stream url was invalid: " + gurl.spec()); | |
2143 return; | |
2144 } | |
2145 | |
2146 // Verify we have a valid stream association. | |
2147 ActiveStreamMap::iterator associated_it = | |
2148 active_streams_.find(associated_stream_id); | |
2149 // TODO(jgraettinger): (See PUSH_PROMISE comment above). | |
2150 if (GetProtocolVersion() < SPDY4 && associated_it == active_streams_.end()) { | |
2151 EnqueueResetStreamFrame( | |
2152 stream_id, request_priority, RST_STREAM_INVALID_STREAM, | |
2153 base::StringPrintf( | |
2154 "Received OnSyn with inactive associated stream %d", | |
2155 associated_stream_id)); | |
2156 return; | |
2157 } | |
2158 | |
2159 // Check that the SYN advertises the same origin as its associated stream. | |
2160 // Bypass this check if and only if this session is with a SPDY proxy that | |
2161 // is trusted explicitly via the --trusted-spdy-proxy switch. | |
2162 if (trusted_spdy_proxy_.Equals(host_port_pair())) { | |
2163 // Disallow pushing of HTTPS content. | |
2164 if (gurl.SchemeIs("https")) { | |
2165 EnqueueResetStreamFrame( | |
2166 stream_id, request_priority, RST_STREAM_REFUSED_STREAM, | |
2167 base::StringPrintf( | |
2168 "Rejected push of Cross Origin HTTPS content %d", | |
2169 associated_stream_id)); | |
2170 } | |
2171 } else if (GetProtocolVersion() < SPDY4) { | |
2172 // TODO(jgraettinger): (See PUSH_PROMISE comment above). | |
2173 GURL associated_url(associated_it->second.stream->GetUrlFromHeaders()); | |
2174 if (associated_url.GetOrigin() != gurl.GetOrigin()) { | |
2175 EnqueueResetStreamFrame( | |
2176 stream_id, request_priority, RST_STREAM_REFUSED_STREAM, | |
2177 base::StringPrintf( | |
2178 "Rejected Cross Origin Push Stream %d", | |
2179 associated_stream_id)); | |
2180 return; | |
2181 } | |
2182 } | |
2183 | |
2184 // There should not be an existing pushed stream with the same path. | |
2185 PushedStreamMap::iterator pushed_it = | |
2186 unclaimed_pushed_streams_.lower_bound(gurl); | |
2187 if (pushed_it != unclaimed_pushed_streams_.end() && | |
2188 pushed_it->first == gurl) { | |
2189 EnqueueResetStreamFrame( | |
2190 stream_id, request_priority, RST_STREAM_PROTOCOL_ERROR, | |
2191 "Received duplicate pushed stream with url: " + | |
2192 gurl.spec()); | |
2193 return; | |
2194 } | |
2195 | |
2196 scoped_ptr<SpdyStream> stream( | |
2197 new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl, | |
2198 request_priority, | |
2199 stream_initial_send_window_size_, | |
2200 stream_initial_recv_window_size_, | |
2201 net_log_)); | |
2202 stream->set_stream_id(stream_id); | |
2203 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); | |
2204 last_compressed_frame_len_ = 0; | |
2205 | |
2206 DeleteExpiredPushedStreams(); | |
2207 PushedStreamMap::iterator inserted_pushed_it = | |
2208 unclaimed_pushed_streams_.insert( | |
2209 pushed_it, | |
2210 std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_()))); | |
2211 DCHECK(inserted_pushed_it != pushed_it); | |
2212 | |
2213 InsertActivatedStream(stream.Pass()); | |
2214 | 2122 |
2215 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); | 2123 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); |
2216 if (active_it == active_streams_.end()) { | 2124 if (active_it == active_streams_.end()) { |
2217 NOTREACHED(); | 2125 NOTREACHED(); |
2218 return; | 2126 return; |
2219 } | 2127 } |
2220 | 2128 |
2221 // Parse the headers. | 2129 // Parse the headers. |
2222 | 2130 |
2223 // Split headers to simulate push promise and response. | 2131 // Split headers to simulate push promise and response. |
2224 SpdyHeaderBlock request_headers; | 2132 SpdyHeaderBlock request_headers; |
2225 SpdyHeaderBlock response_headers; | 2133 SpdyHeaderBlock response_headers; |
2226 SplitPushedHeadersToRequestAndResponse( | 2134 SplitPushedHeadersToRequestAndResponse( |
2227 headers, GetProtocolVersion(), &request_headers, &response_headers); | 2135 headers, GetProtocolVersion(), &request_headers, &response_headers); |
2228 | 2136 |
2229 if (active_it->second.stream->OnPushPromiseHeadersReceived(request_headers) != | 2137 if (active_it->second.stream->OnPushPromiseHeadersReceived(request_headers) != |
Johnny
2014/06/17 04:01:33
It seems like TryCreatePushStream() should receive
baranovich
2014/06/17 21:33:43
Done.
| |
2230 OK) | 2138 OK) |
2231 return; | 2139 return; |
2232 | 2140 |
2141 DCHECK(active_it->second.reserved_remote); | |
2142 ActivateReservedStreamIterator(active_it); | |
2143 | |
2233 if (OnInitialResponseHeadersReceived(response_headers, | 2144 if (OnInitialResponseHeadersReceived(response_headers, |
2234 response_time, | 2145 response_time, |
2235 recv_first_byte_time, | 2146 recv_first_byte_time, |
2236 active_it->second.stream) != OK) | 2147 active_it->second.stream) != OK) |
2237 return; | 2148 return; |
2238 | 2149 |
2239 base::StatsCounter push_requests("spdy.pushed_streams"); | 2150 base::StatsCounter push_requests("spdy.pushed_streams"); |
2240 push_requests.Increment(); | 2151 push_requests.Increment(); |
2241 } | 2152 } |
2242 | 2153 |
2154 void SpdySession::ActivateReservedStreamIterator(ActiveStreamMap::iterator it) { | |
2155 DCHECK_GT(reserved_remote_stream_num_, 0u); | |
Johnny
2014/06/17 04:01:33
I'm thinking this ought to be folded into OnRespon
baranovich
2014/06/17 21:33:43
Done. This method in not necessary unless we have
| |
2156 DCHECK_LE(reserved_remote_stream_num_, active_streams_.size()); | |
2157 reserved_remote_stream_num_--; | |
2158 it->second.reserved_remote = false; | |
2159 } | |
2160 | |
2243 void SpdySession::DeleteExpiredPushedStreams() { | 2161 void SpdySession::DeleteExpiredPushedStreams() { |
2244 if (unclaimed_pushed_streams_.empty()) | 2162 if (unclaimed_pushed_streams_.empty()) |
2245 return; | 2163 return; |
2246 | 2164 |
2247 // Check that adequate time has elapsed since the last sweep. | 2165 // Check that adequate time has elapsed since the last sweep. |
2248 if (time_func_() < next_unclaimed_push_stream_sweep_time_) | 2166 if (time_func_() < next_unclaimed_push_stream_sweep_time_) |
2249 return; | 2167 return; |
2250 | 2168 |
2251 // Gather old streams to delete. | 2169 // Gather old streams to delete. |
2252 base::TimeTicks minimum_freshness = time_func_() - | 2170 base::TimeTicks minimum_freshness = time_func_() - |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2341 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; | 2259 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; |
2342 return; | 2260 return; |
2343 } | 2261 } |
2344 | 2262 |
2345 SpdyStream* stream = it->second.stream; | 2263 SpdyStream* stream = it->second.stream; |
2346 CHECK_EQ(stream->stream_id(), stream_id); | 2264 CHECK_EQ(stream->stream_id(), stream_id); |
2347 | 2265 |
2348 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); | 2266 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); |
2349 last_compressed_frame_len_ = 0; | 2267 last_compressed_frame_len_ = 0; |
2350 | 2268 |
2269 base::Time response_time = base::Time::Now(); | |
2270 base::TimeTicks recv_first_byte_time = time_func_(); | |
2271 | |
2351 if (it->second.waiting_for_syn_reply) { | 2272 if (it->second.waiting_for_syn_reply) { |
2352 if (GetProtocolVersion() < SPDY4) { | 2273 if (GetProtocolVersion() < SPDY4) { |
2353 const std::string& error = | 2274 const std::string& error = |
2354 "Was expecting SYN_REPLY, not HEADERS."; | 2275 "Was expecting SYN_REPLY, not HEADERS."; |
2355 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 2276 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
2356 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error); | 2277 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error); |
2357 return; | 2278 return; |
2358 } | 2279 } |
2359 base::Time response_time = base::Time::Now(); | |
2360 base::TimeTicks recv_first_byte_time = time_func_(); | |
2361 | 2280 |
2362 it->second.waiting_for_syn_reply = false; | 2281 it->second.waiting_for_syn_reply = false; |
2363 ignore_result(OnInitialResponseHeadersReceived( | 2282 ignore_result(OnInitialResponseHeadersReceived( |
2364 headers, response_time, recv_first_byte_time, stream)); | 2283 headers, response_time, recv_first_byte_time, stream)); |
2284 } else if (it->second.reserved_remote) { | |
2285 ActivateReservedStreamIterator(it); | |
2286 ignore_result(OnInitialResponseHeadersReceived( | |
2287 headers, response_time, recv_first_byte_time, stream)); | |
2365 } else { | 2288 } else { |
2366 int rv = stream->OnAdditionalResponseHeadersReceived(headers); | 2289 int rv = stream->OnAdditionalResponseHeadersReceived(headers); |
2367 if (rv < 0) { | 2290 if (rv < 0) { |
2368 DCHECK_NE(rv, ERR_IO_PENDING); | 2291 DCHECK_NE(rv, ERR_IO_PENDING); |
2369 DCHECK(active_streams_.find(stream_id) == active_streams_.end()); | 2292 DCHECK(active_streams_.find(stream_id) == active_streams_.end()); |
2370 } | 2293 } |
2371 } | 2294 } |
2372 } | 2295 } |
2373 | 2296 |
2374 void SpdySession::OnRstStream(SpdyStreamId stream_id, | 2297 void SpdySession::OnRstStream(SpdyStreamId stream_id, |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2514 "delta_window_size %ud", delta_window_size)); | 2437 "delta_window_size %ud", delta_window_size)); |
2515 return; | 2438 return; |
2516 } | 2439 } |
2517 | 2440 |
2518 CHECK_EQ(it->second.stream->stream_id(), stream_id); | 2441 CHECK_EQ(it->second.stream->stream_id(), stream_id); |
2519 it->second.stream->IncreaseSendWindowSize( | 2442 it->second.stream->IncreaseSendWindowSize( |
2520 static_cast<int32>(delta_window_size)); | 2443 static_cast<int32>(delta_window_size)); |
2521 } | 2444 } |
2522 } | 2445 } |
2523 | 2446 |
2447 bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id, | |
2448 SpdyStreamId associated_stream_id, | |
2449 SpdyPriority priority, | |
2450 const SpdyHeaderBlock& headers) { | |
2451 // Server-initiated streams should have even sequence numbers. | |
2452 if ((stream_id & 0x1) != 0) { | |
2453 LOG(WARNING) << "Received invalid push stream id " << stream_id; | |
2454 return false; | |
2455 } | |
2456 | |
2457 if (IsStreamActive(stream_id)) { | |
2458 LOG(WARNING) << "Received push for active stream " << stream_id; | |
2459 return false; | |
2460 } | |
2461 | |
2462 RequestPriority request_priority = | |
2463 ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion()); | |
2464 | |
2465 if (availability_state_ == STATE_GOING_AWAY) { | |
2466 // TODO(akalin): This behavior isn't in the SPDY spec, although it | |
2467 // probably should be. | |
2468 EnqueueResetStreamFrame(stream_id, | |
2469 request_priority, | |
2470 RST_STREAM_REFUSED_STREAM, | |
2471 "push stream request received when going away"); | |
2472 return false; | |
2473 } | |
2474 | |
2475 if (associated_stream_id == 0) { | |
2476 // In SPDY4 0 stream id in PUSH_PROMISE frame leads to framer error and | |
2477 // session going away. We should never get here. | |
2478 CHECK_GT(SPDY4, GetProtocolVersion()); | |
2479 std::string description = base::StringPrintf( | |
2480 "Received invalid associated stream id %d for pushed stream %d", | |
2481 associated_stream_id, | |
2482 stream_id); | |
2483 EnqueueResetStreamFrame( | |
2484 stream_id, request_priority, RST_STREAM_REFUSED_STREAM, description); | |
2485 return false; | |
2486 } | |
2487 | |
2488 streams_pushed_count_++; | |
2489 | |
2490 // TODO(mbelshe): DCHECK that this is a GET method? | |
2491 | |
2492 // Verify that the response had a URL for us. | |
2493 GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true); | |
2494 if (!gurl.is_valid()) { | |
2495 EnqueueResetStreamFrame(stream_id, | |
2496 request_priority, | |
2497 RST_STREAM_PROTOCOL_ERROR, | |
2498 "Pushed stream url was invalid: " + gurl.spec()); | |
2499 return false; | |
2500 } | |
2501 | |
2502 // Verify we have a valid stream association. | |
2503 ActiveStreamMap::iterator associated_it = | |
2504 active_streams_.find(associated_stream_id); | |
2505 if (associated_it == active_streams_.end()) { | |
2506 EnqueueResetStreamFrame( | |
2507 stream_id, | |
2508 request_priority, | |
2509 RST_STREAM_INVALID_STREAM, | |
2510 base::StringPrintf("Received push for inactive associated stream %d", | |
2511 associated_stream_id)); | |
2512 return false; | |
2513 } | |
2514 | |
2515 // Check that the pushed stream advertises the same origin as its associated | |
2516 // stream. Bypass this check if and only if this session is with a SPDY proxy | |
2517 // that is trusted explicitly via the --trusted-spdy-proxy switch. | |
2518 if (trusted_spdy_proxy_.Equals(host_port_pair())) { | |
2519 // Disallow pushing of HTTPS content. | |
2520 if (gurl.SchemeIs("https")) { | |
2521 EnqueueResetStreamFrame( | |
2522 stream_id, | |
2523 request_priority, | |
2524 RST_STREAM_REFUSED_STREAM, | |
2525 base::StringPrintf("Rejected push of Cross Origin HTTPS content %d", | |
2526 associated_stream_id)); | |
2527 } | |
2528 } else { | |
2529 GURL associated_url(associated_it->second.stream->GetUrlFromHeaders()); | |
2530 if (associated_url.GetOrigin() != gurl.GetOrigin()) { | |
2531 EnqueueResetStreamFrame( | |
2532 stream_id, | |
2533 request_priority, | |
2534 RST_STREAM_REFUSED_STREAM, | |
2535 base::StringPrintf("Rejected Cross Origin Push Stream %d", | |
2536 associated_stream_id)); | |
2537 return false; | |
2538 } | |
2539 } | |
2540 | |
2541 // There should not be an existing pushed stream with the same path. | |
2542 PushedStreamMap::iterator pushed_it = | |
2543 unclaimed_pushed_streams_.lower_bound(gurl); | |
2544 if (pushed_it != unclaimed_pushed_streams_.end() && | |
2545 pushed_it->first == gurl) { | |
2546 EnqueueResetStreamFrame( | |
2547 stream_id, | |
2548 request_priority, | |
2549 RST_STREAM_PROTOCOL_ERROR, | |
2550 "Received duplicate pushed stream with url: " + gurl.spec()); | |
2551 return false; | |
2552 } | |
2553 | |
2554 scoped_ptr<SpdyStream> stream(new SpdyStream(SPDY_PUSH_STREAM, | |
2555 GetWeakPtr(), | |
2556 gurl, | |
2557 request_priority, | |
2558 stream_initial_send_window_size_, | |
2559 stream_initial_recv_window_size_, | |
2560 net_log_)); | |
2561 stream->set_stream_id(stream_id); | |
2562 | |
2563 // In spdy4/http2 PUSH_PROMISE arrives on associated stream. | |
2564 if (associated_it != active_streams_.end() && GetProtocolVersion() >= SPDY4) { | |
2565 associated_it->second.stream->IncrementRawReceivedBytes( | |
2566 last_compressed_frame_len_); | |
2567 } else { | |
2568 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); | |
2569 } | |
2570 | |
2571 last_compressed_frame_len_ = 0; | |
2572 | |
2573 DeleteExpiredPushedStreams(); | |
2574 PushedStreamMap::iterator inserted_pushed_it = | |
2575 unclaimed_pushed_streams_.insert( | |
2576 pushed_it, | |
2577 std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_()))); | |
2578 DCHECK(inserted_pushed_it != pushed_it); | |
2579 | |
2580 InsertActivatedStream(stream.Pass()); | |
2581 | |
2582 reserved_remote_stream_num_++; | |
2583 DCHECK_GT(reserved_remote_stream_num_, 0u); | |
2584 DCHECK_LE(reserved_remote_stream_num_, active_streams_.size()); | |
2585 | |
2586 return true; | |
2587 } | |
2588 | |
2524 void SpdySession::OnPushPromise(SpdyStreamId stream_id, | 2589 void SpdySession::OnPushPromise(SpdyStreamId stream_id, |
2525 SpdyStreamId promised_stream_id, | 2590 SpdyStreamId promised_stream_id, |
2526 const SpdyHeaderBlock& headers) { | 2591 const SpdyHeaderBlock& headers) { |
2527 // TODO(akalin): Handle PUSH_PROMISE frames. | 2592 CHECK(in_io_loop_); |
2593 | |
2594 if (net_log_.IsLogging()) { | |
2595 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_PUSH_PROMISE, | |
2596 base::Bind(&NetLogSpdyPushPromiseReceivedCallback, | |
2597 &headers, | |
2598 stream_id, | |
2599 promised_stream_id)); | |
2600 } | |
2601 | |
2602 // Any priority will do. | |
2603 // TODO(baranovich): pass parent stream id priority? | |
2604 if (!TryCreatePushStream(promised_stream_id, stream_id, 0, headers)) | |
2605 return; | |
2606 | |
2607 ActiveStreamMap::iterator active_it = | |
2608 active_streams_.find(promised_stream_id); | |
2609 if (active_it == active_streams_.end()) { | |
2610 NOTREACHED(); | |
2611 return; | |
2612 } | |
2613 DCHECK(active_it->second.reserved_remote); | |
2614 | |
2615 // Parse the headers. | |
2616 if (active_it->second.stream->OnPushPromiseHeadersReceived(headers) != OK) | |
2617 return; | |
2618 | |
2619 base::StatsCounter push_requests("spdy.pushed_streams"); | |
2620 push_requests.Increment(); | |
2528 } | 2621 } |
2529 | 2622 |
2530 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, | 2623 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, |
2531 uint32 delta_window_size) { | 2624 uint32 delta_window_size) { |
2532 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); | 2625 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); |
2533 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); | 2626 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
2534 CHECK(it != active_streams_.end()); | 2627 CHECK(it != active_streams_.end()); |
2535 CHECK_EQ(it->second.stream->stream_id(), stream_id); | 2628 CHECK_EQ(it->second.stream->stream_id(), stream_id); |
2536 SendWindowUpdateFrame( | 2629 SendWindowUpdateFrame( |
2537 stream_id, delta_window_size, it->second.stream->priority()); | 2630 stream_id, delta_window_size, it->second.stream->priority()); |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3051 if (!queue->empty()) { | 3144 if (!queue->empty()) { |
3052 SpdyStreamId stream_id = queue->front(); | 3145 SpdyStreamId stream_id = queue->front(); |
3053 queue->pop_front(); | 3146 queue->pop_front(); |
3054 return stream_id; | 3147 return stream_id; |
3055 } | 3148 } |
3056 } | 3149 } |
3057 return 0; | 3150 return 0; |
3058 } | 3151 } |
3059 | 3152 |
3060 } // namespace net | 3153 } // namespace net |
OLD | NEW |