]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/http/request.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / http / request.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright 2015 Cloudius Systems
20 */
21
22 //
23 // request.hpp
24 // ~~~~~~~~~~~
25 //
26 // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
27 //
28 // Distributed under the Boost Software License, Version 1.0. (See accompanying
29 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
30 //
31 #pragma once
32
33 #include <seastar/core/iostream.hh>
34 #include <seastar/core/sstring.hh>
35 #include <string>
36 #include <vector>
37 #include <strings.h>
38 #include <seastar/http/common.hh>
39 #include <seastar/http/mime_types.hh>
40 #include <seastar/core/iostream.hh>
41
42 namespace seastar {
43
44 namespace http {
45
46 namespace experimental { class connection; }
47
48 /**
49 * A request received from a client.
50 */
51 struct request {
52 enum class ctclass
53 : char {
54 other, multipart, app_x_www_urlencoded,
55 };
56
57 struct case_insensitive_cmp {
58 bool operator()(const sstring& s1, const sstring& s2) const {
59 return std::equal(s1.begin(), s1.end(), s2.begin(), s2.end(),
60 [](char a, char b) { return ::tolower(a) == ::tolower(b); });
61 }
62 };
63
64 struct case_insensitive_hash {
65 size_t operator()(sstring s) const {
66 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
67 return std::hash<sstring>()(s);
68 }
69 };
70
71 sstring _method;
72 sstring _url;
73 sstring _version;
74 ctclass content_type_class;
75 size_t content_length = 0;
76 std::unordered_map<sstring, sstring, case_insensitive_hash, case_insensitive_cmp> _headers;
77 std::unordered_map<sstring, sstring> query_parameters;
78 httpd::parameters param;
79 sstring content; // server-side deprecated: use content_stream instead
80 /*
81 * The handler should read the contents of this stream till reaching eof (i.e., the end of this request's content). Failing to do so
82 * will force the server to close this connection, and the client will not be able to reuse this connection for the next request.
83 * The stream should not be closed by the handler, the server will close it for the handler.
84 * */
85 input_stream<char>* content_stream;
86 std::unordered_map<sstring, sstring> trailing_headers;
87 std::unordered_map<sstring, sstring> chunk_extensions;
88 sstring protocol_name = "http";
89 noncopyable_function<future<>(output_stream<char>&&)> body_writer; // for client
90
91 /**
92 * Search for the first header of a given name
93 * @param name the header name
94 * @return a pointer to the header value, if it exists or empty string
95 */
96 sstring get_header(const sstring& name) const {
97 auto res = _headers.find(name);
98 if (res == _headers.end()) {
99 return "";
100 }
101 return res->second;
102 }
103
104 /**
105 * Search for the first header of a given name
106 * @param name the header name
107 * @return a pointer to the header value, if it exists or empty string
108 */
109 sstring get_query_param(const sstring& name) const {
110 auto res = query_parameters.find(name);
111 if (res == query_parameters.end()) {
112 return "";
113 }
114 return res->second;
115 }
116
117 /**
118 * Get the request protocol name. Can be either "http" or "https".
119 */
120 sstring get_protocol_name() const {
121 return protocol_name;
122 }
123
124 /**
125 * Get the request url.
126 * @return the request url
127 */
128 sstring get_url() const {
129 return get_protocol_name() + "://" + get_header("Host") + _url;
130 }
131
132 bool is_multi_part() const {
133 return content_type_class == ctclass::multipart;
134 }
135
136 bool is_form_post() const {
137 return content_type_class == ctclass::app_x_www_urlencoded;
138 }
139
140 bool should_keep_alive() const {
141 if (_version == "0.9") {
142 return false;
143 }
144
145 // TODO: handle HTTP/2.0 when it releases
146
147 auto it = _headers.find("Connection");
148 if (_version == "1.0") {
149 return it != _headers.end()
150 && case_insensitive_cmp()(it->second, "keep-alive");
151 } else { // HTTP/1.1
152 return it == _headers.end() || !case_insensitive_cmp()(it->second, "close");
153 }
154 }
155
156 /**
157 * Set the query parameters in the request objects.
158 * Returns the URL path part, i.e. -- without the query paremters
159 * query param appear after the question mark and are separated
160 * by the ampersand sign
161 */
162 sstring parse_query_param();
163
164 /**
165 * Generates the URL string from the _url and query_parameters
166 * values in a form parseable by the above method
167 */
168 sstring format_url() const;
169
170 /**
171 * Set the content type mime type.
172 * Used when the mime type is known.
173 * For most cases, use the set_content_type
174 */
175 void set_mime_type(const sstring& mime) {
176 _headers["Content-Type"] = mime;
177 }
178
179 /**
180 * Set the content type mime type according to the file extension
181 * that would have been used if it was a file: e.g. html, txt, json etc'
182 */
183 void set_content_type(const sstring& content_type = "html") {
184 set_mime_type(http::mime_types::extension_to_type(content_type));
185 }
186
187 /**
188 * \brief Write a string as the body
189 *
190 * \param content_type - is used to choose the content type of the body. Use the file extension
191 * you would have used for such a content, (i.e. "txt", "html", "json", etc')
192 * \param content - the message content.
193 * This would set the the content, conent length and content type of the message along
194 * with any additional information that is needed to send the message.
195 *
196 * This method is good to be used if the body is available as a contiguous buffer.
197 */
198 void write_body(const sstring& content_type, sstring content);
199
200 /**
201 * \brief Use an output stream to write the message body
202 *
203 * When a handler needs to use an output stream it should call this method
204 * with a function.
205 *
206 * \param content_type - is used to choose the content type of the body. Use the file extension
207 * you would have used for such a content, (i.e. "txt", "html", "json", etc')
208 * \param body_writer - a function that accept an output stream and use that stream to write the body.
209 * The function should take ownership of the stream while using it and must close the stream when it
210 * is done.
211 *
212 * This method can be used to write body of unknown or hard to evaluate length. For example,
213 * when sending the contents of some other input_stream or when the body is available as a
214 * collection of memory buffers. Message would use chunked transfer encoding.
215 *
216 */
217 void write_body(const sstring& content_type, noncopyable_function<future<>(output_stream<char>&&)>&& body_writer);
218
219 /**
220 * \brief Use an output stream to write the message body
221 *
222 * When a handler needs to use an output stream it should call this method
223 * with a function.
224 *
225 * \param content_type - is used to choose the content type of the body. Use the file extension
226 * you would have used for such a content, (i.e. "txt", "html", "json", etc')
227 * \param len - known in advance content length
228 * \param body_writer - a function that accept an output stream and use that stream to write the body.
229 * The function should take ownership of the stream while using it and must close the stream when it
230 * is done.
231 *
232 * This method is to be used when the body is not available of a single contiguous buffer, but the
233 * size of it is known and it's desirable to provide it to the server, or when the server strongly
234 * requires the content-length header for any reason.
235 *
236 * Message would use plain encoding in the the reply with Content-Length header set accordingly.
237 * If the body_writer doesn't generate enough bytes into the stream or tries to put more data into
238 * the stream, sending the request would resolve with exceptional future.
239 *
240 */
241 void write_body(const sstring& content_type, size_t len, noncopyable_function<future<>(output_stream<char>&&)>&& body_writer);
242
243 /**
244 * \brief Make request send Expect header
245 *
246 * When set, the connection::make_request will send the Expect header and will wait for the
247 * server resply before tranferring the body
248 *
249 */
250 void set_expects_continue();
251
252 /**
253 * \brief Make simple request
254 *
255 * \param method - method to use, e.g. "GET" or "POST"
256 * \param host - host to contact. This value will be used as the "Host" header
257 * \path - the URL to send the request to
258 *
259 */
260 static request make(sstring method, sstring host, sstring path);
261
262 /**
263 * \brief Make simple request
264 *
265 * \param method - method to use, e.g. operation_type::GET
266 * \param host - host to contact. This value will be used as the "Host" header
267 * \path - the URL to send the request to
268 *
269 */
270 static request make(httpd::operation_type type, sstring host, sstring path);
271
272 private:
273 void add_param(const std::string_view& param);
274 sstring request_line() const;
275 future<> write_request_headers(output_stream<char>& out);
276 friend class experimental::connection;
277 };
278
279 } // namespace httpd
280
281 namespace httpd {
282 using request [[deprecated("Use http::request instead")]] = http::request;
283 }
284
285 }