CCF
Loading...
Searching...
No Matches
http_session.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
9#include "enclave/rpc_map.h"
10#include "error_reporter.h"
11#include "http_parser.h"
12#include "http_rpc_context.h"
13
14namespace http
15{
17
21 {
22 private:
23 http::RequestParser request_parser;
24
25 std::shared_ptr<ccf::RPCMap> rpc_map;
26 std::shared_ptr<ccf::RpcHandler> handler;
27 std::shared_ptr<ccf::SessionContext> session_ctx;
28 std::shared_ptr<ErrorReporter> error_reporter;
29 ccf::ListenInterfaceID interface_id;
30
31 public:
33 std::shared_ptr<ccf::RPCMap> rpc_map_,
34 ::tcp::ConnID session_id_,
35 ccf::ListenInterfaceID interface_id_,
37 std::unique_ptr<ccf::tls::Context> ctx,
38 const ccf::http::ParserConfiguration& configuration,
39 const std::shared_ptr<ErrorReporter>& error_reporter_ = nullptr) :
40 HTTPSession(session_id_, writer_factory, std::move(ctx)),
41 request_parser(*this, configuration),
42 rpc_map(std::move(rpc_map_)),
43 error_reporter(error_reporter_),
44 interface_id(std::move(interface_id_))
45 {}
46
47 bool parse(std::span<const uint8_t> data) override
48 {
49 // Catch request parsing errors and convert them to error responses
50 try
51 {
52 request_parser.execute(data.data(), data.size());
53
54 return true;
55 }
57 {
58 if (error_reporter)
59 {
60 error_reporter->report_request_payload_too_large_error(interface_id);
61 }
62
63 LOG_DEBUG_FMT("Request is too large: {}", e.what());
64
66 HTTP_STATUS_PAYLOAD_TOO_LARGE,
67 ccf::errors::RequestBodyTooLarge,
68 e.what()});
69
71 }
73 {
74 if (error_reporter)
75 {
76 error_reporter->report_request_header_too_large_error(interface_id);
77 }
78
79 LOG_DEBUG_FMT("Request header is too large: {}", e.what());
80
82 HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
83 ccf::errors::RequestHeaderTooLarge,
84 e.what()});
85
87 }
88 catch (const std::exception& e)
89 {
90 if (error_reporter)
91 {
92 error_reporter->report_parsing_error(interface_id);
93 }
94 LOG_DEBUG_FMT("Error parsing HTTP request: {}", e.what());
95
97 headers[ccf::http::headers::CONTENT_TYPE] =
98 ccf::http::headervalues::contenttype::TEXT;
99
100 // NB: Avoid formatting input data a string, as it may contain null
101 // bytes. Instead insert it at the end of this message, verbatim
102 auto body_s = fmt::format(
103 "Unable to parse data as a HTTP request. Error message is: {}\n"
104 "Error occurred while parsing fragment:\n",
105 e.what());
106 std::vector<uint8_t> response_body(
107 std::begin(body_s), std::end(body_s));
108 response_body.insert(response_body.end(), data.begin(), data.end());
109
111 HTTP_STATUS_BAD_REQUEST,
112 std::move(headers),
113 {},
114 std::move(response_body));
115
117 }
118
119 return false;
120 }
121
123 llhttp_method verb,
124 const std::string_view& url,
125 ccf::http::HeaderMap&& headers,
126 std::vector<uint8_t>&& body,
127 int32_t /*stream_id*/) override
128 {
130 "Processing msg({}, {} [{} bytes])",
131 llhttp_method_name(verb),
132 url,
133 body.size());
134
135 try
136 {
137 if (session_ctx == nullptr)
138 {
139 session_ctx = std::make_shared<ccf::SessionContext>(
140 session_id, tls_io->peer_cert(), interface_id);
141 }
142
143 std::shared_ptr<http::HttpRpcContext> rpc_ctx = nullptr;
144 try
145 {
146 rpc_ctx = std::make_shared<HttpRpcContext>(
147 session_ctx,
149 verb,
150 url,
151 std::move(headers),
152 std::move(body));
153 }
154 catch (std::exception& e)
155 {
157 HTTP_STATUS_INTERNAL_SERVER_ERROR,
158 ccf::errors::InternalError,
159 fmt::format("Error constructing RpcContext: {}", e.what())});
161 }
162
163 std::shared_ptr<ccf::RpcHandler> search =
164 http::fetch_rpc_handler(rpc_ctx, rpc_map);
165
166 search->process(rpc_ctx);
167
168 if (rpc_ctx->response_is_pending)
169 {
170 // If the RPC is pending, hold the connection.
171 LOG_TRACE_FMT("Pending");
172 return;
173 }
174
176 rpc_ctx->get_response_http_status(),
177 rpc_ctx->get_response_headers(),
178 rpc_ctx->get_response_trailers(),
179 std::move(rpc_ctx->take_response_body()));
180
181 if (rpc_ctx->terminate_session)
182 {
184 }
185 }
186 catch (const std::exception& e)
187 {
189 HTTP_STATUS_INTERNAL_SERVER_ERROR,
190 ccf::errors::InternalError,
191 fmt::format("Exception: {}", e.what())});
192
193 // On any exception, close the connection.
194 LOG_FAIL_FMT("Closing connection");
195 LOG_DEBUG_FMT("Closing connection due to exception: {}", e.what());
197 throw;
198 }
199 }
200
202 ccf::http_status status_code,
203 ccf::http::HeaderMap&& headers,
204 ccf::http::HeaderMap&& trailers,
205 std::vector<uint8_t>&& body) override
206 {
207 if (!trailers.empty())
208 {
209 throw std::logic_error("Cannot return trailers over HTTP/1");
210 }
211
212 auto response = ::http::Response(status_code);
213 for (const auto& [k, v] : headers)
214 {
215 response.set_header(k, v);
216 }
217
218 response.set_body(
219 body.data(),
220 body.size(),
221 false /* Don't overwrite any existing content-length header */
222 );
223
224 send_data(response.build_response());
225 return true;
226 }
227 };
228
230 public ccf::ClientSession,
232 {
233 private:
234 ::http::ResponseParser response_parser;
235
236 public:
238 ::tcp::ConnID session_id_,
239 ringbuffer::AbstractWriterFactory& writer_factory,
240 std::unique_ptr<ccf::tls::Context> ctx) :
241 HTTPSession(session_id_, writer_factory, std::move(ctx)),
242 ClientSession(session_id_, writer_factory),
243 response_parser(*this)
244 {}
245
246 bool parse(std::span<const uint8_t> data) override
247 {
248 // Catch response parsing errors and log them
249 try
250 {
251 response_parser.execute(data.data(), data.size());
252
253 return true;
254 }
255 catch (const std::exception& e)
256 {
257 LOG_FAIL_FMT("Error parsing HTTP response on session {}", session_id);
258 LOG_DEBUG_FMT("Error parsing HTTP response: {}", e.what());
260 "Error occurred while parsing fragment {} byte fragment:\n{}",
261 data.size(),
262 std::string_view(
263 reinterpret_cast<char const*>(data.data()), data.size()));
264
266 }
267 return false;
268 }
269
270 void send_request(http::Request&& request) override
271 {
272 auto data = request.build_request();
273 send_data(std::move(data));
274 }
275
277 const std::string& hostname,
278 const std::string& service,
279 const HandleDataCallback f,
280 const HandleErrorCallback e) override
281 {
282 tls_io->set_handshake_error_cb([e](std::string&& error_msg) {
283 if (e)
284 {
285 e(error_msg);
286 }
287 else
288 {
289 LOG_FAIL_FMT("{}", error_msg);
290 }
291 });
292
293 ccf::ClientSession::connect(hostname, service, f, e);
294 }
295
297 ccf::http_status status,
298 ccf::http::HeaderMap&& headers,
299 std::vector<uint8_t>&& body) override
300 {
301 handle_data_cb(status, std::move(headers), std::move(body));
302
303 LOG_TRACE_FMT("Closing connection, message handled");
305 }
306 };
307
309
311 public ccf::ClientSession,
313 {
314 private:
315 ::http::ResponseParser response_parser;
316
317 public:
319 ::tcp::ConnID session_id_,
320 ringbuffer::AbstractWriterFactory& writer_factory) :
321 UnencryptedHTTPSession(session_id_, writer_factory),
322 ClientSession(session_id_, writer_factory),
323 response_parser(*this)
324 {}
325
326 bool parse(std::span<const uint8_t> data) override
327 {
328 try
329 {
330 response_parser.execute(data.data(), data.size());
331 return true;
332 }
333 catch (const std::exception& e)
334 {
335 LOG_FAIL_FMT("Error parsing HTTP response on session {}", session_id);
336 LOG_DEBUG_FMT("Error parsing HTTP response: {}", e.what());
338 "Error occurred while parsing fragment {} byte fragment:\n{}",
339 data.size(),
340 std::string_view(
341 reinterpret_cast<char const*>(data.data()), data.size()));
342
344 }
345 return false;
346 }
347
348 void send_request(http::Request&& request) override
349 {
350 auto data = request.build_request();
351 send_data(std::move(data));
352 }
353
355 const std::string& hostname,
356 const std::string& service,
357 const HandleDataCallback f,
358 const HandleErrorCallback e) override
359 {
360 ccf::ClientSession::connect(hostname, service, f, e);
361 }
362
364 ccf::http_status status,
365 ccf::http::HeaderMap&& headers,
366 std::vector<uint8_t>&& body) override
367 {
368 handle_data_cb(status, std::move(headers), std::move(body));
369 LOG_TRACE_FMT("Closing connection, message handled");
371 }
372 };
373}
Definition client_session.h:11
virtual void connect(const std::string &hostname, const std::string &service, const HandleDataCallback f, const HandleErrorCallback e=nullptr)
Definition client_session.h:41
std::function< void(const std::string &error_msg)> HandleErrorCallback
Definition client_session.h:21
std::function< void(ccf::http_status status, http::HeaderMap &&headers, std::vector< uint8_t > &&body)> HandleDataCallback
Definition client_session.h:18
HandleDataCallback handle_data_cb
Definition client_session.h:24
Definition session.h:121
::tcp::ConnID session_id
Definition session.h:127
std::shared_ptr< ccf::TLSSession > tls_io
Definition session.h:126
void close_session() override
Definition session.h:109
void send_data(std::vector< uint8_t > &&data) override
Definition session.h:101
Definition session.h:190
::tcp::ConnID session_id
Definition session.h:195
Definition http_responder.h:14
bool send_odata_error_response(ccf::ErrorDetails &&error)
Definition http_responder.h:24
Definition http_session.h:232
HTTPClientSession(::tcp::ConnID session_id_, ringbuffer::AbstractWriterFactory &writer_factory, std::unique_ptr< ccf::tls::Context > ctx)
Definition http_session.h:237
void send_request(http::Request &&request) override
Definition http_session.h:270
void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body) override
Definition http_session.h:296
bool parse(std::span< const uint8_t > data) override
Definition http_session.h:246
void connect(const std::string &hostname, const std::string &service, const HandleDataCallback f, const HandleErrorCallback e) override
Definition http_session.h:276
Definition http_session.h:21
HTTPServerSession(std::shared_ptr< ccf::RPCMap > rpc_map_, ::tcp::ConnID session_id_, ccf::ListenInterfaceID interface_id_, ringbuffer::AbstractWriterFactory &writer_factory, std::unique_ptr< ccf::tls::Context > ctx, const ccf::http::ParserConfiguration &configuration, const std::shared_ptr< ErrorReporter > &error_reporter_=nullptr)
Definition http_session.h:32
bool send_response(ccf::http_status status_code, ccf::http::HeaderMap &&headers, ccf::http::HeaderMap &&trailers, std::vector< uint8_t > &&body) override
Definition http_session.h:201
void handle_request(llhttp_method verb, const std::string_view &url, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body, int32_t) override
Definition http_session.h:122
bool parse(std::span< const uint8_t > data) override
Definition http_session.h:47
void execute(const uint8_t *data, size_t size)
Definition http_parser.h:232
Definition http_exceptions.h:40
Definition http_parser.h:406
Definition http_exceptions.h:31
Definition http_proc.h:20
Definition http_builder.h:117
Definition http_parser.h:466
Definition http_proc.h:33
Definition http_builder.h:200
Definition http_session.h:313
bool parse(std::span< const uint8_t > data) override
Definition http_session.h:326
void send_request(http::Request &&request) override
Definition http_session.h:348
void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body) override
Definition http_session.h:363
UnencryptedHTTPClientSession(::tcp::ConnID session_id_, ringbuffer::AbstractWriterFactory &writer_factory)
Definition http_session.h:318
void connect(const std::string &hostname, const std::string &service, const HandleDataCallback f, const HandleErrorCallback e) override
Definition http_session.h:354
Definition ring_buffer_types.h:157
#define LOG_TRACE_FMT
Definition internal_logger.h:13
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
#define LOG_FAIL_FMT
Definition internal_logger.h:16
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
std::string ListenInterfaceID
Definition rpc_context.h:21
llhttp_status http_status
Definition http_status.h:9
Definition error_reporter.h:6
STL namespace.
int64_t ConnID
Definition msg_types.h:9
Definition odata_error.h:58
Definition http_configuration.h:24