// 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 #include #include #include #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 ` 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& 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 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 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); // 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 GetServerPushResources( std::string request_url); // Implements the functions for interface QuicSimpleServerBackend // |cache_cirectory| can be generated using `wget -p --save-headers `. 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); 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 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> responses_ QUIC_GUARDED_BY(response_mutex_); // The default response for cache misses, if set. std::unique_ptr default_response_ QUIC_GUARDED_BY(response_mutex_); // The generate bytes response, if set. std::unique_ptr generate_bytes_response_ QUIC_GUARDED_BY(response_mutex_); // A map from request URL to associated server push responses (if any). std::multimap 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_