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