| // Copyright (c) 2012 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. | 
 |  | 
 | #ifndef QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ | 
 | #define QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 | #include <memory> | 
 | #include <vector> | 
 |  | 
 | #include "absl/container/flat_hash_map.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "quic/core/http/spdy_utils.h" | 
 | #include "quic/platform/api/quic_containers.h" | 
 | #include "quic/platform/api/quic_mutex.h" | 
 | #include "quic/tools/quic_backend_response.h" | 
 | #include "quic/tools/quic_simple_server_backend.h" | 
 | #include "quic/tools/quic_url.h" | 
 | #include "spdy/core/spdy_framer.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | // In-memory cache for HTTP responses. | 
 | // Reads from disk cache generated by: | 
 | // `wget -p --save_headers <url>` | 
 | class QuicMemoryCacheBackend : public QuicSimpleServerBackend { | 
 |  public: | 
 |   // Class to manage loading a resource file into memory.  There are | 
 |   // two uses: called by InitializeBackend to load resources | 
 |   // from files, and recursively called when said resources specify | 
 |   // server push associations. | 
 |   class ResourceFile { | 
 |    public: | 
 |     explicit ResourceFile(const std::string& file_name); | 
 |     ResourceFile(const ResourceFile&) = delete; | 
 |     ResourceFile& operator=(const ResourceFile&) = delete; | 
 |     virtual ~ResourceFile(); | 
 |  | 
 |     void Read(); | 
 |  | 
 |     // |base| is |file_name_| with |cache_directory| prefix stripped. | 
 |     void SetHostPathFromBase(absl::string_view base); | 
 |  | 
 |     const std::string& file_name() { return file_name_; } | 
 |  | 
 |     absl::string_view host() { return host_; } | 
 |  | 
 |     absl::string_view path() { return path_; } | 
 |  | 
 |     const spdy::Http2HeaderBlock& spdy_headers() { return spdy_headers_; } | 
 |  | 
 |     absl::string_view body() { return body_; } | 
 |  | 
 |     const std::vector<absl::string_view>& push_urls() { return push_urls_; } | 
 |  | 
 |    private: | 
 |     void HandleXOriginalUrl(); | 
 |     absl::string_view RemoveScheme(absl::string_view url); | 
 |  | 
 |     std::string file_name_; | 
 |     std::string file_contents_; | 
 |     absl::string_view body_; | 
 |     spdy::Http2HeaderBlock spdy_headers_; | 
 |     absl::string_view x_original_url_; | 
 |     std::vector<absl::string_view> push_urls_; | 
 |     std::string host_; | 
 |     std::string path_; | 
 |   }; | 
 |  | 
 |   QuicMemoryCacheBackend(); | 
 |   QuicMemoryCacheBackend(const QuicMemoryCacheBackend&) = delete; | 
 |   QuicMemoryCacheBackend& operator=(const QuicMemoryCacheBackend&) = delete; | 
 |   ~QuicMemoryCacheBackend() override; | 
 |  | 
 |   // Retrieve a response from this cache for a given host and path.. | 
 |   // If no appropriate response exists, nullptr is returned. | 
 |   const QuicBackendResponse* GetResponse(absl::string_view host, | 
 |                                          absl::string_view path) const; | 
 |  | 
 |   // Adds a simple response to the cache.  The response headers will | 
 |   // only contain the "content-length" header with the length of |body|. | 
 |   void AddSimpleResponse(absl::string_view host, | 
 |                          absl::string_view path, | 
 |                          int response_code, | 
 |                          absl::string_view body); | 
 |  | 
 |   // Add a simple response to the cache as AddSimpleResponse() does, and add | 
 |   // some server push resources(resource path, corresponding response status and | 
 |   // path) associated with it. | 
 |   // Push resource implicitly come from the same host. | 
 |   // TODO(b/171463363): Remove. | 
 |   void AddSimpleResponseWithServerPushResources( | 
 |       absl::string_view host, | 
 |       absl::string_view path, | 
 |       int response_code, | 
 |       absl::string_view body, | 
 |       std::list<QuicBackendResponse::ServerPushInfo> push_resources); | 
 |  | 
 |   // Add a response to the cache. | 
 |   void AddResponse(absl::string_view host, | 
 |                    absl::string_view path, | 
 |                    spdy::Http2HeaderBlock response_headers, | 
 |                    absl::string_view response_body); | 
 |  | 
 |   // Add a response, with trailers, to the cache. | 
 |   void AddResponse(absl::string_view host, | 
 |                    absl::string_view path, | 
 |                    spdy::Http2HeaderBlock response_headers, | 
 |                    absl::string_view response_body, | 
 |                    spdy::Http2HeaderBlock response_trailers); | 
 |  | 
 |   // Add a response, with 103 Early Hints, to the cache. | 
 |   void AddResponseWithEarlyHints( | 
 |       absl::string_view host, | 
 |       absl::string_view path, | 
 |       spdy::Http2HeaderBlock response_headers, | 
 |       absl::string_view response_body, | 
 |       const std::vector<spdy::Http2HeaderBlock>& early_hints); | 
 |  | 
 |   // Simulate a special behavior at a particular path. | 
 |   void AddSpecialResponse( | 
 |       absl::string_view host, | 
 |       absl::string_view path, | 
 |       QuicBackendResponse::SpecialResponseType response_type); | 
 |  | 
 |   void AddSpecialResponse( | 
 |       absl::string_view host, | 
 |       absl::string_view path, | 
 |       spdy::Http2HeaderBlock response_headers, | 
 |       absl::string_view response_body, | 
 |       QuicBackendResponse::SpecialResponseType response_type); | 
 |  | 
 |   // Sets a default response in case of cache misses.  Takes ownership of | 
 |   // 'response'. | 
 |   void AddDefaultResponse(QuicBackendResponse* response); | 
 |  | 
 |   // Once called, URLs which have a numeric path will send a dynamically | 
 |   // generated response of that many bytes. | 
 |   void GenerateDynamicResponses(); | 
 |  | 
 |   void EnableWebTransport(); | 
 |  | 
 |   // Find all the server push resources associated with |request_url|. | 
 |   // TODO(b/171463363): Remove. | 
 |   std::list<QuicBackendResponse::ServerPushInfo> GetServerPushResources( | 
 |       std::string request_url); | 
 |  | 
 |   // Implements the functions for interface QuicSimpleServerBackend | 
 |   // |cache_cirectory| can be generated using `wget -p --save-headers <url>`. | 
 |   bool InitializeBackend(const std::string& cache_directory) override; | 
 |   bool IsBackendInitialized() const override; | 
 |   void FetchResponseFromBackend( | 
 |       const spdy::Http2HeaderBlock& request_headers, | 
 |       const std::string& request_body, | 
 |       QuicSimpleServerBackend::RequestHandler* quic_stream) override; | 
 |   void CloseBackendResponseStream( | 
 |       QuicSimpleServerBackend::RequestHandler* quic_stream) override; | 
 |   WebTransportResponse ProcessWebTransportRequest( | 
 |       const spdy::Http2HeaderBlock& request_headers, | 
 |       WebTransportSession* session) override; | 
 |   bool SupportsWebTransport() override { return enable_webtransport_; } | 
 |  | 
 |  private: | 
 |   void AddResponseImpl(absl::string_view host, | 
 |                        absl::string_view path, | 
 |                        QuicBackendResponse::SpecialResponseType response_type, | 
 |                        spdy::Http2HeaderBlock response_headers, | 
 |                        absl::string_view response_body, | 
 |                        spdy::Http2HeaderBlock response_trailers, | 
 |                        const std::vector<spdy::Http2HeaderBlock>& early_hints); | 
 |  | 
 |   std::string GetKey(absl::string_view host, absl::string_view path) const; | 
 |  | 
 |   // Add some server push urls with given responses for specified | 
 |   // request if these push resources are not associated with this request yet. | 
 |   // TODO(b/171463363): Remove. | 
 |   void MaybeAddServerPushResources( | 
 |       absl::string_view request_host, | 
 |       absl::string_view request_path, | 
 |       std::list<QuicBackendResponse::ServerPushInfo> push_resources); | 
 |  | 
 |   // Check if push resource(push_host/push_path) associated with given request | 
 |   // url already exists in server push map. | 
 |   // TODO(b/171463363): Remove. | 
 |   bool PushResourceExistsInCache(std::string original_request_url, | 
 |                                  QuicBackendResponse::ServerPushInfo resource); | 
 |  | 
 |   // Cached responses. | 
 |   absl::flat_hash_map<std::string, std::unique_ptr<QuicBackendResponse>> | 
 |       responses_ QUIC_GUARDED_BY(response_mutex_); | 
 |  | 
 |   // The default response for cache misses, if set. | 
 |   std::unique_ptr<QuicBackendResponse> default_response_ | 
 |       QUIC_GUARDED_BY(response_mutex_); | 
 |  | 
 |   // The generate bytes response, if set. | 
 |   std::unique_ptr<QuicBackendResponse> generate_bytes_response_ | 
 |       QUIC_GUARDED_BY(response_mutex_); | 
 |  | 
 |   // A map from request URL to associated server push responses (if any). | 
 |   // TODO(b/171463363): Remove. | 
 |   std::multimap<std::string, QuicBackendResponse::ServerPushInfo> | 
 |       server_push_resources_ QUIC_GUARDED_BY(response_mutex_); | 
 |  | 
 |   // Protects against concurrent access from test threads setting responses, and | 
 |   // server threads accessing those responses. | 
 |   mutable QuicMutex response_mutex_; | 
 |   bool cache_initialized_; | 
 |  | 
 |   bool enable_webtransport_ = false; | 
 | }; | 
 |  | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ |