userver: userver/server/handlers/http_handler_base.hpp Source File
Loading...
Searching...
No Matches
http_handler_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/handlers/http_handler_base.hpp
4/// @brief @copybrief server::handlers::HttpHandlerBase
5
6#include <memory>
7#include <optional>
8#include <string>
9#include <vector>
10
11#include <userver/dynamic_config/source.hpp>
12#include <userver/logging/level.hpp>
13#include <userver/utils/token_bucket.hpp>
14
15#include <userver/server/handlers/exceptions.hpp>
16#include <userver/server/handlers/formatted_error_data.hpp>
17#include <userver/server/handlers/handler_base.hpp>
18#include <userver/server/http/http_request.hpp>
19#include <userver/server/http/http_response.hpp>
20#include <userver/server/http/http_response_body_stream_fwd.hpp>
21// Not needed here, but a lot of code depends on it being included transitively
22#include <userver/tracing/span.hpp>
23
24USERVER_NAMESPACE_BEGIN
25
26namespace server::middlewares {
28class HandlerAdapter;
29class HandlerMetrics;
30class Auth;
31} // namespace server::middlewares
32
33/// @brief Most common \ref userver_http_handlers "userver HTTP handlers"
34namespace server::handlers {
35
36class HttpHandlerStatistics;
37class HttpHandlerStatisticsAggregate;
38class HttpHandlerMethodStatistics;
39class HttpHandlerStatisticsScope;
40
41/// @ingroup userver_components userver_http_handlers userver_base_classes
42///
43/// @brief Base class for all the @ref userver_http_handlers "Userver HTTP Handlers".
44///
45/// ## Static options of server::handlers::HttpHandlerBase :
46/// @include{doc} scripts/docs/en/components_schema/core/src/server/handlers/http_handler_base.md
47///
48/// Options inherited from @ref server::handlers::HandlerBase :
49/// @include{doc} scripts/docs/en/components_schema/core/src/server/handlers/handler_base.md
50///
51/// Options inherited from @ref components::ComponentBase :
52/// @include{doc} scripts/docs/en/components_schema/core/src/components/impl/component_base.md
53///
54/// ## Example usage:
55///
56/// @include samples/hello_service/src/hello_handler.hpp
57/// @include samples/hello_service/src/hello_handler.cpp
59public:
60 HttpHandlerBase(
61 const components::ComponentConfig& config,
62 const components::ComponentContext& component_context,
63 bool is_monitor = false
64 );
65
66 ~HttpHandlerBase() override;
67
68 void PrepareAndHandleRequest(http::HttpRequest& request, request::RequestContext& context) const override;
69
70 void ReportMalformedRequest(http::HttpRequest& request) const final;
71
72 /// @brief Returns the name of this handler (static config section name)
73 virtual const std::string& HandlerName() const;
74
75 const std::vector<http::HttpMethod>& GetAllowedMethods() const;
76
77 /// @cond
78 // For internal use only.
79 HttpHandlerStatisticsAggregate& GetHandlerStatistics() const;
80 /// @endcond
81
82 /// Override it if you need a custom logging level for messages about finish
83 /// of request handling for some http statuses.
84 virtual logging::Level GetLogLevelForResponseStatus(http::HttpStatus status) const;
85
86 virtual FormattedErrorData GetFormattedExternalErrorBody(const CustomHandlerException& exc) const;
87
88 std::string GetResponseDataForLoggingChecked(
89 const http::HttpRequest& request,
90 request::RequestContext& context,
91 const std::string& response_data
92 ) const;
93
94 std::string GetUrlForLoggingChecked(const http::HttpRequest& request, request::RequestContext& context) const;
95
96 /// Takes the exception and formats it into response, as specified by
97 /// exception.
99 const http::HttpRequest& request,
100 request::RequestContext& context,
101 const CustomHandlerException& ex
102 ) const;
103
104 /// Takes the exception and formats it into response as an internal server
105 /// error.
107 const http::HttpRequest& request,
108 request::RequestContext& context,
109 const std::exception& ex
110 ) const;
111
112 /// Helper function to log an unknown exception
113 void LogUnknownException(const std::exception& ex, std::optional<logging::Level> log_level_override = {}) const;
114
115 /// Returns the default log level for the handler
116 const std::optional<logging::Level>& GetLogLevel() const;
117
118 static yaml_config::Schema GetStaticConfigSchema();
119
120 /// Override it if you need a custom streamed logic based on request and context.
121 /// @note The default implementation returns the cached value of
122 /// "response-body-streamed" value from static config.
123 virtual bool IsStreamed(const http::HttpRequest&, server::request::RequestContext&) const {
125 }
126
127protected:
128 /// @brief Override in handlers that set response body directly (e.g. via
129 /// @ref server::request::ResponseBase::SetSharedData) or to implement a more complex streaming logic than the
130 /// IsStreamed overloading allows.
131 virtual void HandleMaybeStreamRequest(http::HttpRequest& request, request::RequestContext& context) const;
132
133 [[noreturn]] void ThrowUnsupportedHttpMethod(const http::HttpRequest& request) const;
134
135 /// Same as `HandleRequest`.
136 virtual std::string HandleRequestThrow(const http::HttpRequest& request, request::RequestContext& context) const;
137
138 /// The core method for HTTP request handling.
139 /// `request` arg contains HTTP headers, full body, etc. The method should return response body.
140 /// @note It is used only if IsStreamed() returned `false`.
141 virtual std::string HandleRequest(http::HttpRequest& request, request::RequestContext& context) const;
142
143 /// The core method for HTTP request handling, that is used only if @ref IsStreamed() returned `true`.
144 /// `request` arg contains HTTP headers, full body, etc.
145 /// The response body is passed in parts to `ResponseBodyStream`.
146 /// Stream transmission is useful when:
147 /// 1) The body size is unknown beforehand.
148 /// 2) The client may take advantage of early body transmission (e.g. a Web Browser may start rendering the HTML
149 /// page or downloading dependent resources).
150 /// 3) The body size is huge and we want to have only a part of it in memory.
151 ///
152 /// Example usage:
153 /// @snippet core/functional_tests/basic_chaos/httpclient_handlers.hpp HandleStreamRequest
154 ///
155 /// @see @ref scripts/docs/en/userver/http_server.md
156 virtual void
157 HandleStreamRequest(server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
158 const;
159
160 /// @returns the cached value of "response-body-streamed" value from static config.
161 bool IsBodyStreamingEnabledInConfig() const noexcept { return is_body_streamed_; }
162
163 /// Override it to show per HTTP-method statistics besides statistics for all
164 /// methods
165 virtual bool IsMethodStatisticIncluded() const { return false; }
166
167 /// Override it if you want to disable auth checks in handler by some
168 /// condition
169 virtual bool NeedCheckAuth() const { return true; }
170
171 /// Override it if you need a custom request body logging.
172 virtual std::string GetRequestBodyForLogging(
173 const http::HttpRequest& request,
174 request::RequestContext& context,
175 const std::string& request_body
176 ) const;
177
178 /// Override it if you need a custom response data logging.
179 virtual std::string GetResponseDataForLogging(
180 const http::HttpRequest& request,
181 request::RequestContext& context,
182 const std::string& response_data
183 ) const;
184
185 /// Override it if you need a custom request url logging.
186 virtual std::string GetUrlForLogging(const http::HttpRequest& request, request::RequestContext& context) const;
187
188 /// For internal use. You don't need to override it. This method is overridden
189 /// in format-specific base handlers.
190 virtual void ParseRequestData(const http::HttpRequest&, request::RequestContext&) const {}
191
192 virtual std::string GetMetaType(const http::HttpRequest&) const;
193
194private:
195 friend class middlewares::HandlerAdapter;
196 friend class middlewares::HandlerMetrics;
197 friend class middlewares::Auth;
198
199 void HandleHttpRequest(http::HttpRequest& request, request::RequestContext& context) const;
200
201 std::string GetRequestBodyForLoggingChecked(
202 const http::HttpRequest& request,
203 request::RequestContext& context,
204 const std::string& request_body
205 ) const;
206
207 template <typename HttpStatistics>
208 void FormatStatistics(utils::statistics::Writer result, const HttpStatistics& stats);
209
210 void FormatPerLabelStatistics(utils::statistics::Writer result) const;
211
212 void SetResponseServerHostname(http::HttpResponse& response) const;
213
214 void BuildMiddlewarePipeline(const components::ComponentConfig&, const components::ComponentContext&);
215
216 const dynamic_config::Source config_source_;
217 const std::vector<http::HttpMethod> allowed_methods_;
218 const std::string handler_name_;
219 std::optional<logging::Level> log_level_;
220 std::unordered_map<int, logging::Level> log_level_for_status_codes_;
221
222 std::unique_ptr<HttpHandlerStatisticsAggregate> handler_statistics_;
223
224 bool set_response_server_hostname_;
225 bool is_body_streamed_;
226
227 std::unique_ptr<middlewares::HttpMiddlewareBase> first_middleware_;
228};
229
230} // namespace server::handlers
231
232USERVER_NAMESPACE_END