You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
11 KiB
278 lines
11 KiB
// 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 LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
|
|
#define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <queue>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <base/callback.h>
|
|
#include <base/location.h>
|
|
#include <base/values.h>
|
|
#include <brillo/http/http_transport.h>
|
|
#include <brillo/http/http_utils.h>
|
|
|
|
namespace brillo {
|
|
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();
|
|
~Transport() override;
|
|
|
|
// Server handler callback signature.
|
|
using HandlerCallback =
|
|
base::Callback<void(const ServerRequest&, ServerResponse*)>;
|
|
|
|
// 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; }
|
|
|
|
// For tests that wish to simulate critical transport errors, this method
|
|
// can be used to specify the error to be returned when creating a connection.
|
|
void SetCreateConnectionError(brillo::ErrorPtr create_connection_error) {
|
|
create_connection_error_ = std::move(create_connection_error);
|
|
}
|
|
|
|
// For tests that really need async operations with message loop, call this
|
|
// function with true.
|
|
void SetAsyncMode(bool async) { async_ = async; }
|
|
|
|
// Pops one callback from the top of |async_callback_queue_| and invokes it.
|
|
// Returns false if the queue is empty.
|
|
bool HandleOneAsyncRequest();
|
|
|
|
// Invokes all the callbacks currently queued in |async_callback_queue_|.
|
|
void HandleAllAsyncRequests();
|
|
|
|
// Overrides from http::Transport.
|
|
std::shared_ptr<http::Connection> CreateConnection(
|
|
const std::string& url,
|
|
const std::string& method,
|
|
const HeaderList& headers,
|
|
const std::string& user_agent,
|
|
const std::string& referer,
|
|
brillo::ErrorPtr* error) override;
|
|
|
|
void RunCallbackAsync(const base::Location& from_here,
|
|
const base::Closure& callback) override;
|
|
|
|
RequestID StartAsyncTransfer(http::Connection* connection,
|
|
const SuccessCallback& success_callback,
|
|
const ErrorCallback& error_callback) override;
|
|
|
|
bool CancelRequest(RequestID request_id) override;
|
|
|
|
void SetDefaultTimeout(base::TimeDelta timeout) override;
|
|
|
|
void SetLocalIpAddress(const std::string& /* ip_address */) override {}
|
|
|
|
void ResolveHostToIp(const std::string& host,
|
|
uint16_t port,
|
|
const std::string& ip_address) override {}
|
|
|
|
protected:
|
|
void ClearHost() 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};
|
|
bool async_{false};
|
|
// A list of queued callbacks that need to be called at some point.
|
|
// Call HandleOneAsyncRequest() or HandleAllAsyncRequests() to invoke them.
|
|
std::queue<base::Closure> async_callback_queue_;
|
|
|
|
// Fake error to be returned from CreateConnection method.
|
|
brillo::ErrorPtr create_connection_error_;
|
|
|
|
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 SetData(StreamPtr stream);
|
|
const std::vector<uint8_t>& GetData() const { return data_; }
|
|
std::string GetDataAsString() const;
|
|
std::unique_ptr<base::DictionaryValue> GetDataAsJson() const;
|
|
// Parses the data into a JSON object and writes it back to JSON to normalize
|
|
// its string representation (no pretty print, extra spaces, etc).
|
|
std::string GetDataAsNormalizedJsonString() const;
|
|
|
|
// Add/retrieve request/response HTTP headers.
|
|
void AddHeaders(const HeaderList& headers);
|
|
std::string GetHeader(const std::string& header_name) const;
|
|
const std::multimap<std::string, std::string>& GetHeaders() const {
|
|
return headers_;
|
|
}
|
|
|
|
protected:
|
|
// Data buffer.
|
|
std::vector<uint8_t> data_;
|
|
// Header map.
|
|
std::multimap<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 std::string& mime_type);
|
|
// Reply with text body.
|
|
void ReplyText(int status_code,
|
|
const std::string& text,
|
|
const std::string& 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 std::string& 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 std::string& 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 brillo
|
|
|
|
#endif // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
|