1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
#define NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
#include <stddef.h>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include "base/strings/string_util.h"
#include "net/ssl/ssl_info.h"
#include "url/gurl.h"
namespace net {
class HttpChunkedDecoder;
namespace test_server {
// Methods of HTTP requests supported by the test HTTP server.
enum HttpMethod {
METHOD_UNKNOWN,
METHOD_GET,
METHOD_HEAD,
METHOD_POST,
METHOD_PUT,
METHOD_DELETE,
METHOD_PATCH,
METHOD_CONNECT,
METHOD_OPTIONS,
};
// Represents a HTTP request. Since it can be big, `use std::unique_ptr` to pass
// it instead of copying. However, the struct is copyable so tests can save and
// examine a HTTP request.
struct HttpRequest {
struct CaseInsensitiveStringComparator {
// Allow using std::string_view instead of string for `find()`.
using is_transparent = void;
bool operator()(std::string_view left, std::string_view right) const {
return base::CompareCaseInsensitiveASCII(left, right) < 0;
}
};
using HeaderMap =
std::map<std::string, std::string, CaseInsensitiveStringComparator>;
HttpRequest();
HttpRequest(const HttpRequest& other);
~HttpRequest();
// Returns a GURL as a convenience to extract the path and query strings.
GURL GetURL() const;
// The request target. For most methods, this will start with '/', e.g.,
// "/test?query=foo". If `method` is `METHOD_OPTIONS`, it may also be "*". If
// `method` is `METHOD_CONNECT`, it will instead be a string like
// "example.com:443".
std::string relative_url;
GURL base_url;
// The HTTP method. If unknown, this will be `METHOD_UNKNOWN` and the actual
// method will be in `method_string`.
HttpMethod method = METHOD_UNKNOWN;
std::string method_string;
std::string all_headers;
HeaderMap headers;
std::string content;
bool has_content = false;
std::optional<SSLInfo> ssl_info;
};
// Parses the input data and produces a valid HttpRequest object. If there is
// more than one request in one chunk, then only the first one will be parsed.
// The common use is as below:
// HttpRequestParser parser;
// (...)
// void OnDataChunkReceived(Socket* socket, const char* data, int size) {
// parser.ProcessChunk(std::string(data, size));
// if (parser.ParseRequest() == HttpRequestParser::ACCEPTED) {
// std::unique_ptr<HttpRequest> request = parser.GetRequest();
// (... process the request ...)
// }
class HttpRequestParser {
public:
// Parsing result.
enum ParseResult {
WAITING, // A request is not completed yet, waiting for more data.
ACCEPTED, // A request has been parsed and it is ready to be processed.
};
// Parser state.
enum State {
STATE_HEADERS, // Waiting for a request headers.
STATE_CONTENT, // Waiting for content data.
STATE_ACCEPTED, // Request has been parsed.
};
HttpRequestParser();
HttpRequestParser(const HttpRequestParser&) = delete;
HttpRequestParser& operator=(const HttpRequestParser&) = delete;
~HttpRequestParser();
// Adds chunk of data into the internal buffer.
void ProcessChunk(std::string_view data);
// Parses the http request (including data - if provided).
// If returns ACCEPTED, then it means that the whole request has been found
// in the internal buffer (and parsed). After calling GetRequest(), it will be
// ready to parse another request.
ParseResult ParseRequest();
// Retrieves parsed request. Can be only called, when the parser is in
// STATE_ACCEPTED state. After calling it, the parser is ready to parse
// another request.
std::unique_ptr<HttpRequest> GetRequest();
// Returns `METHOD_UNKNOWN` if `token` is not a recognized method. Methods are
// case-sensitive.
static HttpMethod GetMethodType(std::string_view token);
private:
// Parses headers and returns ACCEPTED if whole request was parsed. Otherwise
// returns WAITING.
ParseResult ParseHeaders();
// Parses request's content data and returns ACCEPTED if all of it have been
// processed. Chunked Transfer Encoding is supported.
ParseResult ParseContent();
// Fetches the next line from the buffer. Result does not contain \r\n.
// Returns an empty string for an empty line. It will assert if there is
// no line available.
std::string ShiftLine();
std::unique_ptr<HttpRequest> http_request_;
std::string buffer_;
size_t buffer_position_ = 0; // Current position in the internal buffer.
State state_ = STATE_HEADERS;
// Content length of the request currently being parsed.
size_t declared_content_length_ = 0;
std::unique_ptr<HttpChunkedDecoder> chunked_decoder_;
};
} // namespace test_server
} // namespace net
#endif // NET_TEST_EMBEDDED_TEST_SERVER_HTTP_REQUEST_H_
|