Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 void 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     return;
77   }
78
79   for (int i = 0; i < info->num_headers; i++) {
80     const struct mg_request_info::mg_header* header = &info->http_headers[i];
81     const boost::string_ref name(header->name);
82     const auto& value = header->value;
83
84     if (boost::algorithm::iequals(name, "content-length")) {
85       env.set("CONTENT_LENGTH", value);
86       continue;
87     }
88     if (boost::algorithm::iequals(name, "content-type")) {
89       env.set("CONTENT_TYPE", value);
90       continue;
91     }
92     if (boost::algorithm::iequals(name, "connection")) {
93       explicit_keepalive = boost::algorithm::iequals(value, "keep-alive");
94       explicit_conn_close = boost::algorithm::iequals(value, "close");
95     }
96
97     static const boost::string_ref HTTP_{"HTTP_"};
98
99     char buf[name.size() + HTTP_.size() + 1];
100     auto dest = std::copy(std::begin(HTTP_), std::end(HTTP_), buf);
101     for (auto src = name.begin(); src != name.end(); ++src, ++dest) {
102       if (*src == '-') {
103         *dest = '_';
104       } else {
105         *dest = std::toupper(*src);
106       }
107     }
108     *dest = '\0';
109
110     env.set(buf, value);
111   }
112
113   env.set("REQUEST_METHOD", info->request_method);
114   env.set("REQUEST_URI", info->request_uri); // get the full uri, we anyway handle abs uris later
115   env.set("SCRIPT_URI", info->uri); /* FIXME */
116   if (info->query_string) {
117     env.set("QUERY_STRING", info->query_string);
118   }
119   if (info->remote_user) {
120     env.set("REMOTE_USER", info->remote_user);
121   }
122
123   if (port <= 0)
124     lderr(cct) << "init_env: bug: invalid port number" << dendl;
125   char port_buf[16];
126   snprintf(port_buf, sizeof(port_buf), "%d", port);
127   env.set("SERVER_PORT", port_buf);
128   if (info->is_ssl) {
129     env.set("SERVER_PORT_SECURE", port_buf);
130   }
131 }
132
133 size_t RGWCivetWeb::send_status(int status, const char *status_name)
134 {
135   mg_set_http_status(conn, status);
136
137   static constexpr size_t STATUS_BUF_SIZE = 128;
138
139   char statusbuf[STATUS_BUF_SIZE];
140   const auto statuslen = snprintf(statusbuf, sizeof(statusbuf),
141                                   "HTTP/1.1 %d %s\r\n", status, status_name);
142
143   return txbuf.sputn(statusbuf, statuslen);
144 }
145
146 size_t RGWCivetWeb::send_100_continue()
147 {
148   const char HTTTP_100_CONTINUE[] = "HTTP/1.1 100 CONTINUE\r\n\r\n";
149   const size_t sent = txbuf.sputn(HTTTP_100_CONTINUE,
150                                   sizeof(HTTTP_100_CONTINUE) - 1);
151   flush();
152   return sent;
153 }
154
155 size_t RGWCivetWeb::send_header(const boost::string_ref& name,
156                                 const boost::string_ref& value)
157 {
158   static constexpr char HEADER_SEP[] = ": ";
159   static constexpr char HEADER_END[] = "\r\n";
160
161   size_t sent = 0;
162
163   sent += txbuf.sputn(name.data(), name.length());
164   sent += txbuf.sputn(HEADER_SEP, sizeof(HEADER_SEP) - 1);
165   sent += txbuf.sputn(value.data(), value.length());
166   sent += txbuf.sputn(HEADER_END, sizeof(HEADER_END) - 1);
167
168   return sent;
169 }
170
171 size_t RGWCivetWeb::dump_date_header()
172 {
173   char timestr[TIME_BUF_SIZE];
174
175   const time_t gtime = time(nullptr);
176   struct tm result;
177   struct tm const* const tmp = gmtime_r(&gtime, &result);
178
179   if (nullptr == tmp) {
180     return 0;
181   }
182
183   if (! strftime(timestr, sizeof(timestr),
184                  "Date: %a, %d %b %Y %H:%M:%S %Z\r\n", tmp)) {
185     return 0;
186   }
187
188   return txbuf.sputn(timestr, strlen(timestr));
189 }
190
191 size_t RGWCivetWeb::complete_header()
192 {
193   size_t sent = dump_date_header();
194
195   if (explicit_keepalive) {
196     constexpr char CONN_KEEP_ALIVE[] = "Connection: Keep-Alive\r\n";
197     sent += txbuf.sputn(CONN_KEEP_ALIVE, sizeof(CONN_KEEP_ALIVE) - 1);
198   } else if (explicit_conn_close) {
199     constexpr char CONN_KEEP_CLOSE[] = "Connection: close\r\n";
200     sent += txbuf.sputn(CONN_KEEP_CLOSE, sizeof(CONN_KEEP_CLOSE) - 1);
201   }
202
203   static constexpr char HEADER_END[] = "\r\n";
204   sent += txbuf.sputn(HEADER_END, sizeof(HEADER_END) - 1);
205
206   flush();
207   return sent;
208 }
209
210 size_t RGWCivetWeb::send_content_length(uint64_t len)
211 {
212   static constexpr size_t CONLEN_BUF_SIZE = 128;
213
214   char sizebuf[CONLEN_BUF_SIZE];
215   const auto sizelen = snprintf(sizebuf, sizeof(sizebuf),
216                                 "Content-Length: %" PRIu64 "\r\n", len);
217   return txbuf.sputn(sizebuf, sizelen);
218 }