Botan 3.13.0
Crypto and TLS for C&
http_util.h
Go to the documentation of this file.
1/*
2* HTTP utilities
3* (C) 2013 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_UTILS_HTTP_H_
9#define BOTAN_UTILS_HTTP_H_
10
11#include <botan/exceptn.h>
12#include <botan/types.h>
13#include <algorithm>
14#include <chrono>
15#include <functional>
16#include <map>
17#include <optional>
18#include <string>
19#include <string_view>
20#include <vector>
21
22namespace Botan {
23
24class URI;
25
26namespace OS {
27class Socket;
28}
29
30} // namespace Botan
31
32namespace Botan::HTTP {
33
34/**
35* HTTP_Error Exception
36*/
37class BOTAN_TEST_API HTTP_Error final : public Exception {
38 public:
39 explicit HTTP_Error(const std::string& msg) : Exception("HTTP error " + msg) {}
40
41 ErrorType error_type() const noexcept override { return ErrorType::HttpError; }
42};
43
44/**
45* Transparent case-insensitive comparator for HTTP field names.
46* RFC 9110 5.1: "field names are case-insensitive".
47*/
49 using is_transparent = void;
50
51 bool operator()(std::string_view a, std::string_view b) const {
52 const auto ascii_lower = [](unsigned char c) -> unsigned char {
53 return (c >= 'A' && c <= 'Z') ? static_cast<unsigned char>(c + 32) : c;
54 };
55 return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [&](char x, char y) {
56 return ascii_lower(static_cast<unsigned char>(x)) < ascii_lower(static_cast<unsigned char>(y));
57 });
58 }
59};
60
61using Headers = std::map<std::string, std::string, Case_Insensitive_Less>;
62
63class Response final {
64 public:
65 Response() : m_status_code(0), m_status_message("Uninitialized") {}
66
67 Response(unsigned int status_code, std::string status_message, std::vector<uint8_t> body, Headers headers) :
68 m_status_code(status_code),
69 m_status_message(std::move(status_message)),
70 m_body(std::move(body)),
71 m_headers(std::move(headers)) {}
72
73 unsigned int status_code() const { return m_status_code; }
74
75 const std::vector<uint8_t>& body() const { return m_body; }
76
77 const Headers& headers() const { return m_headers; }
78
79 std::string status_message() const { return m_status_message; }
80
81 void throw_unless_ok() const {
82 if(status_code() != 200) {
84 }
85 }
86
87 private:
88 unsigned int m_status_code;
89 std::string m_status_message;
90 std::vector<uint8_t> m_body;
91 Headers m_headers;
92};
93
94BOTAN_TEST_API std::ostream& operator<<(std::ostream& o, const Response& resp);
95
96/**
97* Per-request limits applied to an HTTP exchange.
98*/
99class RequestLimits final {
100 public:
101 RequestLimits() = default;
102
103 size_t max_redirects() const { return m_max_redirects; }
104
105 std::chrono::milliseconds timeout() const { return m_timeout; }
106
107 std::optional<size_t> max_body_size() const { return m_max_body_size; }
108
110 m_max_redirects = n;
111 return *this;
112 }
113
114 RequestLimits& set_timeout(std::chrono::milliseconds t) {
115 m_timeout = t;
116 return *this;
117 }
118
120 m_max_body_size = n;
121 return *this;
122 }
123
124 private:
125 size_t m_max_redirects = 0;
126 std::chrono::milliseconds m_timeout = std::chrono::milliseconds(3000);
127 std::optional<size_t> m_max_body_size;
128};
129
130typedef std::function<Response(std::string_view, std::string_view, std::string_view, std::optional<size_t>)>
132
134 std::string_view verb,
135 const URI& uri,
136 std::string_view content_type,
137 const std::vector<uint8_t>& body,
138 const RequestLimits& limits);
139
140Response http_sync(std::string_view verb,
141 const URI& uri,
142 std::string_view content_type,
143 const std::vector<uint8_t>& body,
144 const RequestLimits& limits = {});
145
146Response BOTAN_TEST_API GET_sync(const URI& uri, const RequestLimits& limits = {});
147
148Response POST_sync(const URI& uri,
149 std::string_view content_type,
150 const std::vector<uint8_t>& body,
151 const RequestLimits& limits = {});
152
153std::string BOTAN_TEST_API url_encode(std::string_view url);
154
155/**
156* Read a complete HTTP/1.0 response from an already-connected socket and
157* return the parsed Response. Enforces header- and body-size limits during
158* the read. Exposed via BOTAN_TEST_API so the parser can be exercised
159* against a fake socket; production code reaches it through http_transact.
160*/
162 std::chrono::milliseconds timeout,
163 std::optional<size_t> max_body_size);
164
165} // namespace Botan::HTTP
166
167#endif
#define BOTAN_TEST_API
Definition api.h:41
Exception(std::string_view msg)
Definition exceptn.cpp:71
ErrorType error_type() const noexcept override
Definition http_util.h:41
HTTP_Error(const std::string &msg)
Definition http_util.h:39
RequestLimits & set_timeout(std::chrono::milliseconds t)
Definition http_util.h:114
std::chrono::milliseconds timeout() const
Definition http_util.h:105
RequestLimits & set_max_body_size(size_t n)
Definition http_util.h:119
size_t max_redirects() const
Definition http_util.h:103
RequestLimits & set_max_redirects(size_t n)
Definition http_util.h:109
std::optional< size_t > max_body_size() const
Definition http_util.h:107
const std::vector< uint8_t > & body() const
Definition http_util.h:75
Response(unsigned int status_code, std::string status_message, std::vector< uint8_t > body, Headers headers)
Definition http_util.h:67
const Headers & headers() const
Definition http_util.h:77
unsigned int status_code() const
Definition http_util.h:73
std::string status_message() const
Definition http_util.h:79
void throw_unless_ok() const
Definition http_util.h:81
std::string url_encode(std::string_view in)
Response GET_sync(const URI &uri, const RequestLimits &limits)
std::function< Response(std::string_view, std::string_view, std::string_view, std::optional< size_t >)> http_exch_fn
Definition http_util.h:131
std::map< std::string, std::string, Case_Insensitive_Less > Headers
Definition http_util.h:61
Response http_sync(const http_exch_fn &http_transact, std::string_view verb, const URI &uri, std::string_view content_type, const std::vector< uint8_t > &body, const RequestLimits &limits)
Response read_response_from_socket(OS::Socket &socket, std::chrono::milliseconds timeout, std::optional< size_t > max_body_size)
Response POST_sync(const URI &uri, std::string_view content_type, const std::vector< uint8_t > &body, const RequestLimits &limits)
std::ostream & operator<<(std::ostream &o, const Response &resp)
ErrorType
Definition exceptn.h:21
bool operator()(std::string_view a, std::string_view b) const
Definition http_util.h:51