]>
git.proxmox.com Git - ceph.git/blob - 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
6 #include <boost/algorithm/string/predicate.hpp>
7 #include <boost/utility/string_ref.hpp>
9 #include "civetweb/civetweb.h"
10 #include "rgw_civetweb.h"
13 #define dout_subsys ceph_subsys_rgw
15 size_t RGWCivetWeb::write_data(const char *buf
, const size_t len
)
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());
26 to_sent
-= static_cast<size_t>(ret
);
32 RGWCivetWeb::RGWCivetWeb(mg_connection
* const conn
)
34 explicit_keepalive(false),
35 explicit_conn_close(false),
36 got_eof_on_read(false),
39 sockaddr
*lsa
= mg_get_local_addr(conn
);
40 switch(lsa
->sa_family
) {
42 port
= ntohs(((struct sockaddr_in
*)lsa
)->sin_port
);
45 port
= ntohs(((struct sockaddr_in6
*)lsa
)->sin6_port
);
52 size_t RGWCivetWeb::read_data(char *buf
, size_t len
)
55 if (got_eof_on_read
) {
58 for (c
= 0; c
< len
; c
+= ret
) {
59 ret
= mg_read(conn
, buf
+c
, len
-c
);
61 throw rgw::io::Exception(EIO
, std::system_category());
64 got_eof_on_read
= true;
71 void RGWCivetWeb::flush()
76 size_t RGWCivetWeb::complete_request()
81 int RGWCivetWeb::init_env(CephContext
*cct
)
84 const struct mg_request_info
* info
= mg_get_request_info(conn
);
87 // request info is NULL; we have no info about the connection
91 for (int i
= 0; i
< info
->num_headers
; i
++) {
92 const struct mg_request_info::mg_header
* header
= &info
->http_headers
[i
];
94 if (header
->name
== nullptr || header
->value
==nullptr) {
95 lderr(cct
) << "client supplied malformatted headers" << dendl
;
99 const boost::string_ref
name(header
->name
);
100 const auto& value
= header
->value
;
102 if (boost::algorithm::iequals(name
, "content-length")) {
103 env
.set("CONTENT_LENGTH", value
);
106 if (boost::algorithm::iequals(name
, "content-type")) {
107 env
.set("CONTENT_TYPE", value
);
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");
115 static const boost::string_ref HTTP_
{"HTTP_"};
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
) {
123 *dest
= std::toupper(*src
);
131 env
.set("REMOTE_ADDR", info
->remote_addr
);
132 env
.set("REQUEST_METHOD", info
->request_method
);
133 env
.set("HTTP_VERSION", info
->http_version
);
134 env
.set("REQUEST_URI", info
->request_uri
); // get the full uri, we anyway handle abs uris later
135 env
.set("SCRIPT_URI", info
->uri
); /* FIXME */
136 if (info
->query_string
) {
137 env
.set("QUERY_STRING", info
->query_string
);
139 if (info
->remote_user
) {
140 env
.set("REMOTE_USER", info
->remote_user
);
144 lderr(cct
) << "init_env: bug: invalid port number" << dendl
;
146 snprintf(port_buf
, sizeof(port_buf
), "%d", port
);
147 env
.set("SERVER_PORT", port_buf
);
149 env
.set("SERVER_PORT_SECURE", port_buf
);
154 size_t RGWCivetWeb::send_status(int status
, const char *status_name
)
156 mg_set_http_status(conn
, status
);
158 static constexpr size_t STATUS_BUF_SIZE
= 128;
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
);
164 return txbuf
.sputn(statusbuf
, statuslen
);
167 size_t RGWCivetWeb::send_100_continue()
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);
176 size_t RGWCivetWeb::send_header(const boost::string_ref
& name
,
177 const boost::string_ref
& value
)
179 static constexpr char HEADER_SEP
[] = ": ";
180 static constexpr char HEADER_END
[] = "\r\n";
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);
192 size_t RGWCivetWeb::dump_date_header()
194 char timestr
[TIME_BUF_SIZE
];
196 const time_t gtime
= time(nullptr);
198 struct tm
const* const tmp
= gmtime_r(>ime
, &result
);
200 if (nullptr == tmp
) {
204 if (! strftime(timestr
, sizeof(timestr
),
205 "Date: %a, %d %b %Y %H:%M:%S %Z\r\n", tmp
)) {
209 return txbuf
.sputn(timestr
, strlen(timestr
));
212 size_t RGWCivetWeb::complete_header()
214 size_t sent
= dump_date_header();
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);
224 static constexpr char HEADER_END
[] = "\r\n";
225 sent
+= txbuf
.sputn(HEADER_END
, sizeof(HEADER_END
) - 1);
231 size_t RGWCivetWeb::send_content_length(uint64_t len
)
233 static constexpr size_t CONLEN_BUF_SIZE
= 128;
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
);