Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
http_types.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6#include <algorithm>
7#include <cctype>
8
10{
11 namespace
12 {
13 // Convert string to lowercase for case-insensitive comparison
14 auto to_lower(std::string str) -> std::string
15 {
16 std::transform(str.begin(), str.end(), str.begin(),
17 [](unsigned char c) { return std::tolower(c); });
18 return str;
19 }
20 }
21
22 // http_request methods
23
24 auto http_request::get_header(const std::string& name) const -> std::optional<std::string>
25 {
26 auto lower_name = to_lower(name);
27 for (const auto& [key, value] : headers)
28 {
29 if (to_lower(key) == lower_name)
30 {
31 return value;
32 }
33 }
34 return std::nullopt;
35 }
36
37 auto http_request::set_header(const std::string& name, const std::string& value) -> void
38 {
39 // Remove existing header with same name (case-insensitive)
40 auto lower_name = to_lower(name);
41 for (auto it = headers.begin(); it != headers.end();)
42 {
43 if (to_lower(it->first) == lower_name)
44 {
45 it = headers.erase(it);
46 }
47 else
48 {
49 ++it;
50 }
51 }
52
53 // Add new header
54 headers[name] = value;
55 }
56
57 auto http_request::get_body_string() const -> std::string
58 {
59 return std::string(body.begin(), body.end());
60 }
61
62 auto http_request::set_body_string(const std::string& content) -> void
63 {
64 body.assign(content.begin(), content.end());
65 }
66
67 // http_response methods
68
69 auto http_response::get_header(const std::string& name) const -> std::optional<std::string>
70 {
71 auto lower_name = to_lower(name);
72 for (const auto& [key, value] : headers)
73 {
74 if (to_lower(key) == lower_name)
75 {
76 return value;
77 }
78 }
79 return std::nullopt;
80 }
81
82 auto http_response::set_header(const std::string& name, const std::string& value) -> void
83 {
84 // Remove existing header with same name (case-insensitive)
85 auto lower_name = to_lower(name);
86 for (auto it = headers.begin(); it != headers.end();)
87 {
88 if (to_lower(it->first) == lower_name)
89 {
90 it = headers.erase(it);
91 }
92 else
93 {
94 ++it;
95 }
96 }
97
98 // Add new header
99 headers[name] = value;
100 }
101
102 auto http_response::get_body_string() const -> std::string
103 {
104 return std::string(body.begin(), body.end());
105 }
106
107 auto http_response::set_body_string(const std::string& content) -> void
108 {
109 body.assign(content.begin(), content.end());
110 }
111
112 // Helper functions
113
114 auto http_method_to_string(http_method method) -> std::string
115 {
116 switch (method)
117 {
118 case http_method::HTTP_GET: return "GET";
119 case http_method::HTTP_POST: return "POST";
120 case http_method::HTTP_PUT: return "PUT";
121 case http_method::HTTP_DELETE: return "DELETE";
122 case http_method::HTTP_HEAD: return "HEAD";
123 case http_method::HTTP_OPTIONS: return "OPTIONS";
124 case http_method::HTTP_PATCH: return "PATCH";
125 case http_method::HTTP_CONNECT: return "CONNECT";
126 case http_method::HTTP_TRACE: return "TRACE";
127 default: return "GET";
128 }
129 }
130
132 {
133 auto upper_method = method_str;
134 std::transform(upper_method.begin(), upper_method.end(), upper_method.begin(),
135 [](unsigned char c) { return std::toupper(c); });
136
137 if (upper_method == "GET") return ::kcenon::network::ok(http_method::HTTP_GET);
138 if (upper_method == "POST") return ::kcenon::network::ok(http_method::HTTP_POST);
139 if (upper_method == "PUT") return ::kcenon::network::ok(http_method::HTTP_PUT);
140 if (upper_method == "DELETE") return ::kcenon::network::ok(http_method::HTTP_DELETE);
141 if (upper_method == "HEAD") return ::kcenon::network::ok(http_method::HTTP_HEAD);
142 if (upper_method == "OPTIONS") return ::kcenon::network::ok(http_method::HTTP_OPTIONS);
143 if (upper_method == "PATCH") return ::kcenon::network::ok(http_method::HTTP_PATCH);
144 if (upper_method == "CONNECT") return ::kcenon::network::ok(http_method::HTTP_CONNECT);
145 if (upper_method == "TRACE") return ::kcenon::network::ok(http_method::HTTP_TRACE);
146
147 return ::kcenon::network::error<http_method>(
149 "Unknown HTTP method: " + method_str,
150 "http_types");
151 }
152
154 {
155 switch (version)
156 {
157 case http_version::HTTP_1_0: return "HTTP/1.0";
158 case http_version::HTTP_1_1: return "HTTP/1.1";
159 case http_version::HTTP_2_0: return "HTTP/2.0";
160 default: return "HTTP/1.1";
161 }
162 }
163
165 {
166 if (version_str == "HTTP/1.0") return ::kcenon::network::ok(http_version::HTTP_1_0);
167 if (version_str == "HTTP/1.1") return ::kcenon::network::ok(http_version::HTTP_1_1);
168 if (version_str == "HTTP/2.0") return ::kcenon::network::ok(http_version::HTTP_2_0);
169 if (version_str == "HTTP/2") return ::kcenon::network::ok(http_version::HTTP_2_0);
170
171 return ::kcenon::network::error<http_version>(
173 "Unknown HTTP version: " + version_str,
174 "http_types");
175 }
176
177 auto get_status_message(int status_code) -> std::string
178 {
179 switch (status_code)
180 {
181 // 1xx Informational
182 case 100: return "Continue";
183 case 101: return "Switching Protocols";
184
185 // 2xx Success
186 case 200: return "OK";
187 case 201: return "Created";
188 case 202: return "Accepted";
189 case 203: return "Non-Authoritative Information";
190 case 204: return "No Content";
191 case 205: return "Reset Content";
192 case 206: return "Partial Content";
193
194 // 3xx Redirection
195 case 300: return "Multiple Choices";
196 case 301: return "Moved Permanently";
197 case 302: return "Found";
198 case 303: return "See Other";
199 case 304: return "Not Modified";
200 case 307: return "Temporary Redirect";
201 case 308: return "Permanent Redirect";
202
203 // 4xx Client Error
204 case 400: return "Bad Request";
205 case 401: return "Unauthorized";
206 case 402: return "Payment Required";
207 case 403: return "Forbidden";
208 case 404: return "Not Found";
209 case 405: return "Method Not Allowed";
210 case 406: return "Not Acceptable";
211 case 407: return "Proxy Authentication Required";
212 case 408: return "Request Timeout";
213 case 409: return "Conflict";
214 case 410: return "Gone";
215 case 411: return "Length Required";
216 case 412: return "Precondition Failed";
217 case 413: return "Payload Too Large";
218 case 414: return "URI Too Long";
219 case 415: return "Unsupported Media Type";
220 case 416: return "Range Not Satisfiable";
221 case 417: return "Expectation Failed";
222 case 429: return "Too Many Requests";
223
224 // 5xx Server Error
225 case 500: return "Internal Server Error";
226 case 501: return "Not Implemented";
227 case 502: return "Bad Gateway";
228 case 503: return "Service Unavailable";
229 case 504: return "Gateway Timeout";
230 case 505: return "HTTP Version Not Supported";
231
232 default: return "Unknown";
233 }
234 }
235
236 // cookie methods
237 auto cookie::to_header_value() const -> std::string
238 {
239 std::string result = name + "=" + value;
240
241 if (!path.empty()) {
242 result += "; Path=" + path;
243 }
244 if (!domain.empty()) {
245 result += "; Domain=" + domain;
246 }
247 if (!expires.empty()) {
248 result += "; Expires=" + expires;
249 }
250 if (max_age >= 0) {
251 result += "; Max-Age=" + std::to_string(max_age);
252 }
253 if (http_only) {
254 result += "; HttpOnly";
255 }
256 if (secure) {
257 result += "; Secure";
258 }
259 if (!same_site.empty()) {
260 result += "; SameSite=" + same_site;
261 }
262
263 return result;
264 }
265
266 // http_response::set_cookie method
267 auto http_response::set_cookie(const std::string& name, const std::string& value,
268 const std::string& path, int max_age,
269 bool http_only, bool secure,
270 const std::string& same_site) -> void
271 {
272 cookie c;
273 c.name = name;
274 c.value = value;
275 c.path = path;
276 c.max_age = max_age;
277 c.http_only = http_only;
278 c.secure = secure;
279 c.same_site = same_site;
280 set_cookies.push_back(c);
281 }
282
283} // namespace kcenon::network::internal
auto http_version_to_string(http_version version) -> std::string
Convert HTTP version enum to string.
auto string_to_http_method(const std::string &method_str) -> ::kcenon::network::internal::Result< http_method >
Convert string to HTTP method enum.
http_version
HTTP protocol version.
Definition http_types.h:41
auto http_method_to_string(http_method method) -> std::string
Convert HTTP method enum to string.
auto string_to_http_version(const std::string &version_str) -> ::kcenon::network::internal::Result< http_version >
Convert string to HTTP version enum.
auto get_status_message(int status_code) -> std::string
Get HTTP status message for a status code.
http_method
HTTP request methods (verbs)
Definition http_types.h:24
constexpr const char * version() noexcept
Get the network system version string.
Definition network.cppm:111
Represents an HTTP cookie.
Definition http_types.h:63
auto to_header_value() const -> std::string
Convert cookie to Set-Cookie header value.
auto get_body_string() const -> std::string
Get body as string.
auto set_body_string(const std::string &content) -> void
Set body from string.
auto set_header(const std::string &name, const std::string &value) -> void
Set a header value.
auto get_header(const std::string &name) const -> std::optional< std::string >
Get the value of a header (case-insensitive)
auto set_cookie(const std::string &name, const std::string &value, const std::string &path="/", int max_age=-1, bool http_only=true, bool secure=false, const std::string &same_site="") -> void
Set a cookie in the response.
auto set_body_string(const std::string &content) -> void
Set body from string.
auto set_header(const std::string &name, const std::string &value) -> void
Set a header value.
auto get_header(const std::string &name) const -> std::optional< std::string >
Get the value of a header (case-insensitive)
auto get_body_string() const -> std::string
Get body as string.