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 |