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