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

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: 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
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 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698