userver: userver/server/handlers/http_handler_flatbuf_base.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
http_handler_flatbuf_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/handlers/http_handler_flatbuf_base.hpp
4/// @brief @copybrief server::handlers::HttpHandlerFlatbufBase
5
6#include <type_traits>
7
8#include <flatbuffers/flatbuffers.h>
9
10#include <userver/server/handlers/http_handler_base.hpp>
11#include <userver/server/http/http_error.hpp>
12#include <userver/utils/log.hpp>
13#include <userver/yaml_config/schema.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace server::handlers {
18
19namespace impl {
20
21inline const std::string kFlatbufRequestDataName = "__request_flatbuf";
22inline const std::string kFlatbufResponseDataName = "__response_flatbuf";
23
24} // namespace impl
25
26// clang-format off
27
28/// @ingroup userver_components userver_http_handlers userver_base_classes
29///
30/// @brief Convenient base for handlers that accept requests with body in
31/// Flatbuffer format and respond with body in Flatbuffer format.
32///
33/// ## Example usage:
34///
35/// @snippet samples/flatbuf_service/flatbuf_service.cpp Flatbuf service sample - component
36
37// clang-format on
38
39template <typename InputType, typename ReturnType>
41 static_assert(std::is_base_of<flatbuffers::Table, InputType>::value,
42 "Input type should be auto-generated FlatBuffers table type");
44 "Return type should be auto-generated FlatBuffers table type");
45
46 public:
47 HttpHandlerFlatbufBase(const components::ComponentConfig& config,
48 const components::ComponentContext& component_context);
49
50 std::string HandleRequestThrow(const http::HttpRequest& request,
51 request::RequestContext& context) const final;
52
53 virtual typename ReturnType::NativeTableType HandleRequestFlatbufThrow(
54 const http::HttpRequest& request,
55 const typename InputType::NativeTableType& input,
56 request::RequestContext& context) const = 0;
57
58 /// @returns A pointer to input data if it was parsed successfully or
59 /// nullptr otherwise.
60 const typename InputType::NativeTableType* GetInputData(
61 const request::RequestContext& context) const;
62
63 /// @returns a pointer to output data if it was returned successfully by
64 /// `HandleRequestFlatbufThrow()` or nullptr otherwise.
65 const typename ReturnType::NativeTableType* GetOutputData(
66 const request::RequestContext& context) const;
67
68 static yaml_config::Schema GetStaticConfigSchema();
69
70 protected:
71 /// Override it if you need a custom request body logging.
72 std::string GetRequestBodyForLogging(
73 const http::HttpRequest& request, request::RequestContext& context,
74 const std::string& request_body) const override;
75
76 /// Override it if you need a custom response data logging.
77 std::string GetResponseDataForLogging(
78 const http::HttpRequest& request, request::RequestContext& context,
79 const std::string& response_data) const override;
80
81 void ParseRequestData(const http::HttpRequest& request,
82 request::RequestContext& context) const final;
83};
84
85template <typename InputType, typename ReturnType>
86HttpHandlerFlatbufBase<InputType, ReturnType>::HttpHandlerFlatbufBase(
87 const components::ComponentConfig& config,
88 const components::ComponentContext& component_context)
89 : HttpHandlerBase(config, component_context) {}
90
91template <typename InputType, typename ReturnType>
92std::string HttpHandlerFlatbufBase<InputType, ReturnType>::HandleRequestThrow(
93 const http::HttpRequest& request, request::RequestContext& context) const {
94 const auto& input =
95 context.GetData<const typename InputType::NativeTableType&>(
96 impl::kFlatbufRequestDataName);
97
98 const auto& ret = context.SetData<const typename ReturnType::NativeTableType>(
99 impl::kFlatbufResponseDataName,
100 HandleRequestFlatbufThrow(request, input, context));
101
102 flatbuffers::FlatBufferBuilder fbb;
103 auto ret_fbb = ReturnType::Pack(fbb, &ret);
104 fbb.Finish(ret_fbb);
105 return {reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()};
106}
107
108template <typename InputType, typename ReturnType>
109const typename InputType::NativeTableType*
110HttpHandlerFlatbufBase<InputType, ReturnType>::GetInputData(
111 const request::RequestContext& context) const {
112 return context.GetDataOptional<const typename InputType::NativeTableType>(
113 impl::kFlatbufRequestDataName);
114}
115
116template <typename InputType, typename ReturnType>
117const typename ReturnType::NativeTableType*
118HttpHandlerFlatbufBase<InputType, ReturnType>::GetOutputData(
119 const request::RequestContext& context) const {
120 return context.GetDataOptional<const typename ReturnType::NativeTableType>(
121 impl::kFlatbufResponseDataName);
122}
123
124template <typename InputType, typename ReturnType>
125std::string
127 const http::HttpRequest&, request::RequestContext&,
128 const std::string& request_body) const {
129 size_t limit = GetConfig().request_body_size_log_limit;
130 return utils::log::ToLimitedHex(request_body, limit);
131}
132
133template <typename InputType, typename ReturnType>
134std::string
136 const http::HttpRequest&, request::RequestContext&,
137 const std::string& response_data) const {
138 size_t limit = GetConfig().response_data_size_log_limit;
139 return utils::log::ToLimitedHex(response_data, limit);
140}
141
142template <typename InputType, typename ReturnType>
143void HttpHandlerFlatbufBase<InputType, ReturnType>::ParseRequestData(
144 const http::HttpRequest& request, request::RequestContext& context) const {
145 const auto& body = request.RequestBody();
146 const auto* input_fbb = flatbuffers::GetRoot<InputType>(body.data());
147 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(body.data()),
148 body.size());
149 if (!input_fbb->Verify(verifier)) {
150 throw ClientError(
151 InternalMessage{"Invalid FlatBuffers format in request body"});
152 }
153
154 typename InputType::NativeTableType input;
155 input_fbb->UnPackTo(&input);
156
157 context.SetData(impl::kFlatbufRequestDataName, std::move(input));
158}
159
160template <typename InputType, typename ReturnType>
161yaml_config::Schema
162HttpHandlerFlatbufBase<InputType, ReturnType>::GetStaticConfigSchema() {
163 auto schema = HttpHandlerBase::GetStaticConfigSchema();
164 schema.UpdateDescription("HTTP handler flatbuf base config");
165 return schema;
166}
167
168} // namespace server::handlers
169
170USERVER_NAMESPACE_END