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