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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright 2015 Cloudius Systems
26 // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
33 #include <seastar/core/iostream.hh>
34 #include <seastar/core/sstring.hh>
38 #include <seastar/http/common.hh>
39 #include <seastar/http/mime_types.hh>
40 #include <seastar/core/iostream.hh>
46 namespace experimental { class connection; }
49 * A request received from a client.
54 other, multipart, app_x_www_urlencoded,
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); });
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);
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
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.
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
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
96 sstring get_header(const sstring& name) const {
97 auto res = _headers.find(name);
98 if (res == _headers.end()) {
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
109 sstring get_query_param(const sstring& name) const {
110 auto res = query_parameters.find(name);
111 if (res == query_parameters.end()) {
118 * Get the request protocol name. Can be either "http" or "https".
120 sstring get_protocol_name() const {
121 return protocol_name;
125 * Get the request url.
126 * @return the request url
128 sstring get_url() const {
129 return get_protocol_name() + "://" + get_header("Host") + _url;
132 bool is_multi_part() const {
133 return content_type_class == ctclass::multipart;
136 bool is_form_post() const {
137 return content_type_class == ctclass::app_x_www_urlencoded;
140 bool should_keep_alive() const {
141 if (_version == "0.9") {
145 // TODO: handle HTTP/2.0 when it releases
147 auto it = _headers.find("Connection");
148 if (_version == "1.0") {
149 return it != _headers.end()
150 && case_insensitive_cmp()(it->second, "keep-alive");
152 return it == _headers.end() || !case_insensitive_cmp()(it->second, "close");
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
162 sstring parse_query_param();
165 * Generates the URL string from the _url and query_parameters
166 * values in a form parseable by the above method
168 sstring format_url() const;
171 * Set the content type mime type.
172 * Used when the mime type is known.
173 * For most cases, use the set_content_type
175 void set_mime_type(const sstring& mime) {
176 _headers["Content-Type"] = mime;
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'
183 void set_content_type(const sstring& content_type = "html") {
184 set_mime_type(http::mime_types::extension_to_type(content_type));
188 * \brief Write a string as the body
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.
196 * This method is good to be used if the body is available as a contiguous buffer.
198 void write_body(const sstring& content_type, sstring content);
201 * \brief Use an output stream to write the message body
203 * When a handler needs to use an output stream it should call this method
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
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.
217 void write_body(const sstring& content_type, noncopyable_function<future<>(output_stream<char>&&)>&& body_writer);
220 * \brief Use an output stream to write the message body
222 * When a handler needs to use an output stream it should call this method
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
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.
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.
241 void write_body(const sstring& content_type, size_t len, noncopyable_function<future<>(output_stream<char>&&)>&& body_writer);
244 * \brief Make request send Expect header
246 * When set, the connection::make_request will send the Expect header and will wait for the
247 * server resply before tranferring the body
250 void set_expects_continue();
253 * \brief Make simple request
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
260 static request make(sstring method, sstring host, sstring path);
263 * \brief Make simple request
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
270 static request make(httpd::operation_type type, sstring host, sstring path);
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;
282 using request [[deprecated("Use http::request instead")]] = http::request;