http2_push_promise_index.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/spdy/http2_push_promise_index.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include "base/trace_event/memory_usage_estimator.h"
  8. namespace net {
  9. Http2PushPromiseIndex::Http2PushPromiseIndex() = default;
  10. Http2PushPromiseIndex::~Http2PushPromiseIndex() {
  11. DCHECK(unclaimed_pushed_streams_.empty());
  12. }
  13. bool Http2PushPromiseIndex::RegisterUnclaimedPushedStream(
  14. const GURL& url,
  15. spdy::SpdyStreamId stream_id,
  16. Delegate* delegate) {
  17. DCHECK(!url.is_empty());
  18. DCHECK_GT(stream_id, kNoPushedStreamFound);
  19. DCHECK(delegate);
  20. // Find the entry with |url| for |delegate| if such exists (there can be at
  21. // most one such entry). It is okay to cast away const from |delegate|,
  22. // because it is only used for lookup.
  23. auto it = unclaimed_pushed_streams_.lower_bound(UnclaimedPushedStream{
  24. url, const_cast<Delegate*>(delegate), kNoPushedStreamFound});
  25. // If such entry is found, do not allow registering another one.
  26. if (it != unclaimed_pushed_streams_.end() && it->url == url &&
  27. it->delegate == delegate) {
  28. return false;
  29. }
  30. unclaimed_pushed_streams_.insert(
  31. it, UnclaimedPushedStream{url, delegate, stream_id});
  32. return true;
  33. }
  34. bool Http2PushPromiseIndex::UnregisterUnclaimedPushedStream(
  35. const GURL& url,
  36. spdy::SpdyStreamId stream_id,
  37. Delegate* delegate) {
  38. DCHECK(!url.is_empty());
  39. DCHECK_GT(stream_id, kNoPushedStreamFound);
  40. DCHECK(delegate);
  41. size_t result = unclaimed_pushed_streams_.erase(
  42. UnclaimedPushedStream{url, delegate, stream_id});
  43. return result == 1;
  44. }
  45. // The runtime of this method is linear in unclaimed_pushed_streams_.size(),
  46. // which is acceptable, because it is only used in NetLog, tests, and DCHECKs.
  47. size_t Http2PushPromiseIndex::CountStreamsForSession(
  48. const Delegate* delegate) const {
  49. DCHECK(delegate);
  50. return std::count_if(unclaimed_pushed_streams_.begin(),
  51. unclaimed_pushed_streams_.end(),
  52. [&delegate](const UnclaimedPushedStream& entry) {
  53. return entry.delegate == delegate;
  54. });
  55. }
  56. spdy::SpdyStreamId Http2PushPromiseIndex::FindStream(
  57. const GURL& url,
  58. const Delegate* delegate) const {
  59. // Find the entry with |url| for |delegate| if such exists (there can be at
  60. // most one such entry). It is okay to cast away const from |delegate|,
  61. // because it is only used for lookup.
  62. auto it = unclaimed_pushed_streams_.lower_bound(UnclaimedPushedStream{
  63. url, const_cast<Delegate*>(delegate), kNoPushedStreamFound});
  64. if (it == unclaimed_pushed_streams_.end() || it->url != url ||
  65. it->delegate != delegate) {
  66. return kNoPushedStreamFound;
  67. }
  68. return it->stream_id;
  69. }
  70. void Http2PushPromiseIndex::ClaimPushedStream(
  71. const SpdySessionKey& key,
  72. const GURL& url,
  73. const HttpRequestInfo& request_info,
  74. base::WeakPtr<SpdySession>* session,
  75. spdy::SpdyStreamId* stream_id) {
  76. DCHECK(!url.is_empty());
  77. *session = nullptr;
  78. *stream_id = kNoPushedStreamFound;
  79. // Find the first entry for |url|, if such exists.
  80. auto it = unclaimed_pushed_streams_.lower_bound(
  81. UnclaimedPushedStream{url, nullptr, kNoPushedStreamFound});
  82. while (it != unclaimed_pushed_streams_.end() && it->url == url) {
  83. if (it->delegate->ValidatePushedStream(it->stream_id, url, request_info,
  84. key)) {
  85. *session = it->delegate->GetWeakPtrToSession();
  86. *stream_id = it->stream_id;
  87. unclaimed_pushed_streams_.erase(it);
  88. return;
  89. }
  90. ++it;
  91. }
  92. }
  93. bool Http2PushPromiseIndex::CompareByUrl::operator()(
  94. const UnclaimedPushedStream& a,
  95. const UnclaimedPushedStream& b) const {
  96. // Compare by URL first.
  97. if (a.url < b.url)
  98. return true;
  99. if (a.url > b.url)
  100. return false;
  101. // For identical URL, put an entry with delegate == nullptr first.
  102. // The C++ standard dictates that comparisons between |nullptr| and other
  103. // pointers are unspecified, hence the need to handle this case separately.
  104. if (a.delegate == nullptr && b.delegate != nullptr) {
  105. return true;
  106. }
  107. if (a.delegate != nullptr && b.delegate == nullptr) {
  108. return false;
  109. }
  110. // Then compare by Delegate.
  111. // The C++ standard guarantees that both |nullptr < nullptr| and
  112. // |nullptr > nullptr| are false, so there is no need to handle that case
  113. // separately.
  114. if (a.delegate < b.delegate)
  115. return true;
  116. if (a.delegate > b.delegate)
  117. return false;
  118. // If URL and Delegate are identical, then compare by stream ID.
  119. return a.stream_id < b.stream_id;
  120. }
  121. } // namespace net