|  | // Copyright 2014 The Chromium OS 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 BUFFET_HTTP_TRANSPORT_FAKE_H_ | 
|  | #define BUFFET_HTTP_TRANSPORT_FAKE_H_ | 
|  |  | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <type_traits> | 
|  | #include <vector> | 
|  |  | 
|  | #include <base/callback.h> | 
|  | #include <base/values.h> | 
|  |  | 
|  | #include "buffet/http_transport.h" | 
|  | #include "buffet/http_utils.h" | 
|  |  | 
|  | namespace buffet { | 
|  | namespace http { | 
|  | namespace fake { | 
|  |  | 
|  | class ServerRequest; | 
|  | class ServerResponse; | 
|  | class Connection; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // A fake implementation of http::Transport that simulates HTTP communication | 
|  | // with a server. | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | class Transport : public http::Transport { | 
|  | public: | 
|  | Transport(); | 
|  | virtual ~Transport(); | 
|  |  | 
|  | // Server handler callback signature. | 
|  | typedef base::Callback<void(const ServerRequest&, ServerResponse*)> | 
|  | HandlerCallback; | 
|  |  | 
|  | // This method allows the test code to provide a callback to handle requests | 
|  | // for specific URL/HTTP-verb combination. When a specific |method| request | 
|  | // is made on the given |url|, the |handler| will be invoked and all the | 
|  | // request data will be filled in the |ServerRequest| parameter. Any server | 
|  | // response should be returned through the |ServerResponse| parameter. | 
|  | // Either |method| or |url| (or both) can be specified as "*" to handle | 
|  | // any requests. So, ("http://localhost","*") will handle any request type | 
|  | // on that URL and ("*","GET") will handle any GET requests. | 
|  | // The lookup starts with the most specific data pair to the catch-all (*,*). | 
|  | void AddHandler(const std::string& url, const std::string& method, | 
|  | const HandlerCallback& handler); | 
|  | // Simple version of AddHandler. AddSimpleReplyHandler just returns the | 
|  | // specified text response of given MIME type. | 
|  | void AddSimpleReplyHandler(const std::string& url, | 
|  | const std::string& method, | 
|  | int status_code, | 
|  | const std::string& reply_text, | 
|  | const std::string& mime_type); | 
|  | // Retrieve a handler for specific |url| and request |method|. | 
|  | HandlerCallback GetHandler(const std::string& url, | 
|  | const std::string& method) const; | 
|  |  | 
|  | // For tests that want to assert on the number of HTTP requests sent, | 
|  | // these methods can be used to do just that. | 
|  | int GetRequestCount() const { return request_count_; } | 
|  | void ResetRequestCount() { request_count_ = 0; } | 
|  |  | 
|  | // Overload from http::Transport | 
|  | virtual std::unique_ptr<http::Connection> CreateConnection( | 
|  | std::shared_ptr<http::Transport> transport, | 
|  | const std::string& url, | 
|  | const std::string& method, | 
|  | const HeaderList& headers, | 
|  | const std::string& user_agent, | 
|  | const std::string& referer, | 
|  | ErrorPtr* error) override; | 
|  |  | 
|  | private: | 
|  | // A list of user-supplied request handlers. | 
|  | std::map<std::string, HandlerCallback> handlers_; | 
|  | // Counter incremented each time a request is made. | 
|  | int request_count_ = 0; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(Transport); | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // A base class for ServerRequest and ServerResponse. It provides common | 
|  | // functionality to work with request/response HTTP headers and data. | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | class ServerRequestResponseBase { | 
|  | public: | 
|  | ServerRequestResponseBase() = default; | 
|  |  | 
|  | // Add/retrieve request/response body data. | 
|  | void AddData(const void* data, size_t data_size); | 
|  | const std::vector<unsigned char>& GetData() const { return data_; } | 
|  | std::string GetDataAsString() const; | 
|  | std::unique_ptr<base::DictionaryValue> GetDataAsJson() const; | 
|  |  | 
|  | // Add/retrieve request/response HTTP headers. | 
|  | void AddHeaders(const HeaderList& headers); | 
|  | std::string GetHeader(const std::string& header_name) const; | 
|  | const std::map<std::string, std::string>& GetHeaders() const { | 
|  | return headers_; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // Data buffer. | 
|  | std::vector<unsigned char> data_; | 
|  | // Header map. | 
|  | std::map<std::string, std::string> headers_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ServerRequestResponseBase); | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // A container class that encapsulates all the HTTP server request information. | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | class ServerRequest : public ServerRequestResponseBase { | 
|  | public: | 
|  | ServerRequest(const std::string& url, const std::string& method); | 
|  |  | 
|  | // Get the actual request URL. Does not include the query string or fragment. | 
|  | const std::string& GetURL() const { return url_; } | 
|  | // Get the request method. | 
|  | const std::string& GetMethod() const { return method_; } | 
|  | // Get the POST/GET request parameters. These are parsed query string | 
|  | // parameters from the URL. In addition, for POST requests with | 
|  | // application/x-www-form-urlencoded content type, the request body is also | 
|  | // parsed and individual fields can be accessed through this method. | 
|  | std::string GetFormField(const std::string& field_name) const; | 
|  |  | 
|  | private: | 
|  | // Request URL (without query string or URL fragment). | 
|  | std::string url_; | 
|  | // Request method | 
|  | std::string method_; | 
|  | // List of available request data form fields. | 
|  | mutable std::map<std::string, std::string> form_fields_; | 
|  | // Flag used on first request to GetFormField to parse the body of HTTP POST | 
|  | // request with application/x-www-form-urlencoded content. | 
|  | mutable bool form_fields_parsed_ = false; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ServerRequest); | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // A container class that encapsulates all the HTTP server response information. | 
|  | // The request handler will use this class to provide a response to the caller. | 
|  | // Call the Reply() or the appropriate ReplyNNN() specialization to provide | 
|  | // the response data. Additional calls to AddHeaders() can be made to provide | 
|  | // custom response headers. The Reply-methods will already provide the | 
|  | // following response headers: | 
|  | //    Content-Length | 
|  | //    Content-Type | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | class ServerResponse : public ServerRequestResponseBase { | 
|  | public: | 
|  | ServerResponse() = default; | 
|  |  | 
|  | // Generic reply method. | 
|  | void Reply(int status_code, const void* data, size_t data_size, | 
|  | const char* mime_type); | 
|  | // Reply with text body. | 
|  | void ReplyText(int status_code, const std::string& text, | 
|  | const char* mime_type); | 
|  | // Reply with JSON object. The content type will be "application/json". | 
|  | void ReplyJson(int status_code, const base::Value* json); | 
|  | // Special form for JSON response for simple objects that have a flat | 
|  | // list of key-value pairs of string type. | 
|  | void ReplyJson(int status_code, const FormFieldList& fields); | 
|  |  | 
|  | // Specialized overload to send the binary data as an array of simple | 
|  | // data elements. Only trivial data types (scalars, POD structures, etc) | 
|  | // can be used. | 
|  | template<typename T> | 
|  | void Reply(int status_code, const std::vector<T>& data, | 
|  | const char* mime_type) { | 
|  | // Make sure T doesn't have virtual functions, custom constructors, etc. | 
|  | static_assert(std::is_trivial<T>::value, "Only simple data is supported"); | 
|  | Reply(status_code, data.data(), data.size() * sizeof(T), mime_type); | 
|  | } | 
|  |  | 
|  | // Specialized overload to send the binary data. | 
|  | // Only trivial data types (scalars, POD structures, etc) can be used. | 
|  | template<typename T> | 
|  | void Reply(int status_code, const T& data, const char* mime_type) { | 
|  | // Make sure T doesn't have virtual functions, custom constructors, etc. | 
|  | static_assert(std::is_trivial<T>::value, "Only simple data is supported"); | 
|  | Reply(status_code, &data, sizeof(T), mime_type); | 
|  | } | 
|  |  | 
|  | // For handlers that want to simulate versions of HTTP protocol other | 
|  | // than HTTP/1.1, call this method with the custom version string, | 
|  | // for example "HTTP/1.0". | 
|  | void SetProtocolVersion(const std::string& protocol_version) { | 
|  | protocol_version_ = protocol_version; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // These methods are helpers to implement corresponding functionality | 
|  | // of fake::Connection. | 
|  | friend class Connection; | 
|  | // Helper for fake::Connection::GetResponseStatusCode(). | 
|  | int GetStatusCode() const { return status_code_; } | 
|  | // Helper for fake::Connection::GetResponseStatusText(). | 
|  | std::string GetStatusText() const; | 
|  | // Helper for fake::Connection::GetProtocolVersion(). | 
|  | std::string GetProtocolVersion() const { return protocol_version_; } | 
|  |  | 
|  | private: | 
|  | int status_code_ = 0; | 
|  | std::string protocol_version_ = "HTTP/1.1"; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ServerResponse); | 
|  | }; | 
|  |  | 
|  | }  // namespace fake | 
|  | }  // namespace http | 
|  | }  // namespace buffet | 
|  |  | 
|  | #endif  // BUFFET_HTTP_TRANSPORT_FAKE_H_ |