Line data Source code
1 : #ifndef HTTP_REQUEST_HPP
2 : #define HTTP_REQUEST_HPP
3 :
4 : #include <boost/asio.hpp>
5 : #include <regex>
6 : #include <utility>
7 : #include "headers.hpp"
8 : #include "../client/cookie_store.hpp"
9 : #include "../client/proxy.hpp"
10 : #include "../util/url.hpp"
11 :
12 : namespace thinger::http {
13 :
14 : enum class method{
15 : GET,
16 : HEAD,
17 : POST,
18 : PUT,
19 : DELETE,
20 : TRACE,
21 : OPTIONS,
22 : CONNECT,
23 : PATCH,
24 : UNKNOWN
25 : };
26 :
27 : method get_method(const std::string& method);
28 : const std::string& get_method(method);
29 : static const std::string https = "https";
30 : static const std::string wss = "wss";
31 : static const std::string ws = "ws";
32 : static const std::string https_port = "443";
33 : static const std::string http = "http";
34 : static const std::string http_port = "80";
35 :
36 : class http_request : public headers{
37 :
38 : public:
39 :
40 : // constructor
41 233073 : http_request() = default;
42 233079 : ~http_request() override = default;
43 :
44 : // setters
45 : bool set_url(const std::string& url);
46 : void set_host(std::string host);
47 : void set_port(const std::string &port);
48 : void set_protocol(std::string protocol);
49 : void set_ssl(bool ssl);
50 : void set_unix_socket(const std::string& unix_socket);
51 : void set_uri(const std::string &uri);
52 : void set_method(const std::string &method);
53 : void set_method(http::method method);
54 : void set_content(std::string content);
55 : void set_content(std::string content, std::string content_type);
56 : void add_uri_parameter(const std::string &key, const std::string &value);
57 : void set_resource(const std::string& resource);
58 :
59 : // getters
60 : std::string get_url() const;
61 : std::string get_base_path() const;
62 : const std::string& get_body() const;
63 : bool has_resource() const;
64 : bool has_query_parameters() const;
65 : bool has_uri_parameter(const std::string& key) const;
66 : bool has_uri_value(const std::string& key, const std::string& value) const;
67 : bool has_uri_parameters() const;
68 : const std::string& get_uri_parameter(const std::string& key) const;
69 : const std::multimap<std::string, std::string>& get_uri_parameters() const;
70 : bool has_content() const;
71 : // (inline: checked on every request and response)
72 173428 : method get_method() const { return method_; }
73 : const std::string& get_method_string() const;
74 : std::string get_query_string() const;
75 : std::string get_path() const;
76 : std::string& get_uri();
77 : const std::string& get_uri() const;
78 : const std::string& get_unix_socket() const;
79 : const std::string& get_protocol() const;
80 : bool is_default_port() const;
81 : const std::string &get_port() const;
82 : cookie_store& get_cookie_store();
83 : const std::string &get_host() const;
84 : bool is_ssl() const;
85 : const std::string& get_resource() const;
86 : std::string& get_resource();
87 : std::string& get_body();
88 :
89 : template<class T>
90 9 : T get_uri_parameter(const std::string& key, T default_value) const{
91 9 : if(has_uri_parameter(key)){
92 6 : const std::string& ts_str = get_uri_parameter(key);
93 6 : if(!ts_str.empty()){
94 : try
95 : {
96 6 : T value = boost::lexical_cast<T>(ts_str);
97 6 : return value;
98 0 : }catch(const boost::bad_lexical_cast &){
99 :
100 : }
101 : }
102 : }
103 3 : return default_value;
104 : }
105 :
106 : // chunked callbacks
107 : std::function<void(int, const std::string&)> get_chunked_callback();
108 : void set_chunked_callback(std::function<void(int, const std::string&)> callback);
109 :
110 : // client side: proxy settings for this request, instead of those of the client (see
111 : // http_client_base::proxy()); an empty proxy_config connects directly
112 24 : void set_proxy_config(proxy_config config) { proxy_config_ = std::move(config); }
113 8154 : const std::optional<proxy_config>& get_proxy_config() const { return proxy_config_; }
114 :
115 : // client side: CAs trusted to verify the server of this request, besides those of the
116 : // client (see http_client_base::add_ca_file()): a PEM file, or PEM text
117 3 : void add_ca_file(std::string path) { ca_files_.push_back(std::move(path)); }
118 12 : void add_ca_pem(std::string pem) { ca_pems_.push_back(std::move(pem)); }
119 985 : const std::vector<std::string>& get_ca_files() const { return ca_files_; }
120 985 : const std::vector<std::string>& get_ca_pems() const { return ca_pems_; }
121 :
122 : // stream related
123 : bool end_stream() override;
124 : size_t get_size() override;
125 : void to_buffer(std::vector<boost::asio::const_buffer> &buffer) const override;
126 : // The request with another request target (e.g. absolute-form, for a proxy), and
127 : // `extra_headers` (complete lines, CRLF included) after its own headers
128 : void to_buffer(std::vector<boost::asio::const_buffer> &buffer, std::string_view request_target,
129 : std::string_view extra_headers) const;
130 : void process_header(std::string key, std::string value) override;
131 :
132 : // logs
133 : void log(const char* scope, const body_logging& options = {}) const override;
134 :
135 : // factory methods
136 : static std::shared_ptr<http_request> create_http_request(const std::string& method, const std::string& url);
137 : static std::shared_ptr<http_request> create_http_request(http::method method, const std::string& url, const std::string& unix_socket="");
138 :
139 : // body status (infrastructure for deferred body reading)
140 252 : bool has_pending_body() const {
141 495 : return (get_content_length() > 0 && content_.size() < get_content_length())
142 495 : || chunked_transfer_;
143 : }
144 :
145 134430 : size_t pending_body_size() const {
146 134430 : return get_content_length() > content_.size() ? get_content_length() - content_.size() : 0;
147 : }
148 :
149 : // Expectation of a received request (Expect header, RFC 9110 section 10.1.1): none (also
150 : // for HTTP/1.0 requests, which must ignore it), 100-continue (the client may wait for a
151 : // 100 Continue before sending the body), or another one, which cannot be met
152 : enum class expectation : uint8_t { none, continue_100, unsupported };
153 50891 : expectation get_expectation() const { return expectation_; }
154 :
155 : // other
156 : void refresh_uri();
157 :
158 : private:
159 : bool ssl_ = false;
160 : method method_ = method::UNKNOWN;
161 : std::string uri_;
162 : std::string resource_;
163 : std::multimap<std::string, std::string> uri_params_;
164 : std::string content_;
165 : std::string host_;
166 : std::string port_;
167 : std::string protocol_;
168 : std::string unix_socket_;
169 : cookie_store cookie_store_;
170 : std::function<void(int, const std::string&)> on_chunked_;
171 : std::optional<proxy_config> proxy_config_;
172 : std::vector<std::string> ca_files_;
173 : std::vector<std::string> ca_pems_;
174 : expectation expectation_ = expectation::none;
175 :
176 : // Set host_ and port_ from a Host value, returning the Host header to send
177 : std::string parse_host(std::string host);
178 :
179 : // Keep track of the expectation of a received Expect header
180 : void process_expect_header(std::string_view value);
181 :
182 : };
183 :
184 :
185 : }
186 :
187 : #endif
|