CCF
Loading...
Searching...
No Matches
http_builder.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/nonstd.h"
6#include "ccf/http_consts.h"
8#include "ccf/http_status.h"
9
10#define FMT_HEADER_ONLY
11#include <fmt/format.h>
12#include <llhttp/llhttp.h>
13#include <map>
14#include <string>
15#include <vector>
16
17namespace http
18{
19 static std::string get_header_string(const ccf::http::HeaderMap& headers)
20 {
21 std::string header_string;
22 for (const auto& [k, v] : headers)
23 {
24 header_string += fmt::format("{}: {}\r\n", k, v);
25 }
26
27 return header_string;
28 }
29
30 class Message
31 {
32 protected:
34 const uint8_t* body = nullptr;
35 size_t body_size = 0;
36
37 Message() = default;
38
39 public:
40 [[nodiscard]] const ccf::http::HeaderMap& get_headers() const
41 {
42 return headers;
43 }
44
45 void set_header(std::string k, const std::string& v)
46 {
47 // Store all headers lower-cased to simplify case-insensitive lookup
48 ccf::nonstd::to_lower(k);
49 headers[k] = v;
50 }
51
53 {
54 headers.clear();
55 }
56
57 [[nodiscard]] size_t get_content_length() const
58 {
59 if (body == nullptr)
60 {
61 return 0;
62 }
63
64 return body_size;
65 }
66
67 [[nodiscard]] const uint8_t* get_content_data() const
68 {
69 return body;
70 }
71
73 const std::vector<uint8_t>* b, bool overwrite_content_length = true)
74 {
75 if (b != nullptr)
76 {
77 set_body(b->data(), b->size(), overwrite_content_length);
78 }
79 else
80 {
81 set_body(nullptr, 0, overwrite_content_length);
82 }
83 }
84
86 const uint8_t* b, size_t s, bool overwrite_content_length = true)
87 {
88 body = b;
89 body_size = s;
90
91 if (
92 overwrite_content_length ||
93 headers.find(ccf::http::headers::CONTENT_LENGTH) == headers.end())
94 {
95 headers[ccf::http::headers::CONTENT_LENGTH] =
96 fmt::format("{}", get_content_length());
97 }
98 }
99
100 void set_body(const std::string& s, bool overwrite_content_length = true)
101 {
102 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
103 body = reinterpret_cast<const uint8_t*>(s.data());
104 body_size = s.size();
105
106 if (
107 overwrite_content_length ||
108 headers.find(ccf::http::headers::CONTENT_LENGTH) == headers.end())
109 {
110 headers[ccf::http::headers::CONTENT_LENGTH] =
111 fmt::format("{}", get_content_length());
112 }
113 }
114 };
115
116 class Request : public Message
117 {
118 private:
119 llhttp_method method;
120 std::string path = "/";
121 std::map<std::string, std::string> query_params;
122
123 public:
124 Request(const std::string_view& p = "/", llhttp_method m = HTTP_POST) :
125 method(m)
126 {
127 set_path(p);
128 }
129
130 void set_method(llhttp_method m)
131 {
132 method = m;
133 }
134
135 [[nodiscard]] llhttp_method get_method() const
136 {
137 return method;
138 }
139
140 void set_path(const std::string_view& p)
141 {
142 if (!p.empty() && p[0] == '/')
143 {
144 path = p;
145 }
146 else
147 {
148 path = fmt::format("/{}", p);
149 }
150 }
151
152 [[nodiscard]] std::string get_path() const
153 {
154 return path;
155 }
156
157 void set_query_param(const std::string& k, const std::string& v)
158 {
159 query_params[k] = v;
160 }
161
162 [[nodiscard]] std::string get_formatted_query() const
163 {
164 std::string formatted_query;
165 bool first = true;
166 for (const auto& it : query_params)
167 {
168 formatted_query +=
169 fmt::format("{}{}={}", (first ? '?' : '&'), it.first, it.second);
170 first = false;
171 }
172 return formatted_query;
173 }
174
175 [[nodiscard]] std::vector<uint8_t> build_request(
176 bool header_only = false) const
177 {
178 const auto uri = fmt::format("{}{}", path, get_formatted_query());
179
180 const auto body_view = (header_only || body == nullptr) ?
181 std::string_view() :
182 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
183 std::string_view(reinterpret_cast<char const*>(body), body_size);
184
185 const auto request_string = fmt::format(
186 "{} {} HTTP/1.1\r\n"
187 "{}"
188 "\r\n"
189 "{}",
190 llhttp_method_name(method),
191 uri,
192 get_header_string(headers),
193 body_view);
194
195 return {request_string.begin(), request_string.end()};
196 }
197 };
198
199 class Response : public Message
200 {
201 private:
202 ccf::http_status status;
203
204 public:
205 Response(ccf::http_status s = HTTP_STATUS_OK) : status(s) {}
206
207 [[nodiscard]] std::vector<uint8_t> build_response(
208 bool header_only = false) const
209 {
210 const auto body_view = (header_only || body == nullptr) ?
211 std::string_view() :
212 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
213 std::string_view(reinterpret_cast<char const*>(body), body_size);
214
215 const auto response_string = fmt::format(
216 "HTTP/1.1 {} {}\r\n"
217 "{}"
218 "\r\n"
219 "{}",
220 status,
221 ccf::http_status_str(status),
222 get_header_string(headers),
223 body_view);
224
225 return {response_string.begin(), response_string.end()};
226 }
227 }; // Most builder function are unused from enclave
228#pragma clang diagnostic push
229#pragma clang diagnostic ignored "-Wunused-function"
230
231 // Generic
232 static std::vector<uint8_t> build_header(
233 llhttp_method method, const std::vector<uint8_t>& body)
234 {
235 Request r("/", method);
236 r.set_body(&body);
237 return r.build_request(true);
238 }
239
240 static std::vector<uint8_t> build_request(
241 llhttp_method method, const std::vector<uint8_t>& body)
242 {
243 Request r("/", method);
244 r.set_body(&body);
245 return r.build_request(false);
246 }
247
248 // HTTP_DELETE
249 static std::vector<uint8_t> build_delete_header(
250 const std::vector<uint8_t>& body)
251 {
252 return build_header(HTTP_DELETE, body);
253 }
254
255 static std::vector<uint8_t> build_delete_request(
256 const std::vector<uint8_t>& body)
257 {
258 return build_request(HTTP_DELETE, body);
259 }
260
261 // HTTP_GET
262 static std::vector<uint8_t> build_get_header(const std::vector<uint8_t>& body)
263 {
264 return build_header(HTTP_GET, body);
265 }
266
267 static std::vector<uint8_t> build_get_request(
268 const std::vector<uint8_t>& body)
269 {
270 return build_request(HTTP_GET, body);
271 }
272
273 // HTTP_POST
274 static std::vector<uint8_t> build_post_header(
275 const std::vector<uint8_t>& body)
276 {
277 return build_header(HTTP_POST, body);
278 }
279
280 static std::vector<uint8_t> build_post_request(
281 const std::vector<uint8_t>& body)
282 {
283 return build_request(HTTP_POST, body);
284 }
285
286 // HTTP_PUT
287 static std::vector<uint8_t> build_put_header(const std::vector<uint8_t>& body)
288 {
289 return build_header(HTTP_PUT, body);
290 }
291
292 static std::vector<uint8_t> build_put_request(
293 const std::vector<uint8_t>& body)
294 {
295 return build_request(HTTP_PUT, body);
296 }
297#pragma clang diagnostic pop
298}
Definition http_builder.h:31
Message()=default
ccf::http::HeaderMap headers
Definition http_builder.h:33
const uint8_t * body
Definition http_builder.h:34
const ccf::http::HeaderMap & get_headers() const
Definition http_builder.h:40
void set_body(const uint8_t *b, size_t s, bool overwrite_content_length=true)
Definition http_builder.h:85
size_t get_content_length() const
Definition http_builder.h:57
void set_header(std::string k, const std::string &v)
Definition http_builder.h:45
void set_body(const std::string &s, bool overwrite_content_length=true)
Definition http_builder.h:100
void set_body(const std::vector< uint8_t > *b, bool overwrite_content_length=true)
Definition http_builder.h:72
const uint8_t * get_content_data() const
Definition http_builder.h:67
size_t body_size
Definition http_builder.h:35
void clear_headers()
Definition http_builder.h:52
Definition http_builder.h:117
std::vector< uint8_t > build_request(bool header_only=false) const
Definition http_builder.h:175
std::string get_path() const
Definition http_builder.h:152
std::string get_formatted_query() const
Definition http_builder.h:162
void set_method(llhttp_method m)
Definition http_builder.h:130
llhttp_method get_method() const
Definition http_builder.h:135
Request(const std::string_view &p="/", llhttp_method m=HTTP_POST)
Definition http_builder.h:124
void set_query_param(const std::string &k, const std::string &v)
Definition http_builder.h:157
void set_path(const std::string_view &p)
Definition http_builder.h:140
Definition http_builder.h:200
std::vector< uint8_t > build_response(bool header_only=false) const
Definition http_builder.h:207
Response(ccf::http_status s=HTTP_STATUS_OK)
Definition http_builder.h:205
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
llhttp_status http_status
Definition http_status.h:9
Definition error_reporter.h:6