]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_civetweb.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rgw / rgw_civetweb.cc
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae
FG
3
4#include <string.h>
f67539c2 5#include <string_view>
7c673cae
FG
6
7#include <boost/algorithm/string/predicate.hpp>
7c673cae
FG
8
9#include "civetweb/civetweb.h"
10#include "rgw_civetweb.h"
11fdf7f2 11#include "rgw_perf_counters.h"
7c673cae
FG
12
13
14#define dout_subsys ceph_subsys_rgw
15
16size_t RGWCivetWeb::write_data(const char *buf, const size_t len)
17{
92f5a8d4 18 size_t off = 0;
7c673cae
FG
19 auto to_sent = len;
20 while (to_sent) {
92f5a8d4 21 const int ret = mg_write(conn, buf + off, to_sent);
7c673cae
FG
22 if (ret < 0 || ! ret) {
23 /* According to the documentation of mg_write() it always returns -1 on
24 * error. The details aren't available, so we will just throw EIO. Same
25 * goes to 0 that is associated with writing to a closed connection. */
26 throw rgw::io::Exception(EIO, std::system_category());
27 } else {
92f5a8d4 28 off += static_cast<size_t>(ret);
7c673cae
FG
29 to_sent -= static_cast<size_t>(ret);
30 }
31 }
32 return len;
33}
34
35RGWCivetWeb::RGWCivetWeb(mg_connection* const conn)
36 : conn(conn),
37 explicit_keepalive(false),
38 explicit_conn_close(false),
94b18763 39 got_eof_on_read(false),
7c673cae
FG
40 txbuf(*this)
41{
42 sockaddr *lsa = mg_get_local_addr(conn);
43 switch(lsa->sa_family) {
44 case AF_INET:
45 port = ntohs(((struct sockaddr_in*)lsa)->sin_port);
46 break;
47 case AF_INET6:
48 port = ntohs(((struct sockaddr_in6*)lsa)->sin6_port);
49 break;
50 default:
51 port = -1;
52 }
53}
54
55size_t RGWCivetWeb::read_data(char *buf, size_t len)
56{
11fdf7f2
TL
57 size_t c;
58 int ret;
94b18763
FG
59 if (got_eof_on_read) {
60 return 0;
7c673cae 61 }
94b18763 62 for (c = 0; c < len; c += ret) {
28e407b8 63 ret = mg_read(conn, buf+c, len-c);
94b18763
FG
64 if (ret < 0) {
65 throw rgw::io::Exception(EIO, std::system_category());
66 }
67 if (!ret) {
68 got_eof_on_read = true;
69 break;
70 }
71 }
72 return c;
7c673cae
FG
73}
74
75void RGWCivetWeb::flush()
76{
77 txbuf.pubsync();
78}
79
80size_t RGWCivetWeb::complete_request()
81{
11fdf7f2
TL
82 perfcounter->inc(l_rgw_qlen, -1);
83 perfcounter->inc(l_rgw_qactive, -1);
7c673cae
FG
84 return 0;
85}
86
3a9019d9 87int RGWCivetWeb::init_env(CephContext *cct)
7c673cae
FG
88{
89 env.init(cct);
90 const struct mg_request_info* info = mg_get_request_info(conn);
91
92 if (! info) {
3a9019d9
FG
93 // request info is NULL; we have no info about the connection
94 return -EINVAL;
7c673cae
FG
95 }
96
97 for (int i = 0; i < info->num_headers; i++) {
11fdf7f2 98 const auto header = &info->http_headers[i];
3a9019d9
FG
99
100 if (header->name == nullptr || header->value==nullptr) {
101 lderr(cct) << "client supplied malformatted headers" << dendl;
102 return -EINVAL;
103 }
104
f67539c2 105 const std::string_view name(header->name);
7c673cae
FG
106 const auto& value = header->value;
107
108 if (boost::algorithm::iequals(name, "content-length")) {
109 env.set("CONTENT_LENGTH", value);
110 continue;
111 }
112 if (boost::algorithm::iequals(name, "content-type")) {
113 env.set("CONTENT_TYPE", value);
114 continue;
115 }
116 if (boost::algorithm::iequals(name, "connection")) {
117 explicit_keepalive = boost::algorithm::iequals(value, "keep-alive");
118 explicit_conn_close = boost::algorithm::iequals(value, "close");
119 }
120
f67539c2 121 static const std::string_view HTTP_{"HTTP_"};
7c673cae
FG
122
123 char buf[name.size() + HTTP_.size() + 1];
124 auto dest = std::copy(std::begin(HTTP_), std::end(HTTP_), buf);
125 for (auto src = name.begin(); src != name.end(); ++src, ++dest) {
126 if (*src == '-') {
127 *dest = '_';
128 } else {
129 *dest = std::toupper(*src);
130 }
131 }
132 *dest = '\0';
133
134 env.set(buf, value);
135 }
136
11fdf7f2
TL
137 perfcounter->inc(l_rgw_qlen);
138 perfcounter->inc(l_rgw_qactive);
139
b32b8144 140 env.set("REMOTE_ADDR", info->remote_addr);
7c673cae 141 env.set("REQUEST_METHOD", info->request_method);
b32b8144 142 env.set("HTTP_VERSION", info->http_version);
31f18b77 143 env.set("REQUEST_URI", info->request_uri); // get the full uri, we anyway handle abs uris later
11fdf7f2 144 env.set("SCRIPT_URI", info->local_uri);
7c673cae
FG
145 if (info->query_string) {
146 env.set("QUERY_STRING", info->query_string);
147 }
148 if (info->remote_user) {
149 env.set("REMOTE_USER", info->remote_user);
150 }
151
152 if (port <= 0)
153 lderr(cct) << "init_env: bug: invalid port number" << dendl;
154 char port_buf[16];
155 snprintf(port_buf, sizeof(port_buf), "%d", port);
156 env.set("SERVER_PORT", port_buf);
157 if (info->is_ssl) {
158 env.set("SERVER_PORT_SECURE", port_buf);
159 }
3a9019d9 160 return 0;
7c673cae
FG
161}
162
163size_t RGWCivetWeb::send_status(int status, const char *status_name)
164{
165 mg_set_http_status(conn, status);
166
167 static constexpr size_t STATUS_BUF_SIZE = 128;
168
169 char statusbuf[STATUS_BUF_SIZE];
170 const auto statuslen = snprintf(statusbuf, sizeof(statusbuf),
171 "HTTP/1.1 %d %s\r\n", status, status_name);
172
173 return txbuf.sputn(statusbuf, statuslen);
174}
175
176size_t RGWCivetWeb::send_100_continue()
177{
178 const char HTTTP_100_CONTINUE[] = "HTTP/1.1 100 CONTINUE\r\n\r\n";
179 const size_t sent = txbuf.sputn(HTTTP_100_CONTINUE,
180 sizeof(HTTTP_100_CONTINUE) - 1);
181 flush();
182 return sent;
183}
184
f67539c2
TL
185size_t RGWCivetWeb::send_header(const std::string_view& name,
186 const std::string_view& value)
7c673cae
FG
187{
188 static constexpr char HEADER_SEP[] = ": ";
189 static constexpr char HEADER_END[] = "\r\n";
190
191 size_t sent = 0;
192
193 sent += txbuf.sputn(name.data(), name.length());
194 sent += txbuf.sputn(HEADER_SEP, sizeof(HEADER_SEP) - 1);
195 sent += txbuf.sputn(value.data(), value.length());
196 sent += txbuf.sputn(HEADER_END, sizeof(HEADER_END) - 1);
197
198 return sent;
199}
200
201size_t RGWCivetWeb::dump_date_header()
202{
203 char timestr[TIME_BUF_SIZE];
204
205 const time_t gtime = time(nullptr);
206 struct tm result;
207 struct tm const* const tmp = gmtime_r(&gtime, &result);
208
209 if (nullptr == tmp) {
210 return 0;
211 }
212
213 if (! strftime(timestr, sizeof(timestr),
214 "Date: %a, %d %b %Y %H:%M:%S %Z\r\n", tmp)) {
215 return 0;
216 }
217
218 return txbuf.sputn(timestr, strlen(timestr));
219}
220
221size_t RGWCivetWeb::complete_header()
222{
223 size_t sent = dump_date_header();
224
225 if (explicit_keepalive) {
226 constexpr char CONN_KEEP_ALIVE[] = "Connection: Keep-Alive\r\n";
227 sent += txbuf.sputn(CONN_KEEP_ALIVE, sizeof(CONN_KEEP_ALIVE) - 1);
228 } else if (explicit_conn_close) {
229 constexpr char CONN_KEEP_CLOSE[] = "Connection: close\r\n";
230 sent += txbuf.sputn(CONN_KEEP_CLOSE, sizeof(CONN_KEEP_CLOSE) - 1);
231 }
232
233 static constexpr char HEADER_END[] = "\r\n";
234 sent += txbuf.sputn(HEADER_END, sizeof(HEADER_END) - 1);
235
236 flush();
237 return sent;
238}
239
240size_t RGWCivetWeb::send_content_length(uint64_t len)
241{
242 static constexpr size_t CONLEN_BUF_SIZE = 128;
243
244 char sizebuf[CONLEN_BUF_SIZE];
245 const auto sizelen = snprintf(sizebuf, sizeof(sizebuf),
246 "Content-Length: %" PRIu64 "\r\n", len);
247 return txbuf.sputn(sizebuf, sizelen);
248}