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.

382 lines
14 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_REQUEST_H_
#define LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/macros.h>
#include <brillo/brillo_export.h>
#include <brillo/errors/error.h>
#include <brillo/http/http_connection.h>
#include <brillo/http/http_transport.h>
namespace brillo {
namespace http {
// HTTP request verbs
namespace request_type {
BRILLO_EXPORT extern const char kOptions[];
BRILLO_EXPORT extern const char kGet[];
BRILLO_EXPORT extern const char kHead[];
BRILLO_EXPORT extern const char kPost[];
BRILLO_EXPORT extern const char kPut[];
BRILLO_EXPORT extern const char kPatch[]; // Non-standard HTTP/1.1 verb
BRILLO_EXPORT extern const char kDelete[];
BRILLO_EXPORT extern const char kTrace[];
BRILLO_EXPORT extern const char kConnect[];
BRILLO_EXPORT extern const char kCopy[]; // Non-standard HTTP/1.1 verb
BRILLO_EXPORT extern const char kMove[]; // Non-standard HTTP/1.1 verb
} // namespace request_type
// HTTP request header names
namespace request_header {
BRILLO_EXPORT extern const char kAccept[];
BRILLO_EXPORT extern const char kAcceptCharset[];
BRILLO_EXPORT extern const char kAcceptEncoding[];
BRILLO_EXPORT extern const char kAcceptLanguage[];
BRILLO_EXPORT extern const char kAllow[];
BRILLO_EXPORT extern const char kAuthorization[];
BRILLO_EXPORT extern const char kCacheControl[];
BRILLO_EXPORT extern const char kConnection[];
BRILLO_EXPORT extern const char kContentEncoding[];
BRILLO_EXPORT extern const char kContentLanguage[];
BRILLO_EXPORT extern const char kContentLength[];
BRILLO_EXPORT extern const char kContentLocation[];
BRILLO_EXPORT extern const char kContentMd5[];
BRILLO_EXPORT extern const char kContentRange[];
BRILLO_EXPORT extern const char kContentType[];
BRILLO_EXPORT extern const char kCookie[];
BRILLO_EXPORT extern const char kDate[];
BRILLO_EXPORT extern const char kExpect[];
BRILLO_EXPORT extern const char kExpires[];
BRILLO_EXPORT extern const char kFrom[];
BRILLO_EXPORT extern const char kHost[];
BRILLO_EXPORT extern const char kIfMatch[];
BRILLO_EXPORT extern const char kIfModifiedSince[];
BRILLO_EXPORT extern const char kIfNoneMatch[];
BRILLO_EXPORT extern const char kIfRange[];
BRILLO_EXPORT extern const char kIfUnmodifiedSince[];
BRILLO_EXPORT extern const char kLastModified[];
BRILLO_EXPORT extern const char kMaxForwards[];
BRILLO_EXPORT extern const char kPragma[];
BRILLO_EXPORT extern const char kProxyAuthorization[];
BRILLO_EXPORT extern const char kRange[];
BRILLO_EXPORT extern const char kReferer[];
BRILLO_EXPORT extern const char kTE[];
BRILLO_EXPORT extern const char kTrailer[];
BRILLO_EXPORT extern const char kTransferEncoding[];
BRILLO_EXPORT extern const char kUpgrade[];
BRILLO_EXPORT extern const char kUserAgent[];
BRILLO_EXPORT extern const char kVia[];
BRILLO_EXPORT extern const char kWarning[];
} // namespace request_header
// HTTP response header names
namespace response_header {
BRILLO_EXPORT extern const char kAcceptRanges[];
BRILLO_EXPORT extern const char kAge[];
BRILLO_EXPORT extern const char kAllow[];
BRILLO_EXPORT extern const char kCacheControl[];
BRILLO_EXPORT extern const char kConnection[];
BRILLO_EXPORT extern const char kContentEncoding[];
BRILLO_EXPORT extern const char kContentLanguage[];
BRILLO_EXPORT extern const char kContentLength[];
BRILLO_EXPORT extern const char kContentLocation[];
BRILLO_EXPORT extern const char kContentMd5[];
BRILLO_EXPORT extern const char kContentRange[];
BRILLO_EXPORT extern const char kContentType[];
BRILLO_EXPORT extern const char kDate[];
BRILLO_EXPORT extern const char kETag[];
BRILLO_EXPORT extern const char kExpires[];
BRILLO_EXPORT extern const char kLastModified[];
BRILLO_EXPORT extern const char kLocation[];
BRILLO_EXPORT extern const char kPragma[];
BRILLO_EXPORT extern const char kProxyAuthenticate[];
BRILLO_EXPORT extern const char kRetryAfter[];
BRILLO_EXPORT extern const char kServer[];
BRILLO_EXPORT extern const char kSetCookie[];
BRILLO_EXPORT extern const char kTrailer[];
BRILLO_EXPORT extern const char kTransferEncoding[];
BRILLO_EXPORT extern const char kUpgrade[];
BRILLO_EXPORT extern const char kVary[];
BRILLO_EXPORT extern const char kVia[];
BRILLO_EXPORT extern const char kWarning[];
BRILLO_EXPORT extern const char kWwwAuthenticate[];
} // namespace response_header
// HTTP request status (error) codes
namespace status_code {
// OK to continue with request
static const int Continue = 100;
// Server has switched protocols in upgrade header
static const int SwitchProtocols = 101;
// Request completed
static const int Ok = 200;
// Object created, reason = new URI
static const int Created = 201;
// Async completion (TBS)
static const int Accepted = 202;
// Partial completion
static const int Partial = 203;
// No info to return
static const int NoContent = 204;
// Request completed, but clear form
static const int ResetContent = 205;
// Partial GET fulfilled
static const int PartialContent = 206;
// Server couldn't decide what to return
static const int Ambiguous = 300;
// Object permanently moved
static const int Moved = 301;
// Object temporarily moved
static const int Redirect = 302;
// Redirection w/ new access method
static const int RedirectMethod = 303;
// If-Modified-Since was not modified
static const int NotModified = 304;
// Redirection to proxy, location header specifies proxy to use
static const int UseProxy = 305;
// HTTP/1.1: keep same verb
static const int RedirectKeepVerb = 307;
// Invalid syntax
static const int BadRequest = 400;
// Access denied
static const int Denied = 401;
// Payment required
static const int PaymentRequired = 402;
// Request forbidden
static const int Forbidden = 403;
// Object not found
static const int NotFound = 404;
// Method is not allowed
static const int BadMethod = 405;
// No response acceptable to client found
static const int NoneAcceptable = 406;
// Proxy authentication required
static const int ProxyAuthRequired = 407;
// Server timed out waiting for request
static const int RequestTimeout = 408;
// User should resubmit with more info
static const int Conflict = 409;
// The resource is no longer available
static const int Gone = 410;
// The server refused to accept request w/o a length
static const int LengthRequired = 411;
// Precondition given in request failed
static const int PrecondionFailed = 412;
// Request entity was too large
static const int RequestTooLarge = 413;
// Request URI too long
static const int UriTooLong = 414;
// Unsupported media type
static const int UnsupportedMedia = 415;
// Retry after doing the appropriate action.
static const int RetryWith = 449;
// Internal server error
static const int InternalServerError = 500;
// Request not supported
static const int NotSupported = 501;
// Error response received from gateway
static const int BadGateway = 502;
// Temporarily overloaded
static const int ServiceUnavailable = 503;
// Timed out waiting for gateway
static const int GatewayTimeout = 504;
// HTTP version not supported
static const int VersionNotSupported = 505;
} // namespace status_code
class Response; // Just a forward declaration.
class FormData;
///////////////////////////////////////////////////////////////////////////////
// Request class is the main object used to set up and initiate an HTTP
// communication session. It is used to specify the HTTP request method,
// request URL and many optional parameters (such as HTTP headers, user agent,
// referer URL and so on.
//
// Once everything is setup, GetResponse() method is used to send the request
// and obtain the server response. The returned Response object can be
// used to inspect the response code, HTTP headers and/or response body.
///////////////////////////////////////////////////////////////////////////////
class BRILLO_EXPORT Request final {
public:
// The main constructor. |url| specifies the remote host address/path
// to send the request to. |method| is the HTTP request verb and
// |transport| is the HTTP transport implementation for server communications.
Request(const std::string& url,
const std::string& method,
std::shared_ptr<Transport> transport);
~Request();
// Gets/Sets "Accept:" header value. The default value is "*/*" if not set.
void SetAccept(const std::string& accept_mime_types);
const std::string& GetAccept() const;
// Gets/Sets "Content-Type:" header value
void SetContentType(const std::string& content_type);
const std::string& GetContentType() const;
// Adds additional HTTP request header
void AddHeader(const std::string& header, const std::string& value);
void AddHeaders(const HeaderList& headers);
// Removes HTTP request header
void RemoveHeader(const std::string& header);
// Adds a request body. This is not to be used with GET method
bool AddRequestBody(const void* data, size_t size, brillo::ErrorPtr* error);
bool AddRequestBody(StreamPtr stream, brillo::ErrorPtr* error);
// Adds a request body. This is not to be used with GET method.
// This method also sets the correct content-type of the request, including
// the multipart data boundary.
bool AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,
brillo::ErrorPtr* error);
// Adds a stream for the response. Otherwise a MemoryStream will be used.
bool AddResponseStream(StreamPtr stream, brillo::ErrorPtr* error);
// Makes a request for a subrange of data. Specifies a partial range with
// either from beginning of the data to the specified offset (if |bytes| is
// negative) or from the specified offset to the end of data (if |bytes| is
// positive).
// All individual ranges will be sent as part of "Range:" HTTP request header.
void AddRange(int64_t bytes);
// Makes a request for a subrange of data. Specifies a full range with
// start and end bytes from the beginning of the requested data.
// All individual ranges will be sent as part of "Range:" HTTP request header.
void AddRange(uint64_t from_byte, uint64_t to_byte);
// Returns the request URL
const std::string& GetRequestURL() const;
// Returns the request verb.
const std::string& GetRequestMethod() const;
// Gets/Sets a request referer URL (sent as "Referer:" request header).
void SetReferer(const std::string& referer);
const std::string& GetReferer() const;
// Gets/Sets a user agent string (sent as "User-Agent:" request header).
void SetUserAgent(const std::string& user_agent);
const std::string& GetUserAgent() const;
// Sends the request to the server and blocks until the response is received,
// which is returned as the response object.
// In case the server couldn't be reached for whatever reason, returns
// empty unique_ptr (null). In such a case, the additional error information
// can be returned through the optional supplied |error| parameter.
std::unique_ptr<Response> GetResponseAndBlock(brillo::ErrorPtr* error);
// Sends out the request and invokes the |success_callback| when the response
// is received. In case of an error, the |error_callback| is invoked.
// Returns the ID of the asynchronous request created.
RequestID GetResponse(const SuccessCallback& success_callback,
const ErrorCallback& error_callback);
private:
friend class HttpRequestTest;
// Helper function to create an http::Connection and send off request headers.
BRILLO_PRIVATE bool SendRequestIfNeeded(brillo::ErrorPtr* error);
// Implementation that provides particular HTTP transport.
std::shared_ptr<Transport> transport_;
// An established connection for adding request body. This connection
// is maintained by the request object after the headers have been
// sent and before the response is requested.
std::shared_ptr<Connection> connection_;
// Full request URL, such as "http://www.host.com/path/to/object"
const std::string request_url_;
// HTTP request verb, such as "GET", "POST", "PUT", ...
const std::string method_;
// Referrer URL, if any. Sent to the server via "Referer: " header.
std::string referer_;
// User agent string, if any. Sent to the server via "User-Agent: " header.
std::string user_agent_;
// Content type of the request body data.
// Sent to the server via "Content-Type: " header.
std::string content_type_;
// List of acceptable response data types.
// Sent to the server via "Accept: " header.
std::string accept_ = "*/*";
// List of optional request headers provided by the caller.
std::multimap<std::string, std::string> headers_;
// List of optional data ranges to request partial content from the server.
// Sent to the server as "Range: " header.
std::vector<std::pair<uint64_t, uint64_t>> ranges_;
// range_value_omitted is used in |ranges_| list to indicate omitted value.
// E.g. range (10,range_value_omitted) represents bytes from 10 to the end
// of the data stream.
const uint64_t range_value_omitted = std::numeric_limits<uint64_t>::max();
DISALLOW_COPY_AND_ASSIGN(Request);
};
///////////////////////////////////////////////////////////////////////////////
// Response class is returned from Request::GetResponse() and is a way
// to get to response status, error codes, response HTTP headers and response
// data (body) if available.
///////////////////////////////////////////////////////////////////////////////
class BRILLO_EXPORT Response final {
public:
explicit Response(const std::shared_ptr<Connection>& connection);
~Response();
// Returns true if server returned a success code (status code below 400).
bool IsSuccessful() const;
// Returns the HTTP status code (e.g. 200 for success)
int GetStatusCode() const;
// Returns the status text (e.g. for error 403 it could be "NOT AUTHORIZED").
std::string GetStatusText() const;
// Returns the content type of the response data.
std::string GetContentType() const;
// Returns response data stream by transferring ownership of the data stream
// from Response class to the caller.
StreamPtr ExtractDataStream(ErrorPtr* error);
// Extracts the data from the underlying response data stream as a byte array.
std::vector<uint8_t> ExtractData();
// Extracts the data from the underlying response data stream as a string.
std::string ExtractDataAsString();
// Returns a value of a given response HTTP header.
std::string GetHeader(const std::string& header_name) const;
private:
friend class HttpRequestTest;
std::shared_ptr<Connection> connection_;
DISALLOW_COPY_AND_ASSIGN(Response);
};
} // namespace http
} // namespace brillo
#endif // LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_