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" |
| (...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 |