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

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

Issue 2596703002: http2: Update priorities of pushed streams (Closed)
Patch Set: Created 3 years, 12 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 <limits> 8 #include <limits>
9 #include <map> 9 #include <map>
10 #include <utility> 10 #include <utility>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
16 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
17 #include "base/metrics/sparse_histogram.h" 18 #include "base/metrics/sparse_histogram.h"
18 #include "base/profiler/scoped_tracker.h" 19 #include "base/profiler/scoped_tracker.h"
19 #include "base/single_thread_task_runner.h" 20 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h" 21 #include "base/stl_util.h"
21 #include "base/strings/string_number_conversions.h" 22 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h" 23 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h" 24 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h" 25 #include "base/strings/utf_string_conversions.h"
25 #include "base/threading/thread_task_runner_handle.h" 26 #include "base/threading/thread_task_runner_handle.h"
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 std::unique_ptr<base::Value> NetLogSpdyAdoptedPushStreamCallback( 259 std::unique_ptr<base::Value> NetLogSpdyAdoptedPushStreamCallback(
259 SpdyStreamId stream_id, 260 SpdyStreamId stream_id,
260 const GURL* url, 261 const GURL* url,
261 NetLogCaptureMode capture_mode) { 262 NetLogCaptureMode capture_mode) {
262 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 263 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
263 dict->SetInteger("stream_id", stream_id); 264 dict->SetInteger("stream_id", stream_id);
264 dict->SetString("url", url->spec()); 265 dict->SetString("url", url->spec());
265 return std::move(dict); 266 return std::move(dict);
266 } 267 }
267 268
269 std::unique_ptr<base::Value> NetLogSpdyPriorityCallback(
270 SpdyStreamId stream_id,
271 SpdyStreamId parent_stream_id,
272 int weight,
273 bool exclusive,
274 NetLogCaptureMode capture_mode) {
275 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
Bence 2017/01/05 17:14:46 Please use MakeUnique in new code, see https://cs.
Tom Bergan 2017/01/06 00:08:41 Done. Also did a search/replace on the other NetLo
276 dict->SetInteger("stream_id", stream_id);
277 dict->SetInteger("parent_stream_id", parent_stream_id);
278 dict->SetInteger("weight", weight);
279 dict->SetBoolean("exclusive", exclusive);
280 return std::move(dict);
281 }
282
268 // Helper function to return the total size of an array of objects 283 // Helper function to return the total size of an array of objects
269 // with .size() member functions. 284 // with .size() member functions.
270 template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) { 285 template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
271 size_t total_size = 0; 286 size_t total_size = 0;
272 for (size_t i = 0; i < N; ++i) { 287 for (size_t i = 0; i < N; ++i) {
273 total_size += arr[i].size(); 288 total_size += arr[i].size();
274 } 289 }
275 return total_size; 290 return total_size;
276 } 291 }
277 292
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 780
766 SSLInfo ssl_info; 781 SSLInfo ssl_info;
767 if (!GetSSLInfo(&ssl_info)) 782 if (!GetSSLInfo(&ssl_info))
768 return true; // This is not a secure session, so all domains are okay. 783 return true; // This is not a secure session, so all domains are okay.
769 784
770 return CanPool(transport_security_state_, ssl_info, 785 return CanPool(transport_security_state_, ssl_info,
771 host_port_pair().host(), domain); 786 host_port_pair().host(), domain);
772 } 787 }
773 788
774 int SpdySession::GetPushStream(const GURL& url, 789 int SpdySession::GetPushStream(const GURL& url,
790 RequestPriority priority,
775 base::WeakPtr<SpdyStream>* stream, 791 base::WeakPtr<SpdyStream>* stream,
776 const NetLogWithSource& stream_net_log) { 792 const NetLogWithSource& stream_net_log) {
777 CHECK(!in_io_loop_); 793 CHECK(!in_io_loop_);
778 794
779 stream->reset(); 795 stream->reset();
780 796
781 if (availability_state_ == STATE_DRAINING) 797 if (availability_state_ == STATE_DRAINING)
782 return ERR_CONNECTION_CLOSED; 798 return ERR_CONNECTION_CLOSED;
783 799
784 *stream = GetActivePushStream(url); 800 *stream = GetActivePushStream(url);
785 if (*stream) { 801 if (*stream) {
786 DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_); 802 DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_);
787 streams_pushed_and_claimed_count_++; 803 streams_pushed_and_claimed_count_++;
804
805 // If the stream is still open, update its priority to match
806 // the priority of the matching request.
807 if (!(*stream)->IsClosed() && (*stream)->priority() != priority) {
808 (*stream)->set_priority(priority);
809
810 // Send PRIORITY updates.
811 auto updates = priority_dependency_state_.OnStreamUpdate(
812 (*stream)->stream_id(),
813 ConvertRequestPriorityToSpdyPriority(priority));
814 for (auto u : updates) {
815 ActiveStreamMap::iterator it = active_streams_.find(u.id);
816 DCHECK(it != active_streams_.end());
817 int weight = Spdy3PriorityToHttp2Weight(
818 ConvertRequestPriorityToSpdyPriority(it->second->priority()));
819 EnqueuePriorityFrame(u.id, u.dependent_stream_id, weight, u.exclusive);
820 }
821 }
788 } 822 }
823
789 return OK; 824 return OK;
790 } 825 }
791 826
792 void SpdySession::CancelPush(const GURL& url) { 827 void SpdySession::CancelPush(const GURL& url) {
793 UnclaimedPushedStreamContainer::const_iterator unclaimed_it = 828 UnclaimedPushedStreamContainer::const_iterator unclaimed_it =
794 unclaimed_pushed_streams_.find(url); 829 unclaimed_pushed_streams_.find(url);
795 if (unclaimed_it == unclaimed_pushed_streams_.end()) 830 if (unclaimed_it == unclaimed_pushed_streams_.end())
796 return; 831 return;
797 832
798 SpdyStreamId stream_id = unclaimed_it->second.stream_id; 833 SpdyStreamId stream_id = unclaimed_it->second.stream_id;
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 1039
1005 DCHECK(buffered_spdy_framer_.get()); 1040 DCHECK(buffered_spdy_framer_.get());
1006 SpdyPriority spdy_priority = ConvertRequestPriorityToSpdyPriority(priority); 1041 SpdyPriority spdy_priority = ConvertRequestPriorityToSpdyPriority(priority);
1007 1042
1008 std::unique_ptr<SpdySerializedFrame> syn_frame; 1043 std::unique_ptr<SpdySerializedFrame> syn_frame;
1009 bool has_priority = true; 1044 bool has_priority = true;
1010 int weight = Spdy3PriorityToHttp2Weight(spdy_priority); 1045 int weight = Spdy3PriorityToHttp2Weight(spdy_priority);
1011 SpdyStreamId dependent_stream_id = 0; 1046 SpdyStreamId dependent_stream_id = 0;
1012 bool exclusive = false; 1047 bool exclusive = false;
1013 1048
1014 priority_dependency_state_.OnStreamSynSent(stream_id, spdy_priority, 1049 priority_dependency_state_.OnStreamCreation(stream_id, spdy_priority,
1015 &dependent_stream_id, &exclusive); 1050 &dependent_stream_id, &exclusive);
1016 1051
1017 if (net_log().IsCapturing()) { 1052 if (net_log().IsCapturing()) {
1018 net_log().AddEvent( 1053 net_log().AddEvent(
1019 NetLogEventType::HTTP2_SESSION_SEND_HEADERS, 1054 NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
1020 base::Bind(&NetLogSpdyHeadersSentCallback, &block, 1055 base::Bind(&NetLogSpdyHeadersSentCallback, &block,
1021 (flags & CONTROL_FLAG_FIN) != 0, stream_id, has_priority, 1056 (flags & CONTROL_FLAG_FIN) != 0, stream_id, has_priority,
1022 weight, dependent_stream_id, exclusive)); 1057 weight, dependent_stream_id, exclusive));
1023 } 1058 }
1024 1059
1025 SpdyHeadersIR headers(stream_id, std::move(block)); 1060 SpdyHeadersIR headers(stream_id, std::move(block));
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
1263 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description)); 1298 base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
1264 1299
1265 DCHECK(buffered_spdy_framer_.get()); 1300 DCHECK(buffered_spdy_framer_.get());
1266 std::unique_ptr<SpdySerializedFrame> rst_frame( 1301 std::unique_ptr<SpdySerializedFrame> rst_frame(
1267 buffered_spdy_framer_->CreateRstStream(stream_id, status)); 1302 buffered_spdy_framer_->CreateRstStream(stream_id, status));
1268 1303
1269 EnqueueSessionWrite(priority, RST_STREAM, std::move(rst_frame)); 1304 EnqueueSessionWrite(priority, RST_STREAM, std::move(rst_frame));
1270 RecordProtocolErrorHistogram(MapRstStreamStatusToProtocolError(status)); 1305 RecordProtocolErrorHistogram(MapRstStreamStatusToProtocolError(status));
1271 } 1306 }
1272 1307
1308 void SpdySession::EnqueuePriorityFrame(SpdyStreamId stream_id,
1309 SpdyStreamId dependency_id,
1310 int weight,
1311 bool exclusive) {
1312 net_log().AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_PRIORITY,
1313 base::Bind(&NetLogSpdyPriorityCallback, stream_id,
1314 dependency_id, weight, exclusive));
1315
1316 DCHECK(buffered_spdy_framer_.get());
1317 std::unique_ptr<SpdySerializedFrame> frame(
1318 buffered_spdy_framer_->CreatePriority(stream_id, dependency_id, weight,
1319 exclusive));
1320
1321 // PRIORITY frames describe sequenced updates to the tree, so they must
1322 // be serialized. We do this by queueing all PRIORITY frames at HIGHEST
1323 // priority.
1324 EnqueueWrite(HIGHEST, PRIORITY,
1325 base::MakeUnique<SimpleBufferProducer>(
1326 base::MakeUnique<SpdyBuffer>(std::move(frame))),
1327 base::WeakPtr<SpdyStream>());
1328 }
1329
1273 void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) { 1330 void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
1274 CHECK(!in_io_loop_); 1331 CHECK(!in_io_loop_);
1275 if (availability_state_ == STATE_DRAINING) { 1332 if (availability_state_ == STATE_DRAINING) {
1276 return; 1333 return;
1277 } 1334 }
1278 ignore_result(DoReadLoop(expected_read_state, result)); 1335 ignore_result(DoReadLoop(expected_read_state, result));
1279 } 1336 }
1280 1337
1281 int SpdySession::DoReadLoop(ReadState expected_read_state, int result) { 1338 int SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
1282 CHECK(!in_io_loop_); 1339 CHECK(!in_io_loop_);
(...skipping 1118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2401 return; 2458 return;
2402 } 2459 }
2403 2460
2404 CHECK_EQ(it->second->stream_id(), stream_id); 2461 CHECK_EQ(it->second->stream_id(), stream_id);
2405 it->second->IncreaseSendWindowSize(delta_window_size); 2462 it->second->IncreaseSendWindowSize(delta_window_size);
2406 } 2463 }
2407 } 2464 }
2408 2465
2409 void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, 2466 void SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
2410 SpdyStreamId associated_stream_id, 2467 SpdyStreamId associated_stream_id,
2411 SpdyPriority priority,
2412 SpdyHeaderBlock headers) { 2468 SpdyHeaderBlock headers) {
2413 // Server-initiated streams should have even sequence numbers. 2469 // Server-initiated streams should have even sequence numbers.
2414 if ((stream_id & 0x1) != 0) { 2470 if ((stream_id & 0x1) != 0) {
2415 LOG(WARNING) << "Received invalid push stream id " << stream_id; 2471 LOG(WARNING) << "Received invalid push stream id " << stream_id;
2416 CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Odd push stream id."); 2472 CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Odd push stream id.");
2417 return; 2473 return;
2418 } 2474 }
2419 2475
2420 // Server-initiated streams must be associated with client-initiated streams. 2476 // Server-initiated streams must be associated with client-initiated streams.
2421 if ((associated_stream_id & 0x1) != 1) { 2477 if ((associated_stream_id & 0x1) != 1) {
(...skipping 14 matching lines...) Expand all
2436 2492
2437 if (IsStreamActive(stream_id)) { 2493 if (IsStreamActive(stream_id)) {
2438 // We should not get here, we'll start going away earlier on 2494 // We should not get here, we'll start going away earlier on
2439 // |last_seen_push_stream_id_| check. 2495 // |last_seen_push_stream_id_| check.
2440 LOG(WARNING) << "Received push for active stream " << stream_id; 2496 LOG(WARNING) << "Received push for active stream " << stream_id;
2441 return; 2497 return;
2442 } 2498 }
2443 2499
2444 last_accepted_push_stream_id_ = stream_id; 2500 last_accepted_push_stream_id_ = stream_id;
2445 2501
2446 RequestPriority request_priority = 2502 // Pushed streams are speculative, so they start at an IDLE priority.
2447 ConvertSpdyPriorityToRequestPriority(priority); 2503 const RequestPriority request_priority = IDLE;
2448 2504
2449 if (availability_state_ == STATE_GOING_AWAY) { 2505 if (availability_state_ == STATE_GOING_AWAY) {
2450 // TODO(akalin): This behavior isn't in the SPDY spec, although it 2506 // TODO(akalin): This behavior isn't in the SPDY spec, although it
2451 // probably should be. 2507 // probably should be.
2452 EnqueueResetStreamFrame(stream_id, 2508 EnqueueResetStreamFrame(stream_id,
2453 request_priority, 2509 request_priority,
2454 RST_STREAM_REFUSED_STREAM, 2510 RST_STREAM_REFUSED_STREAM,
2455 "push stream request received when going away"); 2511 "push stream request received when going away");
2456 return; 2512 return;
2457 } 2513 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
2554 "Received duplicate pushed stream with url: " + gurl.spec()); 2610 "Received duplicate pushed stream with url: " + gurl.spec());
2555 return; 2611 return;
2556 } 2612 }
2557 2613
2558 std::unique_ptr<SpdyStream> stream( 2614 std::unique_ptr<SpdyStream> stream(
2559 new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl, request_priority, 2615 new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl, request_priority,
2560 stream_initial_send_window_size_, 2616 stream_initial_send_window_size_,
2561 stream_max_recv_window_size_, net_log_)); 2617 stream_max_recv_window_size_, net_log_));
2562 stream->set_stream_id(stream_id); 2618 stream->set_stream_id(stream_id);
2563 2619
2620 // Convert RequestPriority to a SpdyPriority to send in a PRIORITY frame.
2621 SpdyPriority spdy_priority =
2622 ConvertRequestPriorityToSpdyPriority(request_priority);
2623 SpdyStreamId dependency_id = 0;
2624 bool exclusive = false;
2625 priority_dependency_state_.OnStreamCreation(stream_id, spdy_priority,
2626 &dependency_id, &exclusive);
2627 EnqueuePriorityFrame(stream_id, dependency_id,
2628 Spdy3PriorityToHttp2Weight(spdy_priority), exclusive);
2629
2564 // PUSH_PROMISE arrives on associated stream. 2630 // PUSH_PROMISE arrives on associated stream.
2565 associated_it->second->AddRawReceivedBytes(last_compressed_frame_len_); 2631 associated_it->second->AddRawReceivedBytes(last_compressed_frame_len_);
2566 last_compressed_frame_len_ = 0; 2632 last_compressed_frame_len_ = 0;
2567 2633
2568 UnclaimedPushedStreamContainer::const_iterator inserted_pushed_it = 2634 UnclaimedPushedStreamContainer::const_iterator inserted_pushed_it =
2569 unclaimed_pushed_streams_.insert(pushed_it, gurl, stream_id, 2635 unclaimed_pushed_streams_.insert(pushed_it, gurl, stream_id,
2570 time_func_()); 2636 time_func_());
2571 DCHECK(inserted_pushed_it != pushed_it); 2637 DCHECK(inserted_pushed_it != pushed_it);
2572 DeleteExpiredPushedStreams(); 2638 DeleteExpiredPushedStreams();
2573 2639
(...skipping 21 matching lines...) Expand all
2595 SpdyStreamId promised_stream_id, 2661 SpdyStreamId promised_stream_id,
2596 SpdyHeaderBlock headers) { 2662 SpdyHeaderBlock headers) {
2597 CHECK(in_io_loop_); 2663 CHECK(in_io_loop_);
2598 2664
2599 if (net_log_.IsCapturing()) { 2665 if (net_log_.IsCapturing()) {
2600 net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE, 2666 net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE,
2601 base::Bind(&NetLogSpdyPushPromiseReceivedCallback, 2667 base::Bind(&NetLogSpdyPushPromiseReceivedCallback,
2602 &headers, stream_id, promised_stream_id)); 2668 &headers, stream_id, promised_stream_id));
2603 } 2669 }
2604 2670
2605 // Any priority will do. TODO(baranovich): Pass parent stream id priority? 2671 TryCreatePushStream(promised_stream_id, stream_id, std::move(headers));
2606 TryCreatePushStream(promised_stream_id, stream_id, 0, std::move(headers));
2607 } 2672 }
2608 2673
2609 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, 2674 void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id,
2610 uint32_t delta_window_size) { 2675 uint32_t delta_window_size) {
2611 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); 2676 ActiveStreamMap::const_iterator it = active_streams_.find(stream_id);
2612 CHECK(it != active_streams_.end()); 2677 CHECK(it != active_streams_.end());
2613 CHECK_EQ(it->second->stream_id(), stream_id); 2678 CHECK_EQ(it->second->stream_id(), stream_id);
2614 SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority()); 2679 SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority());
2615 } 2680 }
2616 2681
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
3011 if (!queue->empty()) { 3076 if (!queue->empty()) {
3012 SpdyStreamId stream_id = queue->front(); 3077 SpdyStreamId stream_id = queue->front();
3013 queue->pop_front(); 3078 queue->pop_front();
3014 return stream_id; 3079 return stream_id;
3015 } 3080 }
3016 } 3081 }
3017 return 0; 3082 return 0;
3018 } 3083 }
3019 3084
3020 } // namespace net 3085 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698