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