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:
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 size_t get_content_length() const
58 {
59 if (body == nullptr)
60 {
61 return 0;
62 }
63 else
64 {
65 return body_size;
66 }
67 }
68
69 const uint8_t* get_content_data() const
70 {
71 return body;
72 }
73
75 const std::vector<uint8_t>* b, bool overwrite_content_length = true)
76 {
77 if (b != nullptr)
78 {
79 set_body(b->data(), b->size(), overwrite_content_length);
80 }
81 else
82 {
83 set_body(nullptr, 0, overwrite_content_length);
84 }
85 }
86
88 const uint8_t* b, size_t s, bool overwrite_content_length = true)
89 {
90 body = b;
91 body_size = s;
92
93 if (
94 overwrite_content_length ||
95 headers.find(ccf::http::headers::CONTENT_LENGTH) == headers.end())
96 {
97 headers[ccf::http::headers::CONTENT_LENGTH] =
98 fmt::format("{}", get_content_length());
99 }
100 }
101
102 void set_body(const std::string& s, bool overwrite_content_length = true)
103 {
104 body = (uint8_t*)s.data();
105 body_size = s.size();
106
107 if (
108 overwrite_content_length ||
109 headers.find(ccf::http::headers::CONTENT_LENGTH) == headers.end())
110 {
111 headers[ccf::http::headers::CONTENT_LENGTH] =
112 fmt::format("{}", get_content_length());
113 }
114 }
115 };
116
117 class Request : public Message
118 {
119 private:
120 llhttp_method method;
121 std::string path = "/";
122 std::map<std::string, std::string> query_params = {};
123
124 public:
125 Request(const std::string_view& p = "/", llhttp_method m = HTTP_POST) :
126 Message(),
127 method(m)
128 {
129 set_path(p);
130 }
131
132 void set_method(llhttp_method m)
133 {
134 method = m;
135 }
136
137 llhttp_method get_method() const
138 {
139 return method;
140 }
141
142 void set_path(const std::string_view& p)
143 {
144 if (p.size() > 0 && p[0] == '/')
145 {
146 path = p;
147 }
148 else
149 {
150 path = fmt::format("/{}", p);
151 }
152 }
153
154 std::string get_path() const
155 {
156 return path;
157 }
158
159 void set_query_param(const std::string& k, const std::string& v)
160 {
161 query_params[k] = v;
162 }
163
164 std::string get_formatted_query() const
165 {
166 std::string formatted_query;
167 bool first = true;
168 for (const auto& it : query_params)
169 {
170 formatted_query +=
171 fmt::format("{}{}={}", (first ? '?' : '&'), it.first, it.second);
172 first = false;
173 }
174 return formatted_query;
175 }
176
177 std::vector<uint8_t> build_request(bool header_only = false) const
178 {
179 const auto uri = fmt::format("{}{}", path, get_formatted_query());
180
181 const auto body_view = (header_only || body == nullptr) ?
182 std::string_view() :
183 std::string_view((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 std::vector<uint8_t>(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 std::vector<uint8_t> build_response(bool header_only = false) const
208 {
209 const auto body_view = (header_only || body == nullptr) ?
210 std::string_view() :
211 std::string_view((char const*)body, body_size);
212
213 const auto response_string = fmt::format(
214 "HTTP/1.1 {} {}\r\n"
215 "{}"
216 "\r\n"
217 "{}",
218 status,
219 ccf::http_status_str(status),
220 get_header_string(headers),
221 body_view);
222
223 return std::vector<uint8_t>(
224 response_string.begin(), response_string.end());
225 }
226 };
227
228// Most builder function are unused from enclave
229#pragma clang diagnostic push
230#pragma clang diagnostic ignored "-Wunused-function"
231
232 // Generic
233 static std::vector<uint8_t> build_header(
234 llhttp_method method, const std::vector<uint8_t>& body)
235 {
236 Request r("/", method);
237 r.set_body(&body);
238 return r.build_request(true);
239 }
240
241 static std::vector<uint8_t> build_request(
242 llhttp_method method, const std::vector<uint8_t>& body)
243 {
244 Request r("/", method);
245 r.set_body(&body);
246 return r.build_request(false);
247 }
248
249 // HTTP_DELETE
250 static std::vector<uint8_t> build_delete_header(
251 const std::vector<uint8_t>& body)
252 {
253 return build_header(HTTP_DELETE, body);
254 }
255
256 static std::vector<uint8_t> build_delete_request(
257 const std::vector<uint8_t>& body)
258 {
259 return build_request(HTTP_DELETE, body);
260 }
261
262 // HTTP_GET
263 static std::vector<uint8_t> build_get_header(const std::vector<uint8_t>& body)
264 {
265 return build_header(HTTP_GET, body);
266 }
267
268 static std::vector<uint8_t> build_get_request(
269 const std::vector<uint8_t>& body)
270 {
271 return build_request(HTTP_GET, body);
272 }
273
274 // HTTP_POST
275 static std::vector<uint8_t> build_post_header(
276 const std::vector<uint8_t>& body)
277 {
278 return build_header(HTTP_POST, body);
279 }
280
281 static std::vector<uint8_t> build_post_request(
282 const std::vector<uint8_t>& body)
283 {
284 return build_request(HTTP_POST, body);
285 }
286
287 // HTTP_PUT
288 static std::vector<uint8_t> build_put_header(const std::vector<uint8_t>& body)
289 {
290 return build_header(HTTP_PUT, body);
291 }
292
293 static std::vector<uint8_t> build_put_request(
294 const std::vector<uint8_t>& body)
295 {
296 return build_request(HTTP_PUT, body);
297 }
298#pragma clang diagnostic pop
299}
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:87
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:102
void set_body(const std::vector< uint8_t > *b, bool overwrite_content_length=true)
Definition http_builder.h:74
const uint8_t * get_content_data() const
Definition http_builder.h:69
size_t body_size
Definition http_builder.h:35
void clear_headers()
Definition http_builder.h:52
Definition http_builder.h:118
std::vector< uint8_t > build_request(bool header_only=false) const
Definition http_builder.h:177
std::string get_path() const
Definition http_builder.h:154
std::string get_formatted_query() const
Definition http_builder.h:164
void set_method(llhttp_method m)
Definition http_builder.h:132
llhttp_method get_method() const
Definition http_builder.h:137
Request(const std::string_view &p="/", llhttp_method m=HTTP_POST)
Definition http_builder.h:125
void set_query_param(const std::string &k, const std::string &v)
Definition http_builder.h:159
void set_path(const std::string_view &p)
Definition http_builder.h:142
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