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 <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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |