Skip to content

Commit d1356ef

Browse files
committed
feat server: allow request body moving out
commit_hash:86bcb7d10acf464a468c10b2c04916403585eda0
1 parent dfb20c9 commit d1356ef

File tree

34 files changed

+64
-72
lines changed

34 files changed

+64
-72
lines changed

core/functional_tests/basic_chaos/httpclient_handlers.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class StreamHandler : public server::handlers::HttpHandlerBase {
6868

6969
/// [HandleStreamRequest]
7070
void HandleStreamRequest(
71-
const server::http::HttpRequest& request,
71+
server::http::HttpRequest& request,
7272
server::request::RequestContext&,
7373
server::http::ResponseBodyStream& response_body_stream
7474
) const override {

core/functional_tests/http2server/service.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class HandlerHttp2 final : public server::handlers::HttpHandlerBase {
3636
};
3737

3838
void HandleStreamRequest(
39-
const server::http::HttpRequest& req,
39+
server::http::HttpRequest& req,
4040
server::request::RequestContext&,
4141
server::http::ResponseBodyStream& stream
4242
) const override {

core/include/userver/server/handlers/handler_base.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class HandlerBase : public components::ComponentBase {
5757

5858
/// Parses request, executes processing routines, and fills response
5959
/// accordingly. Does not throw.
60-
virtual void HandleRequest(http::HttpRequest& request, request::RequestContext& context) const = 0;
60+
virtual void PrepareAndHandleRequest(http::HttpRequest& request, request::RequestContext& context) const = 0;
6161

6262
/// Produces response to a request unrecognized by the protocol based on
6363
/// provided generic response. Does not throw.

core/include/userver/server/handlers/http_handler_base.hpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class HttpHandlerBase : public HandlerBase {
7272

7373
~HttpHandlerBase() override;
7474

75-
void HandleRequest(http::HttpRequest& request, request::RequestContext& context) const override;
75+
void PrepareAndHandleRequest(http::HttpRequest& request, request::RequestContext& context) const override;
7676

7777
void ReportMalformedRequest(http::HttpRequest& request) const final;
7878

@@ -119,11 +119,14 @@ class HttpHandlerBase : public HandlerBase {
119119
protected:
120120
[[noreturn]] void ThrowUnsupportedHttpMethod(const http::HttpRequest& request) const;
121121

122+
/// Same as `HandleRequest`.
123+
virtual std::string HandleRequestThrow(const http::HttpRequest& request, request::RequestContext& context) const;
124+
122125
/// The core method for HTTP request handling.
123126
/// `request` arg contains HTTP headers, full body, etc.
124127
/// The method should return response body.
125128
/// @note It is used only if IsStreamed() returned `false`.
126-
virtual std::string HandleRequestThrow(const http::HttpRequest& request, request::RequestContext& context) const;
129+
virtual std::string HandleRequest(http::HttpRequest& request, request::RequestContext& context) const;
127130

128131
/// The core method for HTTP request handling.
129132
/// `request` arg contains HTTP headers, full body, etc.
@@ -137,12 +140,12 @@ class HttpHandlerBase : public HandlerBase {
137140
/// in memory.
138141
/// @note It is used only if IsStreamed() returned `true`.
139142
virtual void
140-
HandleStreamRequest(const server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
143+
HandleStreamRequest(server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
141144
const;
142145

143146
/// If IsStreamed() returns `true`, call HandleStreamRequest()
144-
/// for request handling, HandleRequestThrow() is not called.
145-
/// If it returns `false`, HandleRequestThrow() is called instead,
147+
/// for request handling, HandleRequest() is not called.
148+
/// If it returns `false`, HandleRequest() is called instead,
146149
/// and HandleStreamRequest() is not called.
147150
/// @note The default implementation returns the cached value of
148151
/// "response-body-streamed" value from static config.
@@ -182,7 +185,7 @@ class HttpHandlerBase : public HandlerBase {
182185

183186
void HandleHttpRequest(http::HttpRequest& request, request::RequestContext& context) const;
184187

185-
void HandleRequestStream(const http::HttpRequest& http_request, request::RequestContext& context) const;
188+
void HandleRequestStream(http::HttpRequest& http_request, request::RequestContext& context) const;
186189

187190
std::string GetRequestBodyForLoggingChecked(
188191
const http::HttpRequest& request,

core/include/userver/server/http/http_request.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class HttpRequest final {
207207
/// @return HTTP body.
208208
const std::string& RequestBody() const;
209209

210+
/// @return moved out HTTP body. `this` is modified.
211+
std::string ExtractRequestBody();
212+
210213
/// @cond
211214
void SetRequestBody(std::string body);
212215
void ParseArgsFromBody();

core/src/server/handlers/http_handler_base.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,7 @@ HttpHandlerBase::HttpHandlerBase(
198198

199199
HttpHandlerBase::~HttpHandlerBase() { statistics_holder_.Unregister(); }
200200

201-
void HttpHandlerBase::HandleRequestStream(const http::HttpRequest& http_request, request::RequestContext& context)
202-
const {
201+
void HttpHandlerBase::HandleRequestStream(http::HttpRequest& http_request, request::RequestContext& context) const {
203202
auto& response = http_request.GetHttpResponse();
204203
const utils::ScopeGuard scope([&response] { response.SetHeadersEnd(); });
205204

@@ -254,11 +253,11 @@ void HttpHandlerBase::HandleHttpRequest(http::HttpRequest& http_request, request
254253
HandleRequestStream(http_request, context);
255254
} else {
256255
// !IsBodyStreamed()
257-
response.SetData(HandleRequestThrow(http_request, context));
256+
response.SetData(HandleRequest(http_request, context));
258257
}
259258
}
260259

261-
void HttpHandlerBase::HandleRequest(http::HttpRequest& http_request, request::RequestContext& context) const {
260+
void HttpHandlerBase::PrepareAndHandleRequest(http::HttpRequest& http_request, request::RequestContext& context) const {
262261
auto& response = http_request.GetHttpResponse();
263262

264263
context.GetInternalContext().SetConfigSnapshot(config_source_.GetSnapshot());
@@ -288,13 +287,18 @@ void HttpHandlerBase::ThrowUnsupportedHttpMethod(const http::HttpRequest& reques
288287

289288
std::string HttpHandlerBase::HandleRequestThrow(const http::HttpRequest&, request::RequestContext&) const {
290289
throw std::runtime_error(
291-
"non-stream HandleRequestThrow() is executed, but the handler doesn't "
292-
"override HandleRequestThrow()."
290+
"non-stream HandleRequest() is executed, but the handler doesn't "
291+
"override HandleRequest()."
293292
);
294293
}
295294

295+
std::string HttpHandlerBase::HandleRequest(http::HttpRequest& request, request::RequestContext& context) const {
296+
// Default implementation proxies the request to legacy HandleRequestThrow()
297+
return HandleRequestThrow(request, context);
298+
}
299+
296300
void HttpHandlerBase::
297-
HandleStreamRequest(const server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
301+
HandleStreamRequest(server::http::HttpRequest&, server::request::RequestContext&, server::http::ResponseBodyStream&)
298302
const {
299303
throw std::runtime_error(
300304
"stream HandleStreamRequest() is executed, but the handler doesn't "

core/src/server/http/http_request.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ const HttpRequest::CookiesMap& HttpRequest::RequestCookies() const { return pimp
227227

228228
const std::string& HttpRequest::RequestBody() const { return pimpl_->request_body_; }
229229

230+
std::string HttpRequest::ExtractRequestBody() { return std::move(pimpl_->request_body_); }
231+
230232
void HttpRequest::SetRequestBody(std::string body) { pimpl_->request_body_ = std::move(body); }
231233

232234
void HttpRequest::ParseArgsFromBody() {

core/src/server/http/http_request_handler.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ engine::TaskWithResult<void> HttpRequestHandler::StartRequestTask(std::shared_pt
153153
request->SetTaskStartTime();
154154

155155
request::RequestContext context;
156-
handler->HandleRequest(*request, context);
156+
handler->PrepareAndHandleRequest(*request, context);
157157

158158
const auto now = std::chrono::steady_clock::now();
159159
request->SetResponseNotifyTime(now);

samples/chaotic_service/src/hello_service.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ class Hello final : public server::handlers::HttpHandlerBase {
1919
using HttpHandlerBase::HttpHandlerBase;
2020

2121
/// [Handler]
22-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
23-
const override {
22+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override {
2423
request.GetHttpResponse().SetContentType(http::content_type::kApplicationJson);
2524

2625
auto request_json = formats::json::FromString(request.RequestBody());

samples/clickhouse_service/clickhouse_service.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class HandlerDb final : public server::handlers::HttpHandlerBase {
3434

3535
HandlerDb(const components::ComponentConfig& config, const components::ComponentContext& context);
3636

37-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& context)
37+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext& context)
3838
const override;
3939

4040
private:
@@ -45,8 +45,7 @@ HandlerDb::HandlerDb(const components::ComponentConfig& config, const components
4545
: server::handlers::HttpHandlerBase{config, context},
4646
clickhouse_{context.FindComponent<components::ClickHouse>("clickhouse-database").GetCluster()} {}
4747

48-
std::string HandlerDb::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
49-
const {
48+
std::string HandlerDb::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const {
5049
const auto& limit = request.GetArg("limit");
5150
// FP?: pfr magic
5251
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)

samples/digest_auth_service/digest_auth_service.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Hello final : public server::handlers::HttpHandlerBase {
2323

2424
using HttpHandlerBase::HttpHandlerBase;
2525

26-
std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override {
26+
std::string HandleRequest(server::http::HttpRequest&, server::request::RequestContext&) const override {
2727
return "Hello world";
2828
}
2929
};

samples/grpc_middleware_service/src/http_handlers/say-hello/view.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ GreeterHttpHandler::GreeterHttpHandler(
1111
)
1212
: HttpHandlerBase(config, context), grpc_greeter_client_(context.FindComponent<GreeterClient>()) {}
1313

14-
std::string
15-
GreeterHttpHandler::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
14+
std::string GreeterHttpHandler::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&)
1615
const {
1716
return grpc_greeter_client_.SayHello(request.RequestBody());
1817
}

samples/grpc_middleware_service/src/http_handlers/say-hello/view.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ class GreeterHttpHandler final : public server::handlers::HttpHandlerBase {
1414

1515
GreeterHttpHandler(const components::ComponentConfig& config, const components::ComponentContext& context);
1616

17-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
18-
const override;
17+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override;
1918

2019
private:
2120
GreeterClient& grpc_greeter_client_;

samples/grpc_service/src/call_greeter_client_test_handler.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ class CallGreeterClientTestHandler final : public server::handlers::HttpHandlerB
2020
: HttpHandlerBase(config, context),
2121
grpc_greeter_client_(context.FindComponent<GreeterClientComponent>().GetClient()) {}
2222

23-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
24-
const override {
23+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override {
2524
const auto& arg_case = request.GetArg("case");
2625
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
2726

samples/hello_service/src/hello_handler.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace samples::hello {
66

7-
std::string HelloHandler::
8-
HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& /*request_context*/)
9-
const {
7+
std::string
8+
HelloHandler::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext& /*request_context*/)
9+
const {
1010
// Setting Content-Type: text/plain in a microservice response ensures
1111
// the client interprets it as plain text, preventing misinterpretation or
1212
// errors. Without this header, the client might assume a different format,

samples/hello_service/src/hello_handler.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ class HelloHandler final : public server::handlers::HttpHandlerBase {
1616
// Component is valid after construction and is able to accept requests
1717
using HttpHandlerBase::HttpHandlerBase;
1818

19-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
20-
const override;
19+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override;
2120
};
2221

2322
} // namespace samples::hello

samples/http_caching/http_caching.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ class GreetUser final : public server::handlers::HttpHandlerBase {
188188
GreetUser(const components::ComponentConfig& config, const components::ComponentContext& context)
189189
: HttpHandlerBase(config, context), cache_(context.FindComponent<HttpCachedTranslations>()) {}
190190

191-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
192-
const override {
191+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override {
193192
const auto cache_snapshot = cache_.Get();
194193

195194
using samples::http_cache::KeyLang;

samples/http_middleware_service/http_middleware_service.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Handler final : public server::handlers::HttpHandlerBase {
1515
public:
1616
using HttpHandlerBase::HttpHandlerBase;
1717

18-
std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override {
18+
std::string HandleRequest(server::http::HttpRequest&, server::request::RequestContext&) const override {
1919
return "Hello world!\n";
2020
}
2121
};

samples/https_service/hello_service.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ class Hello final : public server::handlers::HttpHandlerBase {
1717
// Component is valid after construction and is able to accept requests
1818
using HttpHandlerBase::HttpHandlerBase;
1919

20-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
21-
const override {
20+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override {
2221
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
2322
return "Hello world!\n";
2423
}

samples/mongo_service/mongo_service.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class Translations final : public server::handlers::HttpHandlerBase {
1818
Translations(const components::ComponentConfig& config, const components::ComponentContext& context)
1919
: HttpHandlerBase(config, context), pool_(context.FindComponent<components::Mongo>("mongo-tr").GetPool()) {}
2020

21-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
22-
const override {
21+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override {
2322
request.GetHttpResponse().SetContentType(http::content_type::kApplicationJson);
2423
if (request.GetMethod() == server::http::HttpMethod::kPatch) {
2524
InsertNew(request);

samples/multipart_service/service.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ class Multipart final : public server::handlers::HttpHandlerBase {
1717
// Component is valid after construction and is able to accept requests
1818
using HttpHandlerBase::HttpHandlerBase;
1919

20-
std::string HandleRequestThrow(const server::http::HttpRequest& req, server::request::RequestContext&)
21-
const override;
20+
std::string HandleRequest(server::http::HttpRequest& req, server::request::RequestContext&) const override;
2221
};
2322
/// [Multipart service sample - component]
2423

2524
/// [Multipart service sample - HandleRequestThrow]
26-
std::string Multipart::HandleRequestThrow(const server::http::HttpRequest& req, server::request::RequestContext&)
27-
const {
25+
std::string Multipart::HandleRequest(server::http::HttpRequest& req, server::request::RequestContext&) const {
2826
const auto content_type = http::ContentType(req.GetHeader(http::headers::kContentType));
2927
if (content_type != "multipart/form-data") {
3028
req.GetHttpResponse().SetStatus(server::http::HttpStatus::kBadRequest);

samples/postgres_auth/postgres_service.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ class Hello final : public server::handlers::HttpHandlerBase {
2222

2323
using HttpHandlerBase::HttpHandlerBase;
2424

25-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& ctx)
26-
const override {
25+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext& ctx) const override {
2726
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
2827
return "Hello world, " + ctx.GetData<std::string>("name") + "!\n";
2928
}

samples/postgres_service/postgres_service.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ class KeyValue final : public server::handlers::HttpHandlerBase {
2222

2323
KeyValue(const components::ComponentConfig& config, const components::ComponentContext& context);
2424

25-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
26-
const override;
25+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override;
2726

2827
private:
2928
std::string GetValue(std::string_view key, const server::http::HttpRequest& request) const;
@@ -48,8 +47,7 @@ KeyValue::KeyValue(const components::ComponentConfig& config, const components::
4847
/// [Postgres service sample - component constructor]
4948

5049
/// [Postgres service sample - HandleRequestThrow]
51-
std::string KeyValue::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
52-
const {
50+
std::string KeyValue::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const {
5351
const auto& key = request.GetArg("key");
5452
if (key.empty()) {
5553
throw server::handlers::ClientError(server::handlers::ExternalBody{"No 'key' query argument"});

samples/redis_service/redis_service.cpp

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ class EvalSha final : public server::handlers::HttpHandlerBase {
2323

2424
EvalSha(const components::ComponentConfig& config, const components::ComponentContext& context);
2525

26-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
27-
const override;
26+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override;
2827

2928
private:
3029
std::string EvalShaRequest(const server::http::HttpRequest& request) const;
@@ -40,8 +39,7 @@ class KeyValue final : public server::handlers::HttpHandlerBase {
4039

4140
KeyValue(const components::ComponentConfig& config, const components::ComponentContext& context);
4241

43-
std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
44-
const override;
42+
std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override;
4543

4644
private:
4745
std::string GetValue(std::string_view key, const server::http::HttpRequest& request) const;
@@ -65,8 +63,7 @@ KeyValue::KeyValue(const components::ComponentConfig& config, const components::
6563
/// [Redis service sample - component constructor]
6664

6765
/// [Redis service sample - HandleRequestThrow]
68-
std::string
69-
KeyValue::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& /*context*/)
66+
std::string KeyValue::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext& /*context*/)
7067
const {
7168
const auto& key = request.GetArg("key");
7269
if (key.empty()) {
@@ -124,8 +121,7 @@ EvalSha::EvalSha(const components::ComponentConfig& config, const components::Co
124121
: server::handlers::HttpHandlerBase(config, context),
125122
redis_client_{context.FindComponent<components::Redis>("key-value-database").GetClient("taxi-tmp")} {}
126123

127-
std::string EvalSha::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&)
128-
const {
124+
std::string EvalSha::HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const {
129125
const auto& command = request.GetArg("command");
130126
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);
131127

samples/testsuite-support/src/dynamic_config.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ DynamicConfig::DynamicConfig(const components::ComponentConfig& config, const co
1717
: server::handlers::HttpHandlerBase(config, context),
1818
config_source_(context.FindComponent<components::DynamicConfig>().GetSource()) {}
1919

20-
std::string DynamicConfig::HandleRequestThrow(
21-
[[maybe_unused]] const server::http::HttpRequest& request,
20+
std::string DynamicConfig::HandleRequest(
21+
[[maybe_unused]] server::http::HttpRequest& request,
2222
[[maybe_unused]] server::request::RequestContext& context
2323
) const {
2424
request.GetHttpResponse().SetContentType(http::content_type::kTextPlain);

0 commit comments

Comments
 (0)