]>
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 ft=cpp
6 #include <boost/algorithm/string/predicate.hpp>
7 #include <boost/utility/string_ref.hpp>
9 #include "civetweb/civetweb.h"
10 #include "rgw_civetweb.h"
11 #include "rgw_perf_counters.h"
14 #define dout_subsys ceph_subsys_rgw
16 size_t RGWCivetWeb::write_data(const char *buf
, const size_t len
)
21 const int ret
= mg_write(conn
, buf
+ off
, to_sent
);
22 if (ret
< 0 || ! ret
) {
23 /* According to the documentation of mg_write() it always returns -1 on
24 * error. The details aren't available, so we will just throw EIO. Same
25 * goes to 0 that is associated with writing to a closed connection. */
26 throw rgw::io::Exception(EIO
, std::system_category());
28 off
+= static_cast<size_t>(ret
);
29 to_sent
-= static_cast<size_t>(ret
);
35 RGWCivetWeb::RGWCivetWeb(mg_connection
* const conn
)
37 explicit_keepalive(false),
38 explicit_conn_close(false),
39 got_eof_on_read(false),
42 sockaddr
*lsa
= mg_get_local_addr(conn
);
43 switch(lsa
->sa_family
) {
45 port
= ntohs(((struct sockaddr_in
*)lsa
)->sin_port
);
48 port
= ntohs(((struct sockaddr_in6
*)lsa
)->sin6_port
);
55 size_t RGWCivetWeb::read_data(char *buf
, size_t len
)
59 if (got_eof_on_read
) {
62 for (c
= 0; c
< len
; c
+= ret
) {
63 ret
= mg_read(conn
, buf
+c
, len
-c
);
65 throw rgw::io::Exception(EIO
, std::system_category());
68 got_eof_on_read
= true;
75 void RGWCivetWeb::flush()
80 size_t RGWCivetWeb::complete_request()
82 perfcounter
->inc(l_rgw_qlen
, -1);
83 perfcounter
->inc(l_rgw_qactive
, -1);
87 int RGWCivetWeb::init_env(CephContext
*cct
)
90 const struct mg_request_info
* info
= mg_get_request_info(conn
);
93 // request info is NULL; we have no info about the connection
97 for (int i
= 0; i
< info
->num_headers
; i
++) {
98 const auto header
= &info
->http_headers
[i
];
100 if (header
->name
== nullptr || header
->value
==nullptr) {
101 lderr(cct
) << "client supplied malformatted headers" << dendl
;
105 const boost::string_ref
name(header
->name
);
106 const auto& value
= header
->value
;
108 if (boost::algorithm::iequals(name
, "content-length")) {
109 env
.set("CONTENT_LENGTH", value
);
112 if (boost::algorithm::iequals(name
, "content-type")) {
113 env
.set("CONTENT_TYPE", value
);
116 if (boost::algorithm::iequals(name
, "connection")) {
117 explicit_keepalive
= boost::algorithm::iequals(value
, "keep-alive");
118 explicit_conn_close
= boost::algorithm::iequals(value
, "close");
121 static const boost::string_ref HTTP_
{"HTTP_"};
123 char buf
[name
.size() + HTTP_
.size() + 1];
124 auto dest
= std::copy(std::begin(HTTP_
), std::end(HTTP_
), buf
);
125 for (auto src
= name
.begin(); src
!= name
.end(); ++src
, ++dest
) {
129 *dest
= std::toupper(*src
);
137 perfcounter
->inc(l_rgw_qlen
);
138 perfcounter
->inc(l_rgw_qactive
);
140 env
.set("REMOTE_ADDR", info
->remote_addr
);
141 env
.set("REQUEST_METHOD", info
->request_method
);
142 env
.set("HTTP_VERSION", info
->http_version
);
143 env
.set("REQUEST_URI", info
->request_uri
); // get the full uri, we anyway handle abs uris later
144 env
.set("SCRIPT_URI", info
->local_uri
);
145 if (info
->query_string
) {
146 env
.set("QUERY_STRING", info
->query_string
);
148 if (info
->remote_user
) {
149 env
.set("REMOTE_USER", info
->remote_user
);
153 lderr(cct
) << "init_env: bug: invalid port number" << dendl
;
155 snprintf(port_buf
, sizeof(port_buf
), "%d", port
);
156 env
.set("SERVER_PORT", port_buf
);
158 env
.set("SERVER_PORT_SECURE", port_buf
);
163 size_t RGWCivetWeb::send_status(int status
, const char *status_name
)
165 mg_set_http_status(conn
, status
);
167 static constexpr size_t STATUS_BUF_SIZE
= 128;
169 char statusbuf
[STATUS_BUF_SIZE
];
170 const auto statuslen
= snprintf(statusbuf
, sizeof(statusbuf
),
171 "HTTP/1.1 %d %s\r\n", status
, status_name
);
173 return txbuf
.sputn(statusbuf
, statuslen
);
176 size_t RGWCivetWeb::send_100_continue()
178 const char HTTTP_100_CONTINUE
[] = "HTTP/1.1 100 CONTINUE\r\n\r\n";
179 const size_t sent
= txbuf
.sputn(HTTTP_100_CONTINUE
,
180 sizeof(HTTTP_100_CONTINUE
) - 1);
185 size_t RGWCivetWeb::send_header(const boost::string_ref
& name
,
186 const boost::string_ref
& value
)
188 static constexpr char HEADER_SEP
[] = ": ";
189 static constexpr char HEADER_END
[] = "\r\n";
193 sent
+= txbuf
.sputn(name
.data(), name
.length());
194 sent
+= txbuf
.sputn(HEADER_SEP
, sizeof(HEADER_SEP
) - 1);
195 sent
+= txbuf
.sputn(value
.data(), value
.length());
196 sent
+= txbuf
.sputn(HEADER_END
, sizeof(HEADER_END
) - 1);
201 size_t RGWCivetWeb::dump_date_header()
203 char timestr
[TIME_BUF_SIZE
];
205 const time_t gtime
= time(nullptr);
207 struct tm
const* const tmp
= gmtime_r(>ime
, &result
);
209 if (nullptr == tmp
) {
213 if (! strftime(timestr
, sizeof(timestr
),
214 "Date: %a, %d %b %Y %H:%M:%S %Z\r\n", tmp
)) {
218 return txbuf
.sputn(timestr
, strlen(timestr
));
221 size_t RGWCivetWeb::complete_header()
223 size_t sent
= dump_date_header();
225 if (explicit_keepalive
) {
226 constexpr char CONN_KEEP_ALIVE
[] = "Connection: Keep-Alive\r\n";
227 sent
+= txbuf
.sputn(CONN_KEEP_ALIVE
, sizeof(CONN_KEEP_ALIVE
) - 1);
228 } else if (explicit_conn_close
) {
229 constexpr char CONN_KEEP_CLOSE
[] = "Connection: close\r\n";
230 sent
+= txbuf
.sputn(CONN_KEEP_CLOSE
, sizeof(CONN_KEEP_CLOSE
) - 1);
233 static constexpr char HEADER_END
[] = "\r\n";
234 sent
+= txbuf
.sputn(HEADER_END
, sizeof(HEADER_END
) - 1);
240 size_t RGWCivetWeb::send_content_length(uint64_t len
)
242 static constexpr size_t CONLEN_BUF_SIZE
= 128;
244 char sizebuf
[CONLEN_BUF_SIZE
];
245 const auto sizelen
= snprintf(sizebuf
, sizeof(sizebuf
),
246 "Content-Length: %" PRIu64
"\r\n", len
);
247 return txbuf
.sputn(sizebuf
, sizelen
);