]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/http/httpd.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / include / seastar / http / httpd.hh
CommitLineData
11fdf7f2
TL
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#pragma once
23
24#include <seastar/http/request_parser.hh>
25#include <seastar/http/request.hh>
f67539c2 26#include <seastar/core/seastar.hh>
11fdf7f2
TL
27#include <seastar/core/sstring.hh>
28#include <seastar/core/app-template.hh>
29#include <seastar/core/circular_buffer.hh>
30#include <seastar/core/distributed.hh>
31#include <seastar/core/queue.hh>
f67539c2 32#include <seastar/core/gate.hh>
11fdf7f2
TL
33#include <seastar/core/metrics_registration.hh>
34#include <seastar/util/std-compat.hh>
35#include <iostream>
36#include <algorithm>
37#include <unordered_map>
38#include <queue>
39#include <bitset>
40#include <limits>
41#include <cctype>
42#include <vector>
43#include <boost/intrusive/list.hpp>
44#include <seastar/http/routes.hh>
9f95a23c
TL
45#include <seastar/net/tls.hh>
46#include <seastar/core/shared_ptr.hh>
11fdf7f2
TL
47
48namespace seastar {
49
50namespace httpd {
51
52class http_server;
53class http_stats;
9f95a23c 54struct reply;
11fdf7f2
TL
55
56using namespace std::chrono_literals;
57
58class http_stats {
59 metrics::metric_groups _metric_groups;
60public:
61 http_stats(http_server& server, const sstring& name);
62};
63
64class connection : public boost::intrusive::list_base_hook<> {
65 http_server& _server;
66 connected_socket _fd;
67 input_stream<char> _read_buf;
68 output_stream<char> _write_buf;
69 static constexpr size_t limit = 4096;
70 using tmp_buf = temporary_buffer<char>;
71 http_request_parser _parser;
72 std::unique_ptr<request> _req;
73 std::unique_ptr<reply> _resp;
74 // null element marks eof
75 queue<std::unique_ptr<reply>> _replies { 10 };
76 bool _done = false;
77public:
78 connection(http_server& server, connected_socket&& fd,
79 socket_address addr)
80 : _server(server), _fd(std::move(fd)), _read_buf(_fd.input()), _write_buf(
81 _fd.output()) {
82 on_new_connection();
83 }
84 ~connection();
85 void on_new_connection();
86
f67539c2
TL
87 future<> process();
88 void shutdown();
11fdf7f2
TL
89 future<> read();
90 future<> read_one();
91 future<> respond();
92 future<> do_response_loop();
93
94 void set_headers(reply& resp);
95
96 future<> start_response();
f67539c2 97 future<> write_reply_headers(std::unordered_map<sstring, sstring>::iterator hi);
11fdf7f2 98
f67539c2 99 static short hex_to_byte(char c);
11fdf7f2
TL
100
101 /**
102 * Convert a hex encoded 2 bytes substring to char
103 */
f67539c2 104 static char hexstr_to_char(const std::string_view& in, size_t from);
11fdf7f2
TL
105
106 /**
107 * URL_decode a substring and place it in the given out sstring
108 */
f67539c2 109 static bool url_decode(const std::string_view& in, sstring& out);
11fdf7f2
TL
110
111 /**
112 * Add a single query parameter to the parameter list
113 */
f67539c2 114 static void add_param(request& req, const std::string_view& param);
11fdf7f2
TL
115
116 /**
117 * Set the query parameters in the request objects.
118 * query param appear after the question mark and are separated
119 * by the ampersand sign
120 */
f67539c2 121 static sstring set_query_param(request& req);
11fdf7f2
TL
122
123 future<bool> generate_reply(std::unique_ptr<request> req);
9f95a23c 124 void generate_error_reply_and_close(std::unique_ptr<request> req, reply::status_type status, const sstring& msg);
11fdf7f2
TL
125
126 future<> write_body();
127
f67539c2 128 output_stream<char>& out();
11fdf7f2
TL
129};
130
131class http_server_tester;
132
133class http_server {
f67539c2 134 std::vector<server_socket> _listeners;
11fdf7f2
TL
135 http_stats _stats;
136 uint64_t _total_connections = 0;
137 uint64_t _current_connections = 0;
138 uint64_t _requests_served = 0;
11fdf7f2
TL
139 uint64_t _read_errors = 0;
140 uint64_t _respond_errors = 0;
9f95a23c 141 shared_ptr<seastar::tls::server_credentials> _credentials;
11fdf7f2
TL
142 sstring _date = http_date();
143 timer<> _date_format_timer { [this] {_date = http_date();} };
9f95a23c 144 size_t _content_length_limit = std::numeric_limits<size_t>::max();
20effc67 145 bool _content_streaming = false;
f67539c2 146 gate _task_gate;
11fdf7f2
TL
147public:
148 routes _routes;
149 using connection = seastar::httpd::connection;
150 explicit http_server(const sstring& name) : _stats(*this, name) {
151 _date_format_timer.arm_periodic(1s);
152 }
9f95a23c
TL
153 /*!
154 * \brief set tls credentials for the server
155 * Setting the tls credentials will set the http-server to work in https mode.
156 *
157 * To use the https, create server credentials and pass it to the server before it starts.
158 *
159 * Use case example using seastar threads for clarity:
160
161 distributed<http_server> server; // typical server
162
163 seastar::shared_ptr<seastar::tls::credentials_builder> creds = seastar::make_shared<seastar::tls::credentials_builder>();
164 sstring ms_cert = "MyCertificate.crt";
165 sstring ms_key = "MyKey.key";
166
167 creds->set_dh_level(seastar::tls::dh_params::level::MEDIUM);
168
169 creds->set_x509_key_file(ms_cert, ms_key, seastar::tls::x509_crt_format::PEM).get();
170 creds->set_system_trust().get();
171
172
173 server.invoke_on_all([creds](http_server& server) {
174 server.set_tls_credentials(creds->build_server_credentials());
175 return make_ready_future<>();
176 }).get();
177 *
178 */
f67539c2 179 void set_tls_credentials(shared_ptr<seastar::tls::server_credentials> credentials);
9f95a23c 180
f67539c2 181 size_t get_content_length_limit() const;
9f95a23c 182
f67539c2 183 void set_content_length_limit(size_t limit);
9f95a23c 184
20effc67
TL
185 bool get_content_streaming() const;
186
187 void set_content_streaming(bool b);
188
f67539c2
TL
189 future<> listen(socket_address addr, listen_options lo);
190 future<> listen(socket_address addr);
191 future<> stop();
11fdf7f2 192
f67539c2 193 future<> do_accepts(int which);
11fdf7f2 194
f67539c2
TL
195 uint64_t total_connections() const;
196 uint64_t current_connections() const;
197 uint64_t requests_served() const;
198 uint64_t read_errors() const;
199 uint64_t reply_errors() const;
200 // Write the current date in the specific "preferred format" defined in
201 // RFC 7231, Section 7.1.1.1.
202 static sstring http_date();
11fdf7f2 203private:
f67539c2 204 future<> do_accept_one(int which);
11fdf7f2
TL
205 boost::intrusive::list<connection> _connections;
206 friend class seastar::httpd::connection;
207 friend class http_server_tester;
208};
209
210class http_server_tester {
211public:
f67539c2 212 static std::vector<server_socket>& listeners(http_server& server) {
11fdf7f2
TL
213 return server._listeners;
214 }
215};
216
217/*
218 * A helper class to start, set and listen an http server
219 * typical use would be:
220 *
221 * auto server = new http_server_control();
222 * server->start().then([server] {
223 * server->set_routes(set_routes);
224 * }).then([server, port] {
225 * server->listen(port);
226 * }).then([port] {
227 * std::cout << "Seastar HTTP server listening on port " << port << " ...\n";
228 * });
229 */
230class http_server_control {
231 std::unique_ptr<distributed<http_server>> _server_dist;
232private:
233 static sstring generate_server_name();
234public:
235 http_server_control() : _server_dist(new distributed<http_server>) {
236 }
237
f67539c2
TL
238 future<> start(const sstring& name = generate_server_name());
239 future<> stop();
240 future<> set_routes(std::function<void(routes& r)> fun);
241 future<> listen(socket_address addr);
242 future<> listen(socket_address addr, listen_options lo);
243 distributed<http_server>& server();
11fdf7f2
TL
244};
245
246}
247
248}