• 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 <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.
GetRequestCount()65   int GetRequestCount() const { return request_count_; }
ResetRequestCount()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.
SetCreateConnectionError(brillo::ErrorPtr create_connection_error)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.
SetAsyncMode(bool async)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 base::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 
SetLocalIpAddress(const std::string &)105   void SetLocalIpAddress(const std::string& /* ip_address */) override {}
106 
107  private:
108   // A list of user-supplied request handlers.
109   std::map<std::string, HandlerCallback> handlers_;
110   // Counter incremented each time a request is made.
111   int request_count_{0};
112   bool async_{false};
113   // A list of queued callbacks that need to be called at some point.
114   // Call HandleOneAsyncRequest() or HandleAllAsyncRequests() to invoke them.
115   std::queue<base::Closure> async_callback_queue_;
116 
117   // Fake error to be returned from CreateConnection method.
118   brillo::ErrorPtr create_connection_error_;
119 
120   DISALLOW_COPY_AND_ASSIGN(Transport);
121 };
122 
123 ///////////////////////////////////////////////////////////////////////////////
124 // A base class for ServerRequest and ServerResponse. It provides common
125 // functionality to work with request/response HTTP headers and data.
126 ///////////////////////////////////////////////////////////////////////////////
127 class ServerRequestResponseBase {
128  public:
129   ServerRequestResponseBase() = default;
130 
131   // Add/retrieve request/response body data.
132   void SetData(StreamPtr stream);
GetData()133   const std::vector<uint8_t>& GetData() const { return data_; }
134   std::string GetDataAsString() const;
135   std::unique_ptr<base::DictionaryValue> GetDataAsJson() const;
136   // Parses the data into a JSON object and writes it back to JSON to normalize
137   // its string representation (no pretty print, extra spaces, etc).
138   std::string GetDataAsNormalizedJsonString() const;
139 
140   // Add/retrieve request/response HTTP headers.
141   void AddHeaders(const HeaderList& headers);
142   std::string GetHeader(const std::string& header_name) const;
GetHeaders()143   const std::multimap<std::string, std::string>& GetHeaders() const {
144     return headers_;
145   }
146 
147  protected:
148   // Data buffer.
149   std::vector<uint8_t> data_;
150   // Header map.
151   std::multimap<std::string, std::string> headers_;
152 
153  private:
154   DISALLOW_COPY_AND_ASSIGN(ServerRequestResponseBase);
155 };
156 
157 ///////////////////////////////////////////////////////////////////////////////
158 // A container class that encapsulates all the HTTP server request information.
159 ///////////////////////////////////////////////////////////////////////////////
160 class ServerRequest : public ServerRequestResponseBase {
161  public:
162   ServerRequest(const std::string& url, const std::string& method);
163 
164   // Get the actual request URL. Does not include the query string or fragment.
GetURL()165   const std::string& GetURL() const { return url_; }
166   // Get the request method.
GetMethod()167   const std::string& GetMethod() const { return method_; }
168   // Get the POST/GET request parameters. These are parsed query string
169   // parameters from the URL. In addition, for POST requests with
170   // application/x-www-form-urlencoded content type, the request body is also
171   // parsed and individual fields can be accessed through this method.
172   std::string GetFormField(const std::string& field_name) const;
173 
174  private:
175   // Request URL (without query string or URL fragment).
176   std::string url_;
177   // Request method
178   std::string method_;
179   // List of available request data form fields.
180   mutable std::map<std::string, std::string> form_fields_;
181   // Flag used on first request to GetFormField to parse the body of HTTP POST
182   // request with application/x-www-form-urlencoded content.
183   mutable bool form_fields_parsed_ = false;
184 
185   DISALLOW_COPY_AND_ASSIGN(ServerRequest);
186 };
187 
188 ///////////////////////////////////////////////////////////////////////////////
189 // A container class that encapsulates all the HTTP server response information.
190 // The request handler will use this class to provide a response to the caller.
191 // Call the Reply() or the appropriate ReplyNNN() specialization to provide
192 // the response data. Additional calls to AddHeaders() can be made to provide
193 // custom response headers. The Reply-methods will already provide the
194 // following response headers:
195 //    Content-Length
196 //    Content-Type
197 ///////////////////////////////////////////////////////////////////////////////
198 class ServerResponse : public ServerRequestResponseBase {
199  public:
200   ServerResponse() = default;
201 
202   // Generic reply method.
203   void Reply(int status_code,
204              const void* data,
205              size_t data_size,
206              const std::string& mime_type);
207   // Reply with text body.
208   void ReplyText(int status_code,
209                  const std::string& text,
210                  const std::string& mime_type);
211   // Reply with JSON object. The content type will be "application/json".
212   void ReplyJson(int status_code, const base::Value* json);
213   // Special form for JSON response for simple objects that have a flat
214   // list of key-value pairs of string type.
215   void ReplyJson(int status_code, const FormFieldList& fields);
216 
217   // Specialized overload to send the binary data as an array of simple
218   // data elements. Only trivial data types (scalars, POD structures, etc)
219   // can be used.
220   template<typename T>
Reply(int status_code,const std::vector<T> & data,const std::string & mime_type)221   void Reply(int status_code,
222              const std::vector<T>& data,
223              const std::string& mime_type) {
224     // Make sure T doesn't have virtual functions, custom constructors, etc.
225     static_assert(std::is_trivial<T>::value, "Only simple data is supported");
226     Reply(status_code, data.data(), data.size() * sizeof(T), mime_type);
227   }
228 
229   // Specialized overload to send the binary data.
230   // Only trivial data types (scalars, POD structures, etc) can be used.
231   template<typename T>
Reply(int status_code,const T & data,const std::string & mime_type)232   void Reply(int status_code, const T& data, const std::string& mime_type) {
233     // Make sure T doesn't have virtual functions, custom constructors, etc.
234     static_assert(std::is_trivial<T>::value, "Only simple data is supported");
235     Reply(status_code, &data, sizeof(T), mime_type);
236   }
237 
238   // For handlers that want to simulate versions of HTTP protocol other
239   // than HTTP/1.1, call this method with the custom version string,
240   // for example "HTTP/1.0".
SetProtocolVersion(const std::string & protocol_version)241   void SetProtocolVersion(const std::string& protocol_version) {
242     protocol_version_ = protocol_version;
243   }
244 
245  protected:
246   // These methods are helpers to implement corresponding functionality
247   // of fake::Connection.
248   friend class Connection;
249   // Helper for fake::Connection::GetResponseStatusCode().
GetStatusCode()250   int GetStatusCode() const { return status_code_; }
251   // Helper for fake::Connection::GetResponseStatusText().
252   std::string GetStatusText() const;
253   // Helper for fake::Connection::GetProtocolVersion().
GetProtocolVersion()254   std::string GetProtocolVersion() const { return protocol_version_; }
255 
256  private:
257   int status_code_ = 0;
258   std::string protocol_version_ = "HTTP/1.1";
259 
260   DISALLOW_COPY_AND_ASSIGN(ServerResponse);
261 };
262 
263 }  // namespace fake
264 }  // namespace http
265 }  // namespace brillo
266 
267 #endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
268