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
5#include "ccf/ds/logger.h"
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 const 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(rpc_map),
43 error_reporter(error_reporter),
44 interface_id(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
70 tls_io->close();
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
86 tls_io->close();
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
116 tls_io->close();
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) 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())});
160 tls_io->close();
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 else
175 {
177 rpc_ctx->get_response_http_status(),
178 rpc_ctx->get_response_headers(),
179 rpc_ctx->get_response_trailers(),
180 std::move(rpc_ctx->get_response_body()));
181
182 if (rpc_ctx->terminate_session)
183 {
184 tls_io->close();
185 }
186 }
187 }
188 catch (const std::exception& e)
189 {
191 HTTP_STATUS_INTERNAL_SERVER_ERROR,
192 ccf::errors::InternalError,
193 fmt::format("Exception: {}", e.what())});
194
195 // On any exception, close the connection.
196 LOG_FAIL_FMT("Closing connection");
197 LOG_DEBUG_FMT("Closing connection due to exception: {}", e.what());
198 tls_io->close();
199 throw;
200 }
201 }
202
204 ccf::http_status status_code,
205 ccf::http::HeaderMap&& headers,
206 ccf::http::HeaderMap&& trailers,
207 std::span<const uint8_t> body) override
208 {
209 if (!trailers.empty())
210 {
211 throw std::logic_error("Cannot return trailers over HTTP/1");
212 }
213
214 auto response = ::http::Response(status_code);
215 for (const auto& [k, v] : headers)
216 {
217 response.set_header(k, v);
218 }
219
220 response.set_body(
221 body.data(),
222 body.size(),
223 false /* Don't overwrite any existing content-length header */
224 );
225
226 auto data = response.build_response();
227 tls_io->send_raw(data.data(), data.size());
228 return true;
229 }
230
232 ccf::http_status status, const ccf::http::HeaderMap& headers) override
233 {
234 throw std::logic_error("Not implemented!");
235 }
236
237 bool stream_data(std::span<const uint8_t> data) override
238 {
239 throw std::logic_error("Not implemented!");
240 }
241
243 {
244 throw std::logic_error("Not implemented!");
245 }
246
249 {
250 throw std::logic_error("Not implemented!");
251 }
252 };
253
255 public ccf::ClientSession,
257 {
258 private:
259 ::http::ResponseParser response_parser;
260
261 public:
263 ::tcp::ConnID session_id_,
264 ringbuffer::AbstractWriterFactory& writer_factory,
265 std::unique_ptr<ccf::tls::Context> ctx) :
266 HTTPSession(session_id_, writer_factory, std::move(ctx)),
267 ClientSession(session_id_, writer_factory),
268 response_parser(*this)
269 {}
270
271 bool parse(std::span<const uint8_t> data) override
272 {
273 // Catch response parsing errors and log them
274 try
275 {
276 response_parser.execute(data.data(), data.size());
277
278 return true;
279 }
280 catch (const std::exception& e)
281 {
282 LOG_FAIL_FMT("Error parsing HTTP response on session {}", session_id);
283 LOG_DEBUG_FMT("Error parsing HTTP response: {}", e.what());
285 "Error occurred while parsing fragment {} byte fragment:\n{}",
286 data.size(),
287 std::string_view((char const*)data.data(), data.size()));
288
290 }
291 return false;
292 }
293
294 void send_request(http::Request&& request) override
295 {
296 auto data = request.build_request();
297 send_data(data);
298 }
299
301 const std::string& hostname,
302 const std::string& service,
303 const HandleDataCallback f,
304 const HandleErrorCallback e) override
305 {
306 tls_io->set_handshake_error_cb([e](std::string&& error_msg) {
307 if (e)
308 {
309 e(error_msg);
310 }
311 else
312 {
313 LOG_FAIL_FMT("{}", error_msg);
314 }
315 });
316
317 ccf::ClientSession::connect(hostname, service, f, e);
318 }
319
321 ccf::http_status status,
322 ccf::http::HeaderMap&& headers,
323 std::vector<uint8_t>&& body) override
324 {
325 handle_data_cb(status, std::move(headers), std::move(body));
326
327 LOG_TRACE_FMT("Closing connection, message handled");
329 }
330 };
331
333
335 public ccf::ClientSession,
337 {
338 private:
339 ::http::ResponseParser response_parser;
340
341 public:
343 ::tcp::ConnID session_id_,
344 ringbuffer::AbstractWriterFactory& writer_factory) :
345 UnencryptedHTTPSession(session_id_, writer_factory),
346 ClientSession(session_id_, writer_factory),
347 response_parser(*this)
348 {}
349
350 bool parse(std::span<const uint8_t> data) override
351 {
352 try
353 {
354 response_parser.execute(data.data(), data.size());
355 return true;
356 }
357 catch (const std::exception& e)
358 {
359 LOG_FAIL_FMT("Error parsing HTTP response on session {}", session_id);
360 LOG_DEBUG_FMT("Error parsing HTTP response: {}", e.what());
362 "Error occurred while parsing fragment {} byte fragment:\n{}",
363 data.size(),
364 std::string_view((char const*)data.data(), data.size()));
365
367 }
368 return false;
369 }
370
371 void send_request(http::Request&& request) override
372 {
373 auto data = request.build_request();
374 send_data(data);
375 }
376
378 const std::string& hostname,
379 const std::string& service,
380 const HandleDataCallback f,
381 const HandleErrorCallback e) override
382 {
383 ccf::ClientSession::connect(hostname, service, f, e);
384 }
385
387 ccf::http_status status,
388 ccf::http::HeaderMap&& headers,
389 std::vector<uint8_t>&& body) override
390 {
391 handle_data_cb(status, std::move(headers), std::move(body));
392 LOG_TRACE_FMT("Closing connection, message handled");
394 }
395 };
396}
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:39
std::function< void(const std::string &error_msg)> HandleErrorCallback
Definition client_session.h:19
std::function< void(ccf::http_status status, http::HeaderMap &&headers, std::vector< uint8_t > &&body)> HandleDataCallback
Definition client_session.h:16
HandleDataCallback handle_data_cb
Definition client_session.h:22
Definition session.h:80
void send_data(std::span< const uint8_t > data) override
Definition session.h:99
void close_session() override
Definition session.h:111
::tcp::ConnID session_id
Definition session.h:86
std::shared_ptr< ccf::TLSSession > tls_io
Definition session.h:85
void send_data(std::span< const uint8_t > data) override
Definition session.h:59
Definition session.h:156
::tcp::ConnID session_id
Definition session.h:161
void close_session() override
Definition session.h:181
Definition http_responder.h:16
bool send_odata_error_response(ccf::ErrorDetails &&error)
Definition http_responder.h:35
Definition http_session.h:257
HTTPClientSession(::tcp::ConnID session_id_, ringbuffer::AbstractWriterFactory &writer_factory, std::unique_ptr< ccf::tls::Context > ctx)
Definition http_session.h:262
void send_request(http::Request &&request) override
Definition http_session.h:294
void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body) override
Definition http_session.h:320
bool parse(std::span< const uint8_t > data) override
Definition http_session.h:271
void connect(const std::string &hostname, const std::string &service, const HandleDataCallback f, const HandleErrorCallback e) override
Definition http_session.h:300
Definition http_session.h:21
bool send_response(ccf::http_status status_code, ccf::http::HeaderMap &&headers, ccf::http::HeaderMap &&trailers, std::span< const uint8_t > body) override
Definition http_session.h:203
bool set_on_stream_close_callback(ccf::http::StreamOnCloseCallback cb) override
Definition http_session.h:247
bool close_stream(ccf::http::HeaderMap &&) override
Definition http_session.h:242
bool stream_data(std::span< const uint8_t > data) override
Definition http_session.h:237
bool start_stream(ccf::http_status status, const ccf::http::HeaderMap &headers) override
Definition http_session.h:231
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
HTTPServerSession(std::shared_ptr< ccf::RPCMap > rpc_map, ::tcp::ConnID session_id_, const 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 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:221
Definition http_exceptions.h:40
Definition http_parser.h:394
Definition http_exceptions.h:31
Definition http_proc.h:20
Definition http_builder.h:118
Definition http_parser.h:452
Definition http_proc.h:31
Definition http_builder.h:200
Definition http_session.h:337
bool parse(std::span< const uint8_t > data) override
Definition http_session.h:350
void send_request(http::Request &&request) override
Definition http_session.h:371
void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body) override
Definition http_session.h:386
UnencryptedHTTPClientSession(::tcp::ConnID session_id_, ringbuffer::AbstractWriterFactory &writer_factory)
Definition http_session.h:342
void connect(const std::string &hostname, const std::string &service, const HandleDataCallback f, const HandleErrorCallback e) override
Definition http_session.h:377
Definition ring_buffer_types.h:153
#define LOG_TRACE_FMT
Definition logger.h:356
#define LOG_DEBUG_FMT
Definition logger.h:357
#define LOG_FAIL_FMT
Definition logger.h:363
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
std::function< void(void)> StreamOnCloseCallback
Definition http_responder.h:13
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