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