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 <unordered_map>
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
25namespace impl {
26
27void OutputHeader(USERVER_NAMESPACE::http::headers::HeadersString& header,
28 std::string_view key, std::string_view val);
29
30} // namespace impl
31
32class HttpRequestImpl;
33
34/// @brief HTTP Response data
35class HttpResponse final : public request::ResponseBase {
36 public:
37 using HeadersMap = USERVER_NAMESPACE::http::headers::HeaderMap;
38
39 using HeadersMapKeys = decltype(utils::impl::MakeKeysView(HeadersMap()));
40
41 using CookiesMap = Cookie::CookiesMap;
42
43 using CookiesMapKeys = decltype(utils::impl::MakeKeysView(CookiesMap()));
44
45 /// @cond
46 HttpResponse(const HttpRequestImpl& request,
47 request::ResponseDataAccounter& data_accounter);
48 HttpResponse(const HttpRequestImpl& request,
49 request::ResponseDataAccounter& data_accounter,
50 std::chrono::steady_clock::time_point now,
51 utils::StrCaseHash hasher);
52 ~HttpResponse() override;
53
54 void SetSendFailed(
55 std::chrono::steady_clock::time_point failure_time) override;
56 /// @endcond
57
58 /// @brief Add a new response header or rewrite an existing one.
59 /// @returns true if the header was set. Returns false if headers
60 /// were already sent for stream'ed response and the new header was not set.
61 bool SetHeader(std::string name, std::string value);
62
63 /// @brief Add a new response header or rewrite an existing one.
64 /// @returns true if the header was set. Returns false if headers
65 /// were already sent for stream'ed response and the new header was not set.
66 bool SetHeader(std::string_view name, std::string value);
67
68 /// @overload
70 const USERVER_NAMESPACE::http::headers::PredefinedHeader& header,
71 std::string value);
72
73 /// @brief Add or rewrite the Content-Type header.
74 void SetContentType(const USERVER_NAMESPACE::http::ContentType& type);
75
76 /// @brief Add or rewrite the Content-Encoding header.
77 void SetContentEncoding(std::string encoding);
78
79 /// @brief Set the HTTP response status code.
80 /// @returns true if the status was set. Returns false if headers
81 /// were already sent for stream'ed response and the new status was not set.
82 bool SetStatus(HttpStatus status);
83
84 /// @brief Remove all headers from response.
85 /// @returns true if the headers were cleared. Returns false if headers
86 /// were already sent for stream'ed response and the headers were not cleared.
88
89 /// @brief Sets a cookie if it was not set before.
90 void SetCookie(Cookie cookie);
91
92 /// @brief Remove all cookies from response.
94
95 /// @return HTTP response status
96 HttpStatus GetStatus() const { return status_; }
97
98 /// @return List of HTTP headers names.
100
101 /// @return Value of the header with case insensitive name header_name, or an
102 /// empty string if no such header.
103 const std::string& GetHeader(std::string_view header_name) const;
104 /// @overload
105 const std::string& GetHeader(
106 const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name)
107 const;
108
109 /// @return true if header with case insensitive name header_name exists,
110 /// false otherwise.
111 bool HasHeader(std::string_view header_name) const;
112 /// @overload
113 bool HasHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader&
114 header_name) const;
115
116 /// @return List of cookies names.
118
119 /// @return Value of the cookie with case sensitive name cookie_name, or an
120 /// empty string if no such cookie exists.
121 const Cookie& GetCookie(std::string_view cookie_name) const;
122
123 /// @cond
124 // TODO: server internals. remove from public interface
125 void SendResponse(engine::io::RwBase& socket) override;
126 /// @endcond
127
128 void SetStatusServiceUnavailable() override {
129 SetStatus(HttpStatus::kServiceUnavailable);
130 }
131 void SetStatusOk() override { SetStatus(HttpStatus::kOk); }
132 void SetStatusNotFound() override { SetStatus(HttpStatus::kNotFound); }
133
134 bool WaitForHeadersEnd() override;
135 void SetHeadersEnd() override;
136
137 using Queue = concurrent::StringStreamQueue;
138
139 void SetStreamBody();
140 bool IsBodyStreamed() const override;
141 // Can be called only once
142 Queue::Producer GetBodyProducer();
143
144 private:
145 // Returns total size of the response
146 std::size_t SetBodyStreamed(
147 engine::io::RwBase& socket,
148 USERVER_NAMESPACE::http::headers::HeadersString& header);
149
150 // Returns total size of the response
151 std::size_t SetBodyNotStreamed(
152 engine::io::RwBase& socket,
153 USERVER_NAMESPACE::http::headers::HeadersString& header);
154
155 const HttpRequestImpl& request_;
156 HttpStatus status_ = HttpStatus::kOk;
157 HeadersMap headers_;
158 CookiesMap cookies_;
159
160 engine::SingleConsumerEvent headers_end_{
161 engine::SingleConsumerEvent::NoAutoReset()};
162 std::optional<Queue::Consumer> body_stream_;
163 std::optional<Queue::Producer> body_stream_producer_;
164};
165
166void SetThrottleReason(http::HttpResponse& http_response,
167 std::string log_reason, std::string http_header_reason);
168
169} // namespace server::http
170
171USERVER_NAMESPACE_END