• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_SPDY_HTTP2_PUSH_PROMISE_INDEX_H_
6 #define NET_SPDY_HTTP2_PUSH_PROMISE_INDEX_H_
7 
8 #include <set>
9 
10 #include "base/memory/raw_ptr.h"
11 #include "base/memory/weak_ptr.h"
12 #include "net/base/net_export.h"
13 #include "net/http/http_request_info.h"
14 #include "net/spdy/spdy_session_key.h"
15 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
16 #include "url/gurl.h"
17 
18 namespace net {
19 
20 class SpdySession;
21 
22 namespace test {
23 
24 class Http2PushPromiseIndexPeer;
25 
26 }  // namespace test
27 
28 // Value returned by ClaimPushedStream() and FindStream() if no stream is found.
29 const spdy::SpdyStreamId kNoPushedStreamFound = 0;
30 
31 // This class manages unclaimed pushed streams (push promises) from the receipt
32 // of PUSH_PROMISE frame until they are matched to a request.
33 // Each SpdySessionPool owns one instance of this class.
34 // SpdySession uses this class to register, unregister and query pushed streams.
35 // HttpStreamFactory::Job uses this class to find a SpdySession with a pushed
36 // stream matching the request, if such exists.
37 class NET_EXPORT Http2PushPromiseIndex {
38  public:
39   // Interface for validating pushed streams, signaling when a pushed stream is
40   // claimed, and generating SpdySession weak pointer.
41   class NET_EXPORT Delegate {
42    public:
43     Delegate() = default;
44 
45     Delegate(const Delegate&) = delete;
46     Delegate& operator=(const Delegate&) = delete;
47 
48     virtual ~Delegate() = default;
49 
50     // Return true if a pushed stream with |url| can be used for a request with
51     // |key|.
52     virtual bool ValidatePushedStream(spdy::SpdyStreamId stream_id,
53                                       const GURL& url,
54                                       const HttpRequestInfo& request_info,
55                                       const SpdySessionKey& key) const = 0;
56 
57     // Generate weak pointer.  Guaranateed to be called synchronously after
58     // ValidatePushedStream() is called and returns true.
59     virtual base::WeakPtr<SpdySession> GetWeakPtrToSession() = 0;
60   };
61 
62   Http2PushPromiseIndex();
63 
64   Http2PushPromiseIndex(const Http2PushPromiseIndex&) = delete;
65   Http2PushPromiseIndex& operator=(const Http2PushPromiseIndex&) = delete;
66 
67   ~Http2PushPromiseIndex();
68 
69   // Tries to register a Delegate with an unclaimed pushed stream for |url|.
70   // Caller must make sure |delegate| stays valid by unregistering the exact
71   // same entry before |delegate| is destroyed.
72   // Returns true if there is no unclaimed pushed stream with the same URL for
73   // the same Delegate, in which case the stream is registered.
74   [[nodiscard]] bool RegisterUnclaimedPushedStream(const GURL& url,
75                                                    spdy::SpdyStreamId stream_id,
76                                                    Delegate* delegate);
77 
78   // Tries to unregister a Delegate with an unclaimed pushed stream for |url|
79   // with given |stream_id|.
80   // Returns true if this exact entry is found, in which case it is removed.
81   [[nodiscard]] bool UnregisterUnclaimedPushedStream(
82       const GURL& url,
83       spdy::SpdyStreamId stream_id,
84       Delegate* delegate);
85 
86   // Returns the number of pushed streams registered for |delegate|.
87   size_t CountStreamsForSession(const Delegate* delegate) const;
88 
89   // Returns the stream ID of the entry registered for |delegate| with |url|,
90   // or kNoPushedStreamFound if no such entry exists.
91   spdy::SpdyStreamId FindStream(const GURL& url,
92                                 const Delegate* delegate) const;
93 
94   // If there exists a session compatible with |key| that has an unclaimed push
95   // stream for |url|, then sets |*session| and |*stream| to one such session
96   // and stream, and removes entry from index.  Makes no guarantee on which
97   // (session, stream_id) pair is claimed if there are multiple matches.  Sets
98   // |*session| to nullptr and |*stream| to kNoPushedStreamFound if no such
99   // session exists.
100   void ClaimPushedStream(const SpdySessionKey& key,
101                          const GURL& url,
102                          const HttpRequestInfo& request_info,
103                          base::WeakPtr<SpdySession>* session,
104                          spdy::SpdyStreamId* stream_id);
105 
106  private:
107   friend test::Http2PushPromiseIndexPeer;
108 
109   // An unclaimed pushed stream entry.
110   struct NET_EXPORT UnclaimedPushedStream {
111     GURL url;
112     raw_ptr<Delegate> delegate;
113     spdy::SpdyStreamId stream_id;
114   };
115 
116   // Function object satisfying the requirements of "Compare", see
117   // http://en.cppreference.com/w/cpp/concept/Compare.
118   // A set ordered by this function object supports O(log n) lookup
119   // of the first entry with a given URL, by calling lower_bound() with an entry
120   // with that URL and with delegate = nullptr.
121   struct NET_EXPORT CompareByUrl {
122     bool operator()(const UnclaimedPushedStream& a,
123                     const UnclaimedPushedStream& b) const;
124   };
125 
126   // Collection of all unclaimed pushed streams.  Delegate must unregister
127   // its streams before destruction, so that all pointers remain valid.
128   // Each Delegate can have at most one pushed stream for each URL (but each
129   // Delegate can have pushed streams for different URLs, and different
130   // Delegates can have pushed streams for the same GURL).
131   std::set<UnclaimedPushedStream, CompareByUrl> unclaimed_pushed_streams_;
132 };
133 
134 }  // namespace net
135 
136 #endif  // NET_SPDY_HTTP2_PUSH_PROMISE_INDEX_H_
137