| 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 } |
| 505 | 519 |
| 506 SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {} | 520 SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {} |
| 507 | 521 |
| 508 SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {} | 522 SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {} |
| 509 | 523 |
| 510 SpdySession::PushedStreamInfo::PushedStreamInfo( | 524 SpdySession::PushedStreamInfo::PushedStreamInfo( |
| 511 SpdyStreamId stream_id, | 525 SpdyStreamId stream_id, |
| 512 base::TimeTicks creation_time) | 526 base::TimeTicks creation_time) |
| 513 : stream_id(stream_id), | 527 : stream_id(stream_id), |
| 514 creation_time(creation_time) {} | 528 creation_time(creation_time) {} |
| (...skipping 21 matching lines...) Expand all Loading... |
| 536 read_buffer_(new IOBuffer(kReadBufferSize)), | 550 read_buffer_(new IOBuffer(kReadBufferSize)), |
| 537 stream_hi_water_mark_(kFirstStreamId), | 551 stream_hi_water_mark_(kFirstStreamId), |
| 538 in_flight_write_frame_type_(DATA), | 552 in_flight_write_frame_type_(DATA), |
| 539 in_flight_write_frame_size_(0), | 553 in_flight_write_frame_size_(0), |
| 540 is_secure_(false), | 554 is_secure_(false), |
| 541 certificate_error_code_(OK), | 555 certificate_error_code_(OK), |
| 542 availability_state_(STATE_AVAILABLE), | 556 availability_state_(STATE_AVAILABLE), |
| 543 read_state_(READ_STATE_DO_READ), | 557 read_state_(READ_STATE_DO_READ), |
| 544 write_state_(WRITE_STATE_IDLE), | 558 write_state_(WRITE_STATE_IDLE), |
| 545 error_on_close_(OK), | 559 error_on_close_(OK), |
| 546 max_concurrent_streams_(initial_max_concurrent_streams == 0 ? | 560 max_concurrent_streams_(initial_max_concurrent_streams == 0 |
| 547 kInitialMaxConcurrentStreams : | 561 ? kInitialMaxConcurrentStreams |
| 548 initial_max_concurrent_streams), | 562 : initial_max_concurrent_streams), |
| 549 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 ? | 563 max_concurrent_streams_limit_(max_concurrent_streams_limit == 0 |
| 550 kMaxConcurrentStreamLimit : | 564 ? kMaxConcurrentStreamLimit |
| 551 max_concurrent_streams_limit), | 565 : max_concurrent_streams_limit), |
| 552 streams_initiated_count_(0), | 566 streams_initiated_count_(0), |
| 553 streams_pushed_count_(0), | 567 streams_pushed_count_(0), |
| 554 streams_pushed_and_claimed_count_(0), | 568 streams_pushed_and_claimed_count_(0), |
| 555 streams_abandoned_count_(0), | 569 streams_abandoned_count_(0), |
| 556 total_bytes_received_(0), | 570 total_bytes_received_(0), |
| 557 sent_settings_(false), | 571 sent_settings_(false), |
| 558 received_settings_(false), | 572 received_settings_(false), |
| 559 stalled_streams_(0), | 573 stalled_streams_(0), |
| 560 pings_in_flight_(0), | 574 pings_in_flight_(0), |
| 561 next_ping_id_(1), | 575 next_ping_id_(1), |
| 562 last_activity_time_(time_func()), | 576 last_activity_time_(time_func()), |
| 563 last_compressed_frame_len_(0), | 577 last_compressed_frame_len_(0), |
| 564 check_ping_status_pending_(false), | 578 check_ping_status_pending_(false), |
| 565 send_connection_header_prefix_(false), | 579 send_connection_header_prefix_(false), |
| 566 flow_control_state_(FLOW_CONTROL_NONE), | 580 flow_control_state_(FLOW_CONTROL_NONE), |
| 567 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), | 581 stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), |
| 568 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? | 582 stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 |
| 569 kDefaultInitialRecvWindowSize : | 583 ? kDefaultInitialRecvWindowSize |
| 570 stream_initial_recv_window_size), | 584 : stream_initial_recv_window_size), |
| 571 session_send_window_size_(0), | 585 session_send_window_size_(0), |
| 572 session_recv_window_size_(0), | 586 session_recv_window_size_(0), |
| 573 session_unacked_recv_window_bytes_(0), | 587 session_unacked_recv_window_bytes_(0), |
| 574 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)), | 588 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)), |
| 575 verify_domain_authentication_(verify_domain_authentication), | 589 verify_domain_authentication_(verify_domain_authentication), |
| 576 enable_sending_initial_data_(enable_sending_initial_data), | 590 enable_sending_initial_data_(enable_sending_initial_data), |
| 577 enable_compression_(enable_compression), | 591 enable_compression_(enable_compression), |
| 578 enable_ping_based_connection_checking_( | 592 enable_ping_based_connection_checking_( |
| 579 enable_ping_based_connection_checking), | 593 enable_ping_based_connection_checking), |
| 580 protocol_(default_protocol), | 594 protocol_(default_protocol), |
| 581 connection_at_risk_of_loss_time_( | 595 connection_at_risk_of_loss_time_( |
| 582 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), | 596 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), |
| 583 hung_interval_( | 597 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), |
| 584 base::TimeDelta::FromSeconds(kHungIntervalSeconds)), | |
| 585 trusted_spdy_proxy_(trusted_spdy_proxy), | 598 trusted_spdy_proxy_(trusted_spdy_proxy), |
| 586 time_func_(time_func), | 599 time_func_(time_func), |
| 587 weak_factory_(this) { | 600 weak_factory_(this) { |
| 588 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); | 601 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); |
| 589 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); | 602 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); |
| 590 DCHECK(HttpStreamFactory::spdy_enabled()); | 603 DCHECK(HttpStreamFactory::spdy_enabled()); |
| 591 net_log_.BeginEvent( | 604 net_log_.BeginEvent( |
| 592 NetLog::TYPE_SPDY_SESSION, | 605 NetLog::TYPE_SPDY_SESSION, |
| 593 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); | 606 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); |
| 594 next_unclaimed_push_stream_sweep_time_ = time_func_() + | 607 next_unclaimed_push_stream_sweep_time_ = time_func_() + |
| (...skipping 1482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2077 } | 2090 } |
| 2078 | 2091 |
| 2079 void SpdySession::OnSynStream(SpdyStreamId stream_id, | 2092 void SpdySession::OnSynStream(SpdyStreamId stream_id, |
| 2080 SpdyStreamId associated_stream_id, | 2093 SpdyStreamId associated_stream_id, |
| 2081 SpdyPriority priority, | 2094 SpdyPriority priority, |
| 2082 bool fin, | 2095 bool fin, |
| 2083 bool unidirectional, | 2096 bool unidirectional, |
| 2084 const SpdyHeaderBlock& headers) { | 2097 const SpdyHeaderBlock& headers) { |
| 2085 CHECK(in_io_loop_); | 2098 CHECK(in_io_loop_); |
| 2086 | 2099 |
| 2100 if (GetProtocolVersion() >= SPDY4) { |
| 2101 DCHECK_EQ(0u, associated_stream_id); |
| 2102 OnHeaders(stream_id, fin, headers); |
| 2103 return; |
| 2104 } |
| 2105 |
| 2087 base::Time response_time = base::Time::Now(); | 2106 base::Time response_time = base::Time::Now(); |
| 2088 base::TimeTicks recv_first_byte_time = time_func_(); | 2107 base::TimeTicks recv_first_byte_time = time_func_(); |
| 2089 | 2108 |
| 2090 if (net_log_.IsLogging()) { | 2109 if (net_log_.IsLogging()) { |
| 2091 net_log_.AddEvent( | 2110 net_log_.AddEvent( |
| 2092 NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM, | 2111 NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM, |
| 2093 base::Bind(&NetLogSpdySynStreamReceivedCallback, | 2112 base::Bind(&NetLogSpdySynStreamReceivedCallback, |
| 2094 &headers, fin, unidirectional, priority, | 2113 &headers, fin, unidirectional, priority, |
| 2095 stream_id, associated_stream_id)); | 2114 stream_id, associated_stream_id)); |
| 2096 } | 2115 } |
| 2097 | 2116 |
| 2098 // Server-initiated streams should have even sequence numbers. | 2117 // Split headers to simulate push promise and response. |
| 2099 if ((stream_id & 0x1) != 0) { | 2118 SpdyHeaderBlock request_headers; |
| 2100 LOG(WARNING) << "Received invalid OnSyn stream id " << stream_id; | 2119 SpdyHeaderBlock response_headers; |
| 2120 SplitPushedHeadersToRequestAndResponse( |
| 2121 headers, GetProtocolVersion(), &request_headers, &response_headers); |
| 2122 |
| 2123 if (!TryCreatePushStream( |
| 2124 stream_id, associated_stream_id, priority, request_headers)) |
| 2101 return; | 2125 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 | 2126 |
| 2215 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); | 2127 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); |
| 2216 if (active_it == active_streams_.end()) { | 2128 if (active_it == active_streams_.end()) { |
| 2217 NOTREACHED(); | 2129 NOTREACHED(); |
| 2218 return; | 2130 return; |
| 2219 } | 2131 } |
| 2220 | 2132 |
| 2221 // Parse the headers. | |
| 2222 | |
| 2223 // Split headers to simulate push promise and response. | |
| 2224 SpdyHeaderBlock request_headers; | |
| 2225 SpdyHeaderBlock response_headers; | |
| 2226 SplitPushedHeadersToRequestAndResponse( | |
| 2227 headers, GetProtocolVersion(), &request_headers, &response_headers); | |
| 2228 | |
| 2229 if (active_it->second.stream->OnPushPromiseHeadersReceived(request_headers) != | |
| 2230 OK) | |
| 2231 return; | |
| 2232 | |
| 2233 if (OnInitialResponseHeadersReceived(response_headers, | 2133 if (OnInitialResponseHeadersReceived(response_headers, |
| 2234 response_time, | 2134 response_time, |
| 2235 recv_first_byte_time, | 2135 recv_first_byte_time, |
| 2236 active_it->second.stream) != OK) | 2136 active_it->second.stream) != OK) |
| 2237 return; | 2137 return; |
| 2238 | 2138 |
| 2239 base::StatsCounter push_requests("spdy.pushed_streams"); | 2139 base::StatsCounter push_requests("spdy.pushed_streams"); |
| 2240 push_requests.Increment(); | 2140 push_requests.Increment(); |
| 2241 } | 2141 } |
| 2242 | 2142 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2341 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; | 2241 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; |
| 2342 return; | 2242 return; |
| 2343 } | 2243 } |
| 2344 | 2244 |
| 2345 SpdyStream* stream = it->second.stream; | 2245 SpdyStream* stream = it->second.stream; |
| 2346 CHECK_EQ(stream->stream_id(), stream_id); | 2246 CHECK_EQ(stream->stream_id(), stream_id); |
| 2347 | 2247 |
| 2348 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); | 2248 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); |
| 2349 last_compressed_frame_len_ = 0; | 2249 last_compressed_frame_len_ = 0; |
| 2350 | 2250 |
| 2251 base::Time response_time = base::Time::Now(); |
| 2252 base::TimeTicks recv_first_byte_time = time_func_(); |
| 2253 |
| 2351 if (it->second.waiting_for_syn_reply) { | 2254 if (it->second.waiting_for_syn_reply) { |
| 2352 if (GetProtocolVersion() < SPDY4) { | 2255 if (GetProtocolVersion() < SPDY4) { |
| 2353 const std::string& error = | 2256 const std::string& error = |
| 2354 "Was expecting SYN_REPLY, not HEADERS."; | 2257 "Was expecting SYN_REPLY, not HEADERS."; |
| 2355 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); | 2258 stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
| 2356 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error); | 2259 ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error); |
| 2357 return; | 2260 return; |
| 2358 } | 2261 } |
| 2359 base::Time response_time = base::Time::Now(); | |
| 2360 base::TimeTicks recv_first_byte_time = time_func_(); | |
| 2361 | 2262 |
| 2362 it->second.waiting_for_syn_reply = false; | 2263 it->second.waiting_for_syn_reply = false; |
| 2363 ignore_result(OnInitialResponseHeadersReceived( | 2264 ignore_result(OnInitialResponseHeadersReceived( |
| 2364 headers, response_time, recv_first_byte_time, stream)); | 2265 headers, response_time, recv_first_byte_time, stream)); |
| 2266 } else if (it->second.stream->IsReservedRemote()) { |
| 2267 ignore_result(OnInitialResponseHeadersReceived( |
| 2268 headers, response_time, recv_first_byte_time, stream)); |
| 2365 } else { | 2269 } else { |
| 2366 int rv = stream->OnAdditionalResponseHeadersReceived(headers); | 2270 int rv = stream->OnAdditionalResponseHeadersReceived(headers); |
| 2367 if (rv < 0) { | 2271 if (rv < 0) { |
| 2368 DCHECK_NE(rv, ERR_IO_PENDING); | 2272 DCHECK_NE(rv, ERR_IO_PENDING); |
| 2369 DCHECK(active_streams_.find(stream_id) == active_streams_.end()); | 2273 DCHECK(active_streams_.find(stream_id) == active_streams_.end()); |
| 2370 } | 2274 } |
| 2371 } | 2275 } |
| 2372 } | 2276 } |
| 2373 | 2277 |
| 2374 void SpdySession::OnRstStream(SpdyStreamId stream_id, | 2278 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)); | 2418 "delta_window_size %ud", delta_window_size)); |
| 2515 return; | 2419 return; |
| 2516 } | 2420 } |
| 2517 | 2421 |
| 2518 CHECK_EQ(it->second.stream->stream_id(), stream_id); | 2422 CHECK_EQ(it->second.stream->stream_id(), stream_id); |
| 2519 it->second.stream->IncreaseSendWindowSize( | 2423 it->second.stream->IncreaseSendWindowSize( |
| 2520 static_cast<int32>(delta_window_size)); | 2424 static_cast<int32>(delta_window_size)); |
| 2521 } | 2425 } |
| 2522 } | 2426 } |
| 2523 | 2427 |
| 2428 bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id, |
| 2429 SpdyStreamId associated_stream_id, |
| 2430 SpdyPriority priority, |
| 2431 const SpdyHeaderBlock& headers) { |
| 2432 // Server-initiated streams should have even sequence numbers. |
| 2433 if ((stream_id & 0x1) != 0) { |
| 2434 LOG(WARNING) << "Received invalid push stream id " << stream_id; |
| 2435 return false; |
| 2436 } |
| 2437 |
| 2438 if (IsStreamActive(stream_id)) { |
| 2439 LOG(WARNING) << "Received push for active stream " << stream_id; |
| 2440 return false; |
| 2441 } |
| 2442 |
| 2443 RequestPriority request_priority = |
| 2444 ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion()); |
| 2445 |
| 2446 if (availability_state_ == STATE_GOING_AWAY) { |
| 2447 // TODO(akalin): This behavior isn't in the SPDY spec, although it |
| 2448 // probably should be. |
| 2449 EnqueueResetStreamFrame(stream_id, |
| 2450 request_priority, |
| 2451 RST_STREAM_REFUSED_STREAM, |
| 2452 "push stream request received when going away"); |
| 2453 return false; |
| 2454 } |
| 2455 |
| 2456 if (associated_stream_id == 0) { |
| 2457 // In SPDY4 0 stream id in PUSH_PROMISE frame leads to framer error and |
| 2458 // session going away. We should never get here. |
| 2459 CHECK_GT(SPDY4, GetProtocolVersion()); |
| 2460 std::string description = base::StringPrintf( |
| 2461 "Received invalid associated stream id %d for pushed stream %d", |
| 2462 associated_stream_id, |
| 2463 stream_id); |
| 2464 EnqueueResetStreamFrame( |
| 2465 stream_id, request_priority, RST_STREAM_REFUSED_STREAM, description); |
| 2466 return false; |
| 2467 } |
| 2468 |
| 2469 streams_pushed_count_++; |
| 2470 |
| 2471 // TODO(mbelshe): DCHECK that this is a GET method? |
| 2472 |
| 2473 // Verify that the response had a URL for us. |
| 2474 GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion(), true); |
| 2475 if (!gurl.is_valid()) { |
| 2476 EnqueueResetStreamFrame(stream_id, |
| 2477 request_priority, |
| 2478 RST_STREAM_PROTOCOL_ERROR, |
| 2479 "Pushed stream url was invalid: " + gurl.spec()); |
| 2480 return false; |
| 2481 } |
| 2482 |
| 2483 // Verify we have a valid stream association. |
| 2484 ActiveStreamMap::iterator associated_it = |
| 2485 active_streams_.find(associated_stream_id); |
| 2486 if (associated_it == active_streams_.end()) { |
| 2487 EnqueueResetStreamFrame( |
| 2488 stream_id, |
| 2489 request_priority, |
| 2490 RST_STREAM_INVALID_STREAM, |
| 2491 base::StringPrintf("Received push for inactive associated stream %d", |
| 2492 associated_stream_id)); |
| 2493 return false; |
| 2494 } |
| 2495 |
| 2496 // Check that the pushed stream advertises the same origin as its associated |
| 2497 // stream. Bypass this check if and only if this session is with a SPDY proxy |
| 2498 // that is trusted explicitly via the --trusted-spdy-proxy switch. |
| 2499 if (trusted_spdy_proxy_.Equals(host_port_pair())) { |
| 2500 // Disallow pushing of HTTPS content. |
| 2501 if (gurl.SchemeIs("https")) { |
| 2502 EnqueueResetStreamFrame( |
| 2503 stream_id, |
| 2504 request_priority, |
| 2505 RST_STREAM_REFUSED_STREAM, |
| 2506 base::StringPrintf("Rejected push of Cross Origin HTTPS content %d", |
| 2507 associated_stream_id)); |
| 2508 } |
| 2509 } else { |
| 2510 GURL associated_url(associated_it->second.stream->GetUrlFromHeaders()); |
| 2511 if (associated_url.GetOrigin() != gurl.GetOrigin()) { |
| 2512 EnqueueResetStreamFrame( |
| 2513 stream_id, |
| 2514 request_priority, |
| 2515 RST_STREAM_REFUSED_STREAM, |
| 2516 base::StringPrintf("Rejected Cross Origin Push Stream %d", |
| 2517 associated_stream_id)); |
| 2518 return false; |
| 2519 } |
| 2520 } |
| 2521 |
| 2522 // There should not be an existing pushed stream with the same path. |
| 2523 PushedStreamMap::iterator pushed_it = |
| 2524 unclaimed_pushed_streams_.lower_bound(gurl); |
| 2525 if (pushed_it != unclaimed_pushed_streams_.end() && |
| 2526 pushed_it->first == gurl) { |
| 2527 EnqueueResetStreamFrame( |
| 2528 stream_id, |
| 2529 request_priority, |
| 2530 RST_STREAM_PROTOCOL_ERROR, |
| 2531 "Received duplicate pushed stream with url: " + gurl.spec()); |
| 2532 return false; |
| 2533 } |
| 2534 |
| 2535 scoped_ptr<SpdyStream> stream(new SpdyStream(SPDY_PUSH_STREAM, |
| 2536 GetWeakPtr(), |
| 2537 gurl, |
| 2538 request_priority, |
| 2539 stream_initial_send_window_size_, |
| 2540 stream_initial_recv_window_size_, |
| 2541 net_log_)); |
| 2542 stream->set_stream_id(stream_id); |
| 2543 |
| 2544 // In spdy4/http2 PUSH_PROMISE arrives on associated stream. |
| 2545 if (associated_it != active_streams_.end() && GetProtocolVersion() >= SPDY4) { |
| 2546 associated_it->second.stream->IncrementRawReceivedBytes( |
| 2547 last_compressed_frame_len_); |
| 2548 } else { |
| 2549 stream->IncrementRawReceivedBytes(last_compressed_frame_len_); |
| 2550 } |
| 2551 |
| 2552 last_compressed_frame_len_ = 0; |
| 2553 |
| 2554 DeleteExpiredPushedStreams(); |
| 2555 PushedStreamMap::iterator inserted_pushed_it = |
| 2556 unclaimed_pushed_streams_.insert( |
| 2557 pushed_it, |
| 2558 std::make_pair(gurl, PushedStreamInfo(stream_id, time_func_()))); |
| 2559 DCHECK(inserted_pushed_it != pushed_it); |
| 2560 |
| 2561 InsertActivatedStream(stream.Pass()); |
| 2562 |
| 2563 ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); |
| 2564 if (active_it == active_streams_.end()) { |
| 2565 NOTREACHED(); |
| 2566 return false; |
| 2567 } |
| 2568 |
| 2569 active_it->second.stream->OnPushPromiseHeadersReceived(headers); |
| 2570 DCHECK(active_it->second.stream->IsReservedRemote()); |
| 2571 return true; |
| 2572 } |
| 2573 |
| 2524 void SpdySession::OnPushPromise(SpdyStreamId stream_id, | 2574 void SpdySession::OnPushPromise(SpdyStreamId stream_id, |
| 2525 SpdyStreamId promised_stream_id, | 2575 SpdyStreamId promised_stream_id, |
| 2526 const SpdyHeaderBlock& headers) { | 2576 const SpdyHeaderBlock& headers) { |
| 2527 // TODO(akalin): Handle PUSH_PROMISE frames. | 2577 CHECK(in_io_loop_); |
| 2578 |
| 2579 if (net_log_.IsLogging()) { |
| 2580 net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_PUSH_PROMISE, |
| 2581 base::Bind(&NetLogSpdyPushPromiseReceivedCallback, |
| 2582 &headers, |
| 2583 stream_id, |
| 2584 promised_stream_id)); |
| 2585 } |
| 2586 |
| 2587 // Any priority will do. |
| 2588 // TODO(baranovich): pass parent stream id priority? |
| 2589 if (!TryCreatePushStream(promised_stream_id, stream_id, 0, headers)) |
| 2590 return; |
| 2591 |
| 2592 base::StatsCounter push_requests("spdy.pushed_streams"); |
| 2593 push_requests.Increment(); |
| 2528 } | 2594 } |
| 2529 | 2595 |
| 2530 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, | 2596 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, |
| 2531 uint32 delta_window_size) { | 2597 uint32 delta_window_size) { |
| 2532 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); | 2598 CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); |
| 2533 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); | 2599 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
| 2534 CHECK(it != active_streams_.end()); | 2600 CHECK(it != active_streams_.end()); |
| 2535 CHECK_EQ(it->second.stream->stream_id(), stream_id); | 2601 CHECK_EQ(it->second.stream->stream_id(), stream_id); |
| 2536 SendWindowUpdateFrame( | 2602 SendWindowUpdateFrame( |
| 2537 stream_id, delta_window_size, it->second.stream->priority()); | 2603 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()) { | 3117 if (!queue->empty()) { |
| 3052 SpdyStreamId stream_id = queue->front(); | 3118 SpdyStreamId stream_id = queue->front(); |
| 3053 queue->pop_front(); | 3119 queue->pop_front(); |
| 3054 return stream_id; | 3120 return stream_id; |
| 3055 } | 3121 } |
| 3056 } | 3122 } |
| 3057 return 0; | 3123 return 0; |
| 3058 } | 3124 } |
| 3059 | 3125 |
| 3060 } // namespace net | 3126 } // namespace net |
| OLD | NEW |