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