| // 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. |
| 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(); |
| |
| // Find all the server push resources associated with |request_url|. |
| 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_server_stream) override; |
| void CloseBackendResponseStream( |
| QuicSimpleServerBackend::RequestHandler* quic_server_stream) override; |
| |
| 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. |
| 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. |
| 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). |
| 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_; |
| }; |
| |
| } // namespace quic |
| |
| #endif // QUICHE_QUIC_TOOLS_QUIC_MEMORY_CACHE_BACKEND_H_ |