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