Home | History | Annotate | Download | only in http
      1 // Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
      6 #define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
      7 
      8 #include <map>
      9 #include <queue>
     10 #include <string>
     11 #include <type_traits>
     12 #include <vector>
     13 
     14 #include <base/callback.h>
     15 #include <base/values.h>
     16 #include <brillo/http/http_transport.h>
     17 #include <brillo/http/http_utils.h>
     18 
     19 namespace brillo {
     20 namespace http {
     21 namespace fake {
     22 
     23 class ServerRequest;
     24 class ServerResponse;
     25 class Connection;
     26 
     27 ///////////////////////////////////////////////////////////////////////////////
     28 // A fake implementation of http::Transport that simulates HTTP communication
     29 // with a server.
     30 ///////////////////////////////////////////////////////////////////////////////
     31 class Transport : public http::Transport {
     32  public:
     33   Transport();
     34   ~Transport() override;
     35 
     36   // Server handler callback signature.
     37   using HandlerCallback =
     38       base::Callback<void(const ServerRequest&, ServerResponse*)>;
     39 
     40   // This method allows the test code to provide a callback to handle requests
     41   // for specific URL/HTTP-verb combination. When a specific |method| request
     42   // is made on the given |url|, the |handler| will be invoked and all the
     43   // request data will be filled in the |ServerRequest| parameter. Any server
     44   // response should be returned through the |ServerResponse| parameter.
     45   // Either |method| or |url| (or both) can be specified as "*" to handle
     46   // any requests. So, ("http://localhost","*") will handle any request type
     47   // on that URL and ("*","GET") will handle any GET requests.
     48   // The lookup starts with the most specific data pair to the catch-all (*,*).
     49   void AddHandler(const std::string& url,
     50                   const std::string& method,
     51                   const HandlerCallback& handler);
     52   // Simple version of AddHandler. AddSimpleReplyHandler just returns the
     53   // specified text response of given MIME type.
     54   void AddSimpleReplyHandler(const std::string& url,
     55                              const std::string& method,
     56                              int status_code,
     57                              const std::string& reply_text,
     58                              const std::string& mime_type);
     59   // Retrieve a handler for specific |url| and request |method|.
     60   HandlerCallback GetHandler(const std::string& url,
     61                              const std::string& method) const;
     62 
     63   // For tests that want to assert on the number of HTTP requests sent,
     64   // these methods can be used to do just that.
     65   int GetRequestCount() const { return request_count_; }
     66   void ResetRequestCount() { request_count_ = 0; }
     67 
     68   // For tests that wish to simulate critical transport errors, this method
     69   // can be used to specify the error to be returned when creating a connection.
     70   void SetCreateConnectionError(brillo::ErrorPtr create_connection_error) {
     71     create_connection_error_ = std::move(create_connection_error);
     72   }
     73 
     74   // For tests that really need async operations with message loop, call this
     75   // function with true.
     76   void SetAsyncMode(bool async) { async_ = async; }
     77 
     78   // Pops one callback from the top of |async_callback_queue_| and invokes it.
     79   // Returns false if the queue is empty.
     80   bool HandleOneAsyncRequest();
     81 
     82   // Invokes all the callbacks currently queued in |async_callback_queue_|.
     83   void HandleAllAsyncRequests();
     84 
     85   // Overrides from http::Transport.
     86   std::shared_ptr<http::Connection> CreateConnection(
     87       const std::string& url,
     88       const std::string& method,
     89       const HeaderList& headers,
     90       const std::string& user_agent,
     91       const std::string& referer,
     92       brillo::ErrorPtr* error) override;
     93 
     94   void RunCallbackAsync(const tracked_objects::Location& from_here,
     95                         const base::Closure& callback) override;
     96 
     97   RequestID StartAsyncTransfer(http::Connection* connection,
     98                                const SuccessCallback& success_callback,
     99                                const ErrorCallback& error_callback) override;
    100 
    101   bool CancelRequest(RequestID request_id) override;
    102 
    103   void SetDefaultTimeout(base::TimeDelta timeout) override;
    104 
    105  private:
    106   // A list of user-supplied request handlers.
    107   std::map<std::string, HandlerCallback> handlers_;
    108   // Counter incremented each time a request is made.
    109   int request_count_{0};
    110   bool async_{false};
    111   // A list of queued callbacks that need to be called at some point.
    112   // Call HandleOneAsyncRequest() or HandleAllAsyncRequests() to invoke them.
    113   std::queue<base::Closure> async_callback_queue_;
    114 
    115   // Fake error to be returned from CreateConnection method.
    116   brillo::ErrorPtr create_connection_error_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(Transport);
    119 };
    120 
    121 ///////////////////////////////////////////////////////////////////////////////
    122 // A base class for ServerRequest and ServerResponse. It provides common
    123 // functionality to work with request/response HTTP headers and data.
    124 ///////////////////////////////////////////////////////////////////////////////
    125 class ServerRequestResponseBase {
    126  public:
    127   ServerRequestResponseBase() = default;
    128 
    129   // Add/retrieve request/response body data.
    130   void SetData(StreamPtr stream);
    131   const std::vector<uint8_t>& GetData() const { return data_; }
    132   std::string GetDataAsString() const;
    133   std::unique_ptr<base::DictionaryValue> GetDataAsJson() const;
    134   // Parses the data into a JSON object and writes it back to JSON to normalize
    135   // its string representation (no pretty print, extra spaces, etc).
    136   std::string GetDataAsNormalizedJsonString() const;
    137 
    138   // Add/retrieve request/response HTTP headers.
    139   void AddHeaders(const HeaderList& headers);
    140   std::string GetHeader(const std::string& header_name) const;
    141   const std::multimap<std::string, std::string>& GetHeaders() const {
    142     return headers_;
    143   }
    144 
    145  protected:
    146   // Data buffer.
    147   std::vector<uint8_t> data_;
    148   // Header map.
    149   std::multimap<std::string, std::string> headers_;
    150 
    151  private:
    152   DISALLOW_COPY_AND_ASSIGN(ServerRequestResponseBase);
    153 };
    154 
    155 ///////////////////////////////////////////////////////////////////////////////
    156 // A container class that encapsulates all the HTTP server request information.
    157 ///////////////////////////////////////////////////////////////////////////////
    158 class ServerRequest : public ServerRequestResponseBase {
    159  public:
    160   ServerRequest(const std::string& url, const std::string& method);
    161 
    162   // Get the actual request URL. Does not include the query string or fragment.
    163   const std::string& GetURL() const { return url_; }
    164   // Get the request method.
    165   const std::string& GetMethod() const { return method_; }
    166   // Get the POST/GET request parameters. These are parsed query string
    167   // parameters from the URL. In addition, for POST requests with
    168   // application/x-www-form-urlencoded content type, the request body is also
    169   // parsed and individual fields can be accessed through this method.
    170   std::string GetFormField(const std::string& field_name) const;
    171 
    172  private:
    173   // Request URL (without query string or URL fragment).
    174   std::string url_;
    175   // Request method
    176   std::string method_;
    177   // List of available request data form fields.
    178   mutable std::map<std::string, std::string> form_fields_;
    179   // Flag used on first request to GetFormField to parse the body of HTTP POST
    180   // request with application/x-www-form-urlencoded content.
    181   mutable bool form_fields_parsed_ = false;
    182 
    183   DISALLOW_COPY_AND_ASSIGN(ServerRequest);
    184 };
    185 
    186 ///////////////////////////////////////////////////////////////////////////////
    187 // A container class that encapsulates all the HTTP server response information.
    188 // The request handler will use this class to provide a response to the caller.
    189 // Call the Reply() or the appropriate ReplyNNN() specialization to provide
    190 // the response data. Additional calls to AddHeaders() can be made to provide
    191 // custom response headers. The Reply-methods will already provide the
    192 // following response headers:
    193 //    Content-Length
    194 //    Content-Type
    195 ///////////////////////////////////////////////////////////////////////////////
    196 class ServerResponse : public ServerRequestResponseBase {
    197  public:
    198   ServerResponse() = default;
    199 
    200   // Generic reply method.
    201   void Reply(int status_code,
    202              const void* data,
    203              size_t data_size,
    204              const std::string& mime_type);
    205   // Reply with text body.
    206   void ReplyText(int status_code,
    207                  const std::string& text,
    208                  const std::string& mime_type);
    209   // Reply with JSON object. The content type will be "application/json".
    210   void ReplyJson(int status_code, const base::Value* json);
    211   // Special form for JSON response for simple objects that have a flat
    212   // list of key-value pairs of string type.
    213   void ReplyJson(int status_code, const FormFieldList& fields);
    214 
    215   // Specialized overload to send the binary data as an array of simple
    216   // data elements. Only trivial data types (scalars, POD structures, etc)
    217   // can be used.
    218   template<typename T>
    219   void Reply(int status_code,
    220              const std::vector<T>& data,
    221              const std::string& mime_type) {
    222     // Make sure T doesn't have virtual functions, custom constructors, etc.
    223     static_assert(std::is_trivial<T>::value, "Only simple data is supported");
    224     Reply(status_code, data.data(), data.size() * sizeof(T), mime_type);
    225   }
    226 
    227   // Specialized overload to send the binary data.
    228   // Only trivial data types (scalars, POD structures, etc) can be used.
    229   template<typename T>
    230   void Reply(int status_code, const T& data, const std::string& mime_type) {
    231     // Make sure T doesn't have virtual functions, custom constructors, etc.
    232     static_assert(std::is_trivial<T>::value, "Only simple data is supported");
    233     Reply(status_code, &data, sizeof(T), mime_type);
    234   }
    235 
    236   // For handlers that want to simulate versions of HTTP protocol other
    237   // than HTTP/1.1, call this method with the custom version string,
    238   // for example "HTTP/1.0".
    239   void SetProtocolVersion(const std::string& protocol_version) {
    240     protocol_version_ = protocol_version;
    241   }
    242 
    243  protected:
    244   // These methods are helpers to implement corresponding functionality
    245   // of fake::Connection.
    246   friend class Connection;
    247   // Helper for fake::Connection::GetResponseStatusCode().
    248   int GetStatusCode() const { return status_code_; }
    249   // Helper for fake::Connection::GetResponseStatusText().
    250   std::string GetStatusText() const;
    251   // Helper for fake::Connection::GetProtocolVersion().
    252   std::string GetProtocolVersion() const { return protocol_version_; }
    253 
    254  private:
    255   int status_code_ = 0;
    256   std::string protocol_version_ = "HTTP/1.1";
    257 
    258   DISALLOW_COPY_AND_ASSIGN(ServerResponse);
    259 };
    260 
    261 }  // namespace fake
    262 }  // namespace http
    263 }  // namespace brillo
    264 
    265 #endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
    266