]>
Commit | Line | Data |
---|---|---|
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 | ||
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), | |
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 | ||
52 | size_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 | ||
71 | void RGWCivetWeb::flush() | |
72 | { | |
73 | txbuf.pubsync(); | |
74 | } | |
75 | ||
76 | size_t RGWCivetWeb::complete_request() | |
77 | { | |
78 | return 0; | |
79 | } | |
80 | ||
3a9019d9 | 81 | int 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 | ||
154 | size_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 | ||
167 | size_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 | ||
176 | size_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 | ||
192 | size_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(>ime, &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 | ||
212 | size_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 | ||
231 | size_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 | } |