blob: 71acd3ef2e4f504eb78fab59dbbd077ff981308f [file] [log] [blame]
Alex Vakulenko9cd5e272014-04-25 17:26:11 -07001// 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 BUFFET_HTTP_TRANSPORT_FAKE_H_
6#define BUFFET_HTTP_TRANSPORT_FAKE_H_
7
Alex Vakulenkob3aac252014-05-07 17:35:24 -07008#include <map>
9#include <string>
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070010#include <type_traits>
Alex Vakulenkob3aac252014-05-07 17:35:24 -070011#include <vector>
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070012
13#include <base/callback.h>
14#include <base/values.h>
15
16#include "buffet/http_transport.h"
Alex Vakulenko8e34d392014-04-29 11:02:56 -070017#include "buffet/http_utils.h"
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070018
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070019namespace buffet {
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070020namespace http {
21namespace fake {
22
23class ServerRequest;
24class ServerResponse;
25class Connection;
26
27///////////////////////////////////////////////////////////////////////////////
28// A fake implementation of http::Transport that simulates HTTP communication
29// with a server.
30///////////////////////////////////////////////////////////////////////////////
31class Transport : public http::Transport {
32 public:
33 Transport();
34 virtual ~Transport();
35
36 // Server handler callback signature.
37 typedef base::Callback<void(const ServerRequest&, ServerResponse*)>
38 HandlerCallback;
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, const std::string& method,
50 const HandlerCallback& handler);
Alex Vakulenko8e34d392014-04-29 11:02:56 -070051 // Simple version of AddHandler. AddSimpleReplyHandler just returns the
52 // specified text response of given MIME type.
53 void AddSimpleReplyHandler(const std::string& url,
54 const std::string& method,
55 int status_code,
56 const std::string& reply_text,
57 const std::string& mime_type);
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070058 // Retrieve a handler for specific |url| and request |method|.
59 HandlerCallback GetHandler(const std::string& url,
60 const std::string& method) const;
61
Alex Vakulenko8e34d392014-04-29 11:02:56 -070062 // For tests that want to assert on the number of HTTP requests sent,
63 // these methods can be used to do just that.
64 int GetRequestCount() const { return request_count_; }
65 void ResetRequestCount() { request_count_ = 0; }
66
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070067 // Overload from http::Transport
Alex Vakulenko5a9e7182014-08-11 15:59:58 -070068 std::unique_ptr<http::Connection> CreateConnection(
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070069 std::shared_ptr<http::Transport> transport,
70 const std::string& url,
71 const std::string& method,
72 const HeaderList& headers,
73 const std::string& user_agent,
74 const std::string& referer,
Alex Vakulenkob3aac252014-05-07 17:35:24 -070075 ErrorPtr* error) override;
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070076
77 private:
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070078 // A list of user-supplied request handlers.
79 std::map<std::string, HandlerCallback> handlers_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -070080 // Counter incremented each time a request is made.
81 int request_count_ = 0;
Alex Vakulenkob3aac252014-05-07 17:35:24 -070082
83 DISALLOW_COPY_AND_ASSIGN(Transport);
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070084};
85
86///////////////////////////////////////////////////////////////////////////////
87// A base class for ServerRequest and ServerResponse. It provides common
88// functionality to work with request/response HTTP headers and data.
89///////////////////////////////////////////////////////////////////////////////
90class ServerRequestResponseBase {
91 public:
92 ServerRequestResponseBase() = default;
93
94 // Add/retrieve request/response body data.
95 void AddData(const void* data, size_t data_size);
96 const std::vector<unsigned char>& GetData() const { return data_; }
97 std::string GetDataAsString() const;
Alex Vakulenko8e34d392014-04-29 11:02:56 -070098 std::unique_ptr<base::DictionaryValue> GetDataAsJson() const;
Alex Vakulenko9cd5e272014-04-25 17:26:11 -070099
100 // Add/retrieve request/response HTTP headers.
101 void AddHeaders(const HeaderList& headers);
102 std::string GetHeader(const std::string& header_name) const;
Alex Vakulenko28b31f52014-04-28 12:40:05 -0700103 const std::map<std::string, std::string>& GetHeaders() const {
104 return headers_;
105 }
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700106
107 protected:
108 // Data buffer.
109 std::vector<unsigned char> data_;
110 // Header map.
111 std::map<std::string, std::string> headers_;
112
113 private:
114 DISALLOW_COPY_AND_ASSIGN(ServerRequestResponseBase);
115};
116
117///////////////////////////////////////////////////////////////////////////////
118// A container class that encapsulates all the HTTP server request information.
119///////////////////////////////////////////////////////////////////////////////
120class ServerRequest : public ServerRequestResponseBase {
121 public:
122 ServerRequest(const std::string& url, const std::string& method);
123
124 // Get the actual request URL. Does not include the query string or fragment.
125 const std::string& GetURL() const { return url_; }
126 // Get the request method.
127 const std::string& GetMethod() const { return method_; }
128 // Get the POST/GET request parameters. These are parsed query string
129 // parameters from the URL. In addition, for POST requests with
130 // application/x-www-form-urlencoded content type, the request body is also
131 // parsed and individual fields can be accessed through this method.
132 std::string GetFormField(const std::string& field_name) const;
133
134 private:
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700135 // Request URL (without query string or URL fragment).
136 std::string url_;
137 // Request method
138 std::string method_;
139 // List of available request data form fields.
140 mutable std::map<std::string, std::string> form_fields_;
141 // Flag used on first request to GetFormField to parse the body of HTTP POST
142 // request with application/x-www-form-urlencoded content.
143 mutable bool form_fields_parsed_ = false;
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700144
145 DISALLOW_COPY_AND_ASSIGN(ServerRequest);
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700146};
147
148///////////////////////////////////////////////////////////////////////////////
149// A container class that encapsulates all the HTTP server response information.
150// The request handler will use this class to provide a response to the caller.
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700151// Call the Reply() or the appropriate ReplyNNN() specialization to provide
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700152// the response data. Additional calls to AddHeaders() can be made to provide
153// custom response headers. The Reply-methods will already provide the
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700154// following response headers:
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700155// Content-Length
156// Content-Type
157///////////////////////////////////////////////////////////////////////////////
158class ServerResponse : public ServerRequestResponseBase {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700159 public:
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700160 ServerResponse() = default;
161
162 // Generic reply method.
163 void Reply(int status_code, const void* data, size_t data_size,
164 const char* mime_type);
165 // Reply with text body.
166 void ReplyText(int status_code, const std::string& text,
167 const char* mime_type);
168 // Reply with JSON object. The content type will be "application/json".
169 void ReplyJson(int status_code, const base::Value* json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700170 // Special form for JSON response for simple objects that have a flat
171 // list of key-value pairs of string type.
172 void ReplyJson(int status_code, const FormFieldList& fields);
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700173
174 // Specialized overload to send the binary data as an array of simple
175 // data elements. Only trivial data types (scalars, POD structures, etc)
176 // can be used.
177 template<typename T>
178 void Reply(int status_code, const std::vector<T>& data,
179 const char* mime_type) {
180 // Make sure T doesn't have virtual functions, custom constructors, etc.
181 static_assert(std::is_trivial<T>::value, "Only simple data is supported");
182 Reply(status_code, data.data(), data.size() * sizeof(T), mime_type);
183 }
184
185 // Specialized overload to send the binary data.
186 // Only trivial data types (scalars, POD structures, etc) can be used.
187 template<typename T>
188 void Reply(int status_code, const T& data, const char* mime_type) {
189 // Make sure T doesn't have virtual functions, custom constructors, etc.
190 static_assert(std::is_trivial<T>::value, "Only simple data is supported");
191 Reply(status_code, &data, sizeof(T), mime_type);
192 }
193
194 // For handlers that want to simulate versions of HTTP protocol other
195 // than HTTP/1.1, call this method with the custom version string,
196 // for example "HTTP/1.0".
197 void SetProtocolVersion(const std::string& protocol_version) {
198 protocol_version_ = protocol_version;
199 }
200
201 protected:
202 // These methods are helpers to implement corresponding functionality
203 // of fake::Connection.
204 friend class Connection;
205 // Helper for fake::Connection::GetResponseStatusCode().
206 int GetStatusCode() const { return status_code_; }
207 // Helper for fake::Connection::GetResponseStatusText().
208 std::string GetStatusText() const;
209 // Helper for fake::Connection::GetProtocolVersion().
210 std::string GetProtocolVersion() const { return protocol_version_; }
211
212 private:
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700213 int status_code_ = 0;
214 std::string protocol_version_ = "HTTP/1.1";
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700215
216 DISALLOW_COPY_AND_ASSIGN(ServerResponse);
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700217};
218
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700219} // namespace fake
220} // namespace http
Alex Vakulenkoaf23b322014-05-08 16:25:45 -0700221} // namespace buffet
Alex Vakulenko9cd5e272014-04-25 17:26:11 -0700222
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700223#endif // BUFFET_HTTP_TRANSPORT_FAKE_H_