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