Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: net/spdy/spdy_session.cc

Issue 331663007: Implement PUSH_PROMISE handling in spdy_session (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Call OnPushPromiseHeaders.. inside TryCreatePushStream Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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) {
Johnny 2014/06/19 16:58:51 Optional Nit: This could also live in BufferedSpdy
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
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
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;
Johnny 2014/06/19 16:58:51 Shouldn't be done in this CL, but we probably even
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
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
OLDNEW
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698