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 /// Takes the exception and formats it into response, as specified by
104 /// exception.
105 void HandleCustomHandlerException(const http::HttpRequest& request, const CustomHandlerException& ex) const;
106
107 /// Takes the exception and formats it into response as an internal server
108 /// error.
109 void HandleUnknownException(const http::HttpRequest& request, const std::exception& ex) const;
110
111 /// Helper function to log an unknown exception
112 void LogUnknownException(const std::exception& ex, std::optional<logging::Level> log_level_override = {}) const;
113
114 /// Returns the default log level for the handler
115 const std::optional<logging::Level>& GetLogLevel() const;
116
117 static yaml_config::Schema GetStaticConfigSchema();
118
119protected:
120 [[noreturn]] void ThrowUnsupportedHttpMethod(const http::HttpRequest& request) const;
121
122 /// Same as `HandleRequest`.
123 virtual std::string HandleRequestThrow(const http::HttpRequest& request, request::RequestContext& context) const;
124
125 /// The core method for HTTP request handling.
126 /// `request` arg contains HTTP headers, full body, etc.
127 /// The method should return response body.
128 /// @note It is used only if IsStreamed() returned `false`.
129 virtual std::string HandleRequest(http::HttpRequest& request, request::RequestContext& context) const;
130
131 /// The core method for HTTP request handling.
132 /// `request` arg contains HTTP headers, full body, etc.
133 /// The response body is passed in parts to `ResponseBodyStream`.
134 /// Stream transmission is useful when:
135 /// 1) The body size is unknown beforehand.
136 /// 2) The client may take advantage of early body transmission
137 /// (e.g. a Web Browser may start rendering the HTML page
138 /// or downloading dependant resources).
139 /// 3) The body size is huge and we want to have only a part of it
140 /// in memory.
141 /// @note It is used only if IsStreamed() returned `true`.
142 virtual void
143 HandleStreamRequest(server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
144 const;
145
146 /// If IsStreamed() returns `true`, call HandleStreamRequest()
147 /// for request handling, HandleRequest() is not called.
148 /// If it returns `false`, HandleRequest() is called instead,
149 /// and HandleStreamRequest() is not called.
150 /// @note The default implementation returns the cached value of
151 /// "response-body-streamed" value from static config.
152 virtual bool IsStreamed() const { return is_body_streamed_; }
153
154 /// Override it to show per HTTP-method statistics besides statistics for all
155 /// methods
156 virtual bool IsMethodStatisticIncluded() const { return false; }
157
158 /// Override it if you want to disable auth checks in handler by some
159 /// condition
160 virtual bool NeedCheckAuth() const { return true; }
161
162 /// Override it if you need a custom request body logging.
163 virtual std::string GetRequestBodyForLogging(
164 const http::HttpRequest& request,
165 request::RequestContext& context,
166 const std::string& request_body
167 ) const;
168
169 /// Override it if you need a custom response data logging.
170 virtual std::string GetResponseDataForLogging(
171 const http::HttpRequest& request,
172 request::RequestContext& context,
173 const std::string& response_data
174 ) const;
175
176 /// For internal use. You don't need to override it. This method is overridden
177 /// in format-specific base handlers.
178 virtual void ParseRequestData(const http::HttpRequest&, request::RequestContext&) const {}
179
180 virtual std::string GetMetaType(const http::HttpRequest&) const;
181
182private:
183 friend class middlewares::HandlerAdapter;
184 friend class middlewares::Auth;
185
186 void HandleHttpRequest(http::HttpRequest& request, request::RequestContext& context) const;
187
188 void HandleRequestStream(http::HttpRequest& http_request, request::RequestContext& context) const;
189
190 std::string GetRequestBodyForLoggingChecked(
191 const http::HttpRequest& request,
192 request::RequestContext& context,
193 const std::string& request_body
194 ) const;
195
196 template <typename HttpStatistics>
197 void FormatStatistics(utils::statistics::Writer result, const HttpStatistics& stats);
198
199 void SetResponseServerHostname(http::HttpResponse& response) const;
200
201 void BuildMiddlewarePipeline(const components::ComponentConfig&, const components::ComponentContext&);
202
203 const dynamic_config::Source config_source_;
204 const std::vector<http::HttpMethod> allowed_methods_;
205 const std::string handler_name_;
206 utils::statistics::Entry statistics_holder_;
207 std::optional<logging::Level> log_level_;
208 std::unordered_map<int, logging::Level> log_level_for_status_codes_;
209
210 std::unique_ptr<HttpHandlerStatistics> handler_statistics_;
211 std::unique_ptr<HttpRequestStatistics> request_statistics_;
212
213 bool set_response_server_hostname_;
214 bool is_body_streamed_;
215
216 std::unique_ptr<middlewares::HttpMiddlewareBase> first_middleware_;
217};
218
219} // namespace server::handlers
220
221USERVER_NAMESPACE_END