userver: userver/server/http/http_response.hpp Source File
Loading...
Searching...
No Matches
http_response.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/http/http_response.hpp
4/// @brief @copybrief server::http::HttpResponse
5
6#include <chrono>
7#include <string>
8#include <variant>
9
10#include <userver/concurrent/queue.hpp>
11#include <userver/engine/single_consumer_event.hpp>
12#include <userver/http/content_type.hpp>
13#include <userver/http/header_map.hpp>
14#include <userver/server/http/http_response_cookie.hpp>
15#include <userver/server/request/response_base.hpp>
16#include <userver/utils/impl/projecting_view.hpp>
17#include <userver/utils/str_icase.hpp>
18
19#include "http_status.hpp"
20
21USERVER_NAMESPACE_BEGIN
22
23namespace server::http {
24
25// RFC 9110 states that in case of missing Content-Type it may be assumed to be
26// application/octet-stream.
27//
28// text/plain was our first guess, but we should provide an encoding with that
29// type, which we do not know for sure. "application/octet-stream" has no
30// charset https://www.iana.org/assignments/media-types/application/octet-stream
31inline constexpr std::string_view kDefaultContentType = "application/octet-stream";
32
33class Http2ResponseWriter;
34
35namespace impl {
36
37void OutputHeader(USERVER_NAMESPACE::http::headers::HeadersString& header, std::string_view key, std::string_view val);
38
39} // namespace impl
40
41class HttpRequest;
42
43/// @brief HTTP Response data
44class HttpResponse final : public request::ResponseBase {
45public:
46 using HeadersMap = USERVER_NAMESPACE::http::headers::HeaderMap;
47
48 using HeadersMapKeys = decltype(utils::impl::MakeKeysView(HeadersMap()));
49
50 using CookiesMap = Cookie::CookiesMap;
51
52 using CookiesMapKeys = decltype(utils::impl::MakeKeysView(CookiesMap()));
53
54 /// @cond
55 HttpResponse(const HttpRequest& request, request::ResponseDataAccounter& data_accounter);
56 HttpResponse(
57 const HttpRequest& request,
58 request::ResponseDataAccounter& data_accounter,
59 std::chrono::steady_clock::time_point now,
60 utils::StrCaseHash hasher
61 );
62 ~HttpResponse() override;
63
64 void SetSendFailed(std::chrono::steady_clock::time_point failure_time) override;
65 /// @endcond
66
67 /// @brief Add a new response header or rewrite an existing one.
68 /// @returns true if the header was set. Returns false if headers
69 /// were already sent for stream'ed response and the new header was not set.
70 bool SetHeader(std::string name, std::string value);
71
72 /// @brief Add a new response header or rewrite an existing one.
73 /// @returns true if the header was set. Returns false if headers
74 /// were already sent for stream'ed response and the new header was not set.
75 bool SetHeader(std::string_view name, std::string value);
76
77 /// @overload
78 bool SetHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header, std::string value);
79
80 /// @brief Add or rewrite the Content-Type header.
81 void SetContentType(const USERVER_NAMESPACE::http::ContentType& type);
82
83 /// @brief Add or rewrite the Content-Encoding header.
84 void SetContentEncoding(std::string encoding);
85
86 /// @brief Set the HTTP response status code.
87 /// @returns true if the status was set. Returns false if headers
88 /// were already sent for stream'ed response and the new status was not set.
89 bool SetStatus(HttpStatus status);
90
91 /// @brief Remove all headers from response.
92 /// @returns true if the headers were cleared. Returns false if headers
93 /// were already sent for stream'ed response and the headers were not cleared.
95
96 /// @brief Sets a cookie if it was not set before.
97 void SetCookie(Cookie cookie);
98
99 /// @brief Remove all cookies from response.
101
102 /// @return HTTP response status
103 HttpStatus GetStatus() const { return status_; }
104
105 /// @return List of HTTP headers names.
107
108 /// @return Value of the header with case insensitive name header_name, or an
109 /// empty string if no such header.
110 const std::string& GetHeader(std::string_view header_name) const;
111 /// @overload
112 const std::string& GetHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name) const;
113
114 /// @return true if header with case insensitive name header_name exists,
115 /// false otherwise.
116 bool HasHeader(std::string_view header_name) const;
117 /// @overload
118 bool HasHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name) const;
119
120 /// @return List of cookies names.
122
123 /// @return Value of the cookie with case sensitive name cookie_name, or an
124 /// empty string if no such cookie exists.
125 const Cookie& GetCookie(std::string_view cookie_name) const;
126
127 /// @cond
128 // TODO: server internals. remove from public interface
129 void SendResponse(engine::io::RwBase& socket) override;
130 /// @endcond
131
132 void SetStatusServiceUnavailable() override { SetStatus(HttpStatus::kServiceUnavailable); }
133 void SetStatusOk() override { SetStatus(HttpStatus::kOk); }
134 void SetStatusNotFound() override { SetStatus(HttpStatus::kNotFound); }
135
136 bool WaitForHeadersEnd() override;
137 void SetHeadersEnd() override;
138
139 using Queue = concurrent::StringStreamQueue;
140 using Producer = std::variant<std::monostate, Queue::Producer, impl::Http2StreamEventProducer>;
141
142 void SetStreamBody();
143 bool IsBodyStreamed() const override;
144 // Can be called only once
145 Producer GetBodyProducer();
146
147private:
148 friend class Http2ResponseWriter;
149
150 // Returns total size of the response
151 std::size_t SetBodyStreamed(engine::io::RwBase& socket, USERVER_NAMESPACE::http::headers::HeadersString& header);
152
153 // Returns total size of the response
154 std::size_t SetBodyNotStreamed(engine::io::RwBase& socket, USERVER_NAMESPACE::http::headers::HeadersString& header);
155
156 const HttpRequest& request_;
157 HttpStatus status_ = HttpStatus::kOk;
158 HeadersMap headers_;
159 CookiesMap cookies_;
160
161 engine::SingleConsumerEvent headers_end_{engine::SingleConsumerEvent::NoAutoReset()};
162 std::optional<Queue::Consumer> body_stream_;
163 Producer body_stream_producer_;
164 bool is_stream_body_{false};
165};
166
167void SetThrottleReason(http::HttpResponse& http_response, std::string log_reason, std::string http_header_reason);
168
169} // namespace server::http
170
171USERVER_NAMESPACE_END