Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ |
| 6 | #define QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ |
| 7 | |
| 8 | #include <list> |
| 9 | #include <map> |
| 10 | #include <memory> |
| 11 | #include <vector> |
| 12 | |
| 13 | #include "absl/container/flat_hash_map.h" |
| 14 | #include "absl/strings/string_view.h" |
| 15 | #include "quiche/quic/core/http/spdy_utils.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 16 | #include "quiche/quic/platform/api/quic_mutex.h" |
| 17 | #include "quiche/quic/tools/quic_backend_response.h" |
| 18 | #include "quiche/quic/tools/quic_simple_server_backend.h" |
bnc | ffaa4c3 | 2022-07-18 08:29:54 -0700 | [diff] [blame] | 19 | #include "quiche/spdy/core/http2_header_block.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 20 | #include "quiche/spdy/core/spdy_framer.h" |
| 21 | |
| 22 | namespace quic { |
| 23 | |
| 24 | // In-memory cache for HTTP responses. |
| 25 | // Reads from disk cache generated by: |
| 26 | // `wget -p --save_headers <url>` |
| 27 | class QuicMemoryCacheBackend : public QuicSimpleServerBackend { |
| 28 | public: |
| 29 | // Class to manage loading a resource file into memory. There are |
| 30 | // two uses: called by InitializeBackend to load resources |
| 31 | // from files, and recursively called when said resources specify |
| 32 | // server push associations. |
| 33 | class ResourceFile { |
| 34 | public: |
| 35 | explicit ResourceFile(const std::string& file_name); |
| 36 | ResourceFile(const ResourceFile&) = delete; |
| 37 | ResourceFile& operator=(const ResourceFile&) = delete; |
| 38 | virtual ~ResourceFile(); |
| 39 | |
| 40 | void Read(); |
| 41 | |
| 42 | // |base| is |file_name_| with |cache_directory| prefix stripped. |
| 43 | void SetHostPathFromBase(absl::string_view base); |
| 44 | |
| 45 | const std::string& file_name() { return file_name_; } |
| 46 | |
| 47 | absl::string_view host() { return host_; } |
| 48 | |
| 49 | absl::string_view path() { return path_; } |
| 50 | |
| 51 | const spdy::Http2HeaderBlock& spdy_headers() { return spdy_headers_; } |
| 52 | |
| 53 | absl::string_view body() { return body_; } |
| 54 | |
| 55 | const std::vector<absl::string_view>& push_urls() { return push_urls_; } |
| 56 | |
| 57 | private: |
| 58 | void HandleXOriginalUrl(); |
| 59 | absl::string_view RemoveScheme(absl::string_view url); |
| 60 | |
| 61 | std::string file_name_; |
| 62 | std::string file_contents_; |
| 63 | absl::string_view body_; |
| 64 | spdy::Http2HeaderBlock spdy_headers_; |
| 65 | absl::string_view x_original_url_; |
| 66 | std::vector<absl::string_view> push_urls_; |
| 67 | std::string host_; |
| 68 | std::string path_; |
| 69 | }; |
| 70 | |
| 71 | QuicMemoryCacheBackend(); |
| 72 | QuicMemoryCacheBackend(const QuicMemoryCacheBackend&) = delete; |
| 73 | QuicMemoryCacheBackend& operator=(const QuicMemoryCacheBackend&) = delete; |
| 74 | ~QuicMemoryCacheBackend() override; |
| 75 | |
| 76 | // Retrieve a response from this cache for a given host and path.. |
| 77 | // If no appropriate response exists, nullptr is returned. |
| 78 | const QuicBackendResponse* GetResponse(absl::string_view host, |
| 79 | absl::string_view path) const; |
| 80 | |
| 81 | // Adds a simple response to the cache. The response headers will |
| 82 | // only contain the "content-length" header with the length of |body|. |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 83 | void AddSimpleResponse(absl::string_view host, absl::string_view path, |
| 84 | int response_code, absl::string_view body); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 85 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 86 | // Add a response to the cache. |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 87 | void AddResponse(absl::string_view host, absl::string_view path, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 88 | spdy::Http2HeaderBlock response_headers, |
| 89 | absl::string_view response_body); |
| 90 | |
| 91 | // Add a response, with trailers, to the cache. |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 92 | void AddResponse(absl::string_view host, absl::string_view path, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 93 | spdy::Http2HeaderBlock response_headers, |
| 94 | absl::string_view response_body, |
| 95 | spdy::Http2HeaderBlock response_trailers); |
| 96 | |
| 97 | // Add a response, with 103 Early Hints, to the cache. |
| 98 | void AddResponseWithEarlyHints( |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 99 | absl::string_view host, absl::string_view path, |
| 100 | spdy::Http2HeaderBlock response_headers, absl::string_view response_body, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 101 | const std::vector<spdy::Http2HeaderBlock>& early_hints); |
| 102 | |
| 103 | // Simulate a special behavior at a particular path. |
| 104 | void AddSpecialResponse( |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 105 | absl::string_view host, absl::string_view path, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 106 | QuicBackendResponse::SpecialResponseType response_type); |
| 107 | |
| 108 | void AddSpecialResponse( |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 109 | absl::string_view host, absl::string_view path, |
| 110 | spdy::Http2HeaderBlock response_headers, absl::string_view response_body, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 111 | QuicBackendResponse::SpecialResponseType response_type); |
| 112 | |
QUICHE team | 3ea648e | 2022-08-16 22:34:53 -0700 | [diff] [blame] | 113 | // Finds a response with the given host and path, and assign it a simulated |
| 114 | // delay. Returns true if the requisite response was found and the delay was |
| 115 | // set. |
| 116 | bool SetResponseDelay(absl::string_view host, absl::string_view path, |
| 117 | QuicTime::Delta delay); |
| 118 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 119 | // Sets a default response in case of cache misses. Takes ownership of |
| 120 | // 'response'. |
| 121 | void AddDefaultResponse(QuicBackendResponse* response); |
| 122 | |
| 123 | // Once called, URLs which have a numeric path will send a dynamically |
| 124 | // generated response of that many bytes. |
| 125 | void GenerateDynamicResponses(); |
| 126 | |
| 127 | void EnableWebTransport(); |
| 128 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 129 | // Implements the functions for interface QuicSimpleServerBackend |
| 130 | // |cache_cirectory| can be generated using `wget -p --save-headers <url>`. |
| 131 | bool InitializeBackend(const std::string& cache_directory) override; |
| 132 | bool IsBackendInitialized() const override; |
| 133 | void FetchResponseFromBackend( |
| 134 | const spdy::Http2HeaderBlock& request_headers, |
| 135 | const std::string& request_body, |
| 136 | QuicSimpleServerBackend::RequestHandler* quic_stream) override; |
| 137 | void CloseBackendResponseStream( |
| 138 | QuicSimpleServerBackend::RequestHandler* quic_stream) override; |
| 139 | WebTransportResponse ProcessWebTransportRequest( |
| 140 | const spdy::Http2HeaderBlock& request_headers, |
| 141 | WebTransportSession* session) override; |
| 142 | bool SupportsWebTransport() override { return enable_webtransport_; } |
| 143 | |
| 144 | private: |
bnc | bd76ad8 | 2022-04-13 08:30:34 -0700 | [diff] [blame] | 145 | void AddResponseImpl(absl::string_view host, absl::string_view path, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 146 | QuicBackendResponse::SpecialResponseType response_type, |
| 147 | spdy::Http2HeaderBlock response_headers, |
| 148 | absl::string_view response_body, |
| 149 | spdy::Http2HeaderBlock response_trailers, |
| 150 | const std::vector<spdy::Http2HeaderBlock>& early_hints); |
| 151 | |
| 152 | std::string GetKey(absl::string_view host, absl::string_view path) const; |
| 153 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 154 | // Cached responses. |
| 155 | absl::flat_hash_map<std::string, std::unique_ptr<QuicBackendResponse>> |
| 156 | responses_ QUIC_GUARDED_BY(response_mutex_); |
| 157 | |
| 158 | // The default response for cache misses, if set. |
| 159 | std::unique_ptr<QuicBackendResponse> default_response_ |
| 160 | QUIC_GUARDED_BY(response_mutex_); |
| 161 | |
| 162 | // The generate bytes response, if set. |
| 163 | std::unique_ptr<QuicBackendResponse> generate_bytes_response_ |
| 164 | QUIC_GUARDED_BY(response_mutex_); |
| 165 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 166 | // Protects against concurrent access from test threads setting responses, and |
| 167 | // server threads accessing those responses. |
| 168 | mutable QuicMutex response_mutex_; |
| 169 | bool cache_initialized_; |
| 170 | |
| 171 | bool enable_webtransport_ = false; |
| 172 | }; |
| 173 | |
| 174 | } // namespace quic |
| 175 | |
| 176 | #endif // QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ |