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