]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: rebase mongoose prototype
authorYehuda Sadeh <yehuda@inktank.com>
Tue, 22 Oct 2013 20:53:59 +0000 (13:53 -0700)
committerYehuda Sadeh <yehuda@inktank.com>
Tue, 5 Nov 2013 04:28:06 +0000 (20:28 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
15 files changed:
src/rgw/Makefile.am
src/rgw/rgw_client_io.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_env.cc
src/rgw/rgw_fcgi.cc
src/rgw/rgw_fcgi.h
src/rgw/rgw_http_errors.h
src/rgw/rgw_main.cc
src/rgw/rgw_mongoose.cc [new file with mode: 0644]
src/rgw/rgw_mongoose.h [new file with mode: 0644]
src/rgw/rgw_op.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_rest_client.cc
src/rgw/rgw_rest_conn.cc

index b92c35e08d61f81b37e428355e1c5f9b6b8ed913..2cfa20caace2e2150da38ffa79e4157ee991bc57 100644 (file)
@@ -67,6 +67,8 @@ radosgw_SOURCES = \
        rgw/rgw_http_client.cc \
        rgw/rgw_swift.cc \
        rgw/rgw_swift_auth.cc \
+       rgw/rgw_mongoose.cc \
+       mongoose/mongoose.c \
        rgw/rgw_main.cc
 radosgw_LDADD = $(LIBRGW) $(LIBRGW_DEPS) -lresolv $(CEPH_GLOBAL)
 bin_PROGRAMS += radosgw
@@ -148,5 +150,7 @@ noinst_HEADERS += \
        rgw/rgw_usage.h \
        rgw/rgw_user.h \
        rgw/rgw_bucket.h \
-       rgw/rgw_keystone.h
+       rgw/rgw_keystone.h \
+       rgw/rgw_mongoose.h \
+       mongoose/mongoose.h
 
index 546b16d51f70235114132ce429f775c2e00827fe..4f0168a8cc2e7cc20663a8d48493921aaa6ef222 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "include/types.h"
 
+#include "rgw_common.h"
+
 class RGWClientIO {
   bool account;
 
@@ -12,6 +14,10 @@ class RGWClientIO {
   size_t bytes_received;
 
 protected:
+  RGWEnv env;
+
+  virtual void init_env(CephContext *cct) = 0;
+
   virtual int write_data(const char *buf, int len) = 0;
   virtual int read_data(char *buf, int max) = 0;
 
@@ -19,12 +25,20 @@ public:
   virtual ~RGWClientIO() {}
   RGWClientIO() : account(false), bytes_sent(0), bytes_received(0) {}
 
+  void init(CephContext *cct) {
+    init_env(cct);
+  }
+
   int print(const char *format, ...);
   int write(const char *buf, int len);
   virtual void flush() = 0;
   int read(char *buf, int max, int *actual);
 
-  virtual const char **envp() = 0;
+  virtual int send_status(const char *status, const char *status_name) = 0;
+  virtual int send_100_continue() = 0;
+  virtual int complete_header() = 0;
+
+  RGWEnv& get_env() { return env; }
 
   void set_account(bool _account) {
     account = _account;
index cb87c18b93d71898c55cd52cab51969dbeb0ffd4..34c7bf1e2bc459ba8fe3ebd5aed227fe024339df 100644 (file)
@@ -101,6 +101,8 @@ req_info::req_info(CephContext *cct, class RGWEnv *e) : env(e) {
   if (pos >= 0) {
     request_params = request_uri.substr(pos + 1);
     request_uri = request_uri.substr(0, pos);
+  } else {
+    request_params = env->get("QUERY_STRING", "");
   }
   host = env->get("HTTP_HOST");
 }
@@ -184,8 +186,8 @@ void req_info::init_meta_info(bool *found_bad_meta)
 {
   x_meta_map.clear();
 
-  map<string, string>& m = env->get_map();
-  map<string, string>::iterator iter;
+  map<string, string, ltstr_nocase>& m = env->get_map();
+  map<string, string, ltstr_nocase>::iterator iter;
   for (iter = m.begin(); iter != m.end(); ++iter) {
     const char *prefix;
     const string& header_name = iter->first;
index a7ef250b7d8d345a70689ae53e5267727f7c3e7d..fabf8cf62fdafac30c55187f0835c763c43e440f 100644 (file)
@@ -30,6 +30,7 @@
 #include "rgw_acl.h"
 #include "rgw_cors.h"
 #include "rgw_quota.h"
+#include "rgw_string.h"
 #include "cls/version/cls_version_types.h"
 #include "include/rados/librados.hpp"
 
@@ -273,13 +274,15 @@ class XMLArgs
 class RGWConf;
 
 class RGWEnv {
-  std::map<string, string> env_map;
+  std::map<string, string, ltstr_nocase> env_map;
 public:
   RGWConf *conf; 
 
   RGWEnv();
   ~RGWEnv();
+  void init(CephContext *cct);
   void init(CephContext *cct, char **envp);
+  void set(const char *name, const char *val);
   const char *get(const char *name, const char *def_val = NULL);
   int get_int(const char *name, int def_val = 0);
   bool get_bool(const char *name, bool def_val = 0);
@@ -288,8 +291,8 @@ public:
   bool exists_prefix(const char *prefix);
 
   void remove(const char *name);
-  void set(const char *name, const char *val);
-  std::map<string, string>& get_map() { return env_map; }
+
+  std::map<string, string, ltstr_nocase>& get_map() { return env_map; }
 };
 
 class RGWConf {
index 78ac0d41d7a2714c955a8642b4e7c5309fc5c64a..0628dffbde4a72e08176f46db137caf0e94e9c2f 100644 (file)
@@ -16,6 +16,20 @@ RGWEnv::~RGWEnv()
   delete conf;
 }
 
+void RGWEnv::init(CephContext *cct)
+{
+  conf->init(cct, this);
+}
+
+void RGWEnv::set(const char *name, const char *val)
+{
+  if (!val)
+    val = "";
+  env_map[name] = val;
+
+  dout(0) << "RGWEnv::set(): " << name << ": " << val << dendl;
+}
+
 void RGWEnv::init(CephContext *cct, char **envp)
 {
   const char *p;
@@ -32,12 +46,12 @@ void RGWEnv::init(CephContext *cct, char **envp)
     env_map[name] = val;
   }
 
-  conf->init(cct, this);
+  init(cct);
 }
 
 const char *RGWEnv::get(const char *name, const char *def_val)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   if (iter == env_map.end())
     return def_val;
 
@@ -46,7 +60,7 @@ const char *RGWEnv::get(const char *name, const char *def_val)
 
 int RGWEnv::get_int(const char *name, int def_val)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   if (iter == env_map.end())
     return def_val;
 
@@ -56,7 +70,7 @@ int RGWEnv::get_int(const char *name, int def_val)
 
 bool RGWEnv::get_bool(const char *name, bool def_val)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   if (iter == env_map.end())
     return def_val;
 
@@ -66,7 +80,7 @@ bool RGWEnv::get_bool(const char *name, bool def_val)
 
 size_t RGWEnv::get_size(const char *name, size_t def_val)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   if (iter == env_map.end())
     return def_val;
 
@@ -76,7 +90,7 @@ size_t RGWEnv::get_size(const char *name, size_t def_val)
 
 bool RGWEnv::exists(const char *name)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   return (iter != env_map.end());
 }
 
@@ -85,21 +99,16 @@ bool RGWEnv::exists_prefix(const char *prefix)
   if (env_map.empty() || prefix == NULL)
     return false;
 
-  map<string, string>::iterator iter = env_map.lower_bound(prefix);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.lower_bound(prefix);
   if (iter == env_map.end())
     return false;
 
   return (strncmp(iter->first.c_str(), prefix, strlen(prefix)) == 0);
 }
 
-void RGWEnv::set(const char *name, const char *val)
-{
-  env_map[name] = val;
-}
-
 void RGWEnv::remove(const char *name)
 {
-  map<string, string>::iterator iter = env_map.find(name);
+  map<string, string, ltstr_nocase>::iterator iter = env_map.find(name);
   if (iter != env_map.end())
     env_map.erase(iter);
 }
index 70ed99619754c68874fb58cbf92f3001811e5836..e653ee6fc0de777f8fbfd993b4ac66c54e03b4fa 100644 (file)
@@ -25,7 +25,27 @@ void RGWFCGX::flush()
   FCGX_FFlush(fcgx->out);
 }
 
-const char **RGWFCGX::envp()
+void RGWFCGX::init_env(CephContext *cct)
 {
-  return (const char **)fcgx->envp;
+  env.init(cct, (char **)fcgx->envp);
 }
+
+int RGWFCGX::send_status(const char *status, const char *status_name)
+{
+  return print("Status: %s\n", status);
+}
+
+int RGWFCGX::send_100_continue()
+{
+  int r = send_status("100", "Continue");
+  if (r >= 0) {
+    flush();
+  }
+  return r;
+}
+
+int RGWFCGX::complete_header()
+{
+  return print("\r\n");
+}
+
index ccf48f5954da98b52e6332b4c1ccb2f94c28f4bd..16d9fb6ca306fb0a83dbb019c30b266f8e47108c 100644 (file)
@@ -11,13 +11,16 @@ class RGWFCGX : public RGWClientIO
 {
   FCGX_Request *fcgx;
 protected:
+  void init_env(CephContext *cct);
   int write_data(const char *buf, int len);
   int read_data(char *buf, int len);
 
+  int send_status(const char *status, const char *status_name);
+  int send_100_continue();
+  int complete_header();
 public:
   RGWFCGX(FCGX_Request *_fcgx) : fcgx(_fcgx) {}
   void flush();
-  const char **envp();
 };
 
 
index ba3e522651f95973767aed08812e07767ec38d8d..0ab19addac06826cb4bf8c874510fd98645e0fd4 100644 (file)
@@ -60,6 +60,52 @@ const static struct rgw_http_errors RGW_HTTP_SWIFT_ERRORS[] = {
     { ERR_BAD_URL, 412, "Bad URL" },
 };
 
+struct rgw_http_status_code {
+  int code;
+  const char *name;
+};
+
+const static struct rgw_http_status_code http_codes[] = {
+  { 100, "Continue" },
+  { 200, "OK" },
+  { 201, "Created" },
+  { 202, "Accepted" },
+  { 204, "No Content" },
+  { 205, "Reset Content" },
+  { 206, "Partial Content" },
+  { 207, "Multi Status" },
+  { 208, "Already Reported" },
+  { 300, "Multiple Choices" },
+  { 302, "Found" },
+  { 303, "See Other" },
+  { 304, "Not Modified" },
+  { 305, "User Proxy" },
+  { 306, "Switch Proxy" },
+  { 307, "Temporary Redirect" },
+  { 308, "Permanent Redirect" },
+  { 400, "Bad Request" },
+  { 401, "Unauthorized" },
+  { 402, "Payment Required" },
+  { 403, "Forbidden" },
+  { 404, "Not Found" },
+  { 405, "Method Not Allowed" },
+  { 406, "Not Acceptable" },
+  { 407, "Proxy Authentication Required" },
+  { 408, "Request Timeout" },
+  { 409, "Conflict" },
+  { 410, "Gone" },
+  { 411, "Length Required" },
+  { 412, "Precondition Failed" },
+  { 413, "Request Entity Too Large" },
+  { 414, "Request-URI Too Long" },
+  { 415, "Unsupported Media Type" },
+  { 416, "Requested Range Not Satisfiable" },
+  { 417, "Expectation Failed" },
+  { 422, "Unprocessable Entity" },
+  { 500, "Internal Server Error" },
+  { 0, NULL },
+};
+
 #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
 
 static inline const struct rgw_http_errors *search_err(int err_no, const struct rgw_http_errors *errs, int len)
index 5fbecf88cab0dc7149b6435384387826c08a1f39..d8d98456106e17522c63b79c72f96f2dea5099a3 100644 (file)
@@ -51,6 +51,9 @@
 #include "rgw_log.h"
 #include "rgw_tools.h"
 #include "rgw_resolve.h"
+#include "rgw_mongoose.h"
+
+#include "mongoose/mongoose.h"
 
 #include <map>
 #include <string>
@@ -76,7 +79,6 @@ static RGWProcess *pprocess = NULL;
 
 struct RGWRequest
 {
-  FCGX_Request fcgx;
   uint64_t id;
   struct req_state *s;
   string req_str;
@@ -123,51 +125,64 @@ struct RGWRequest
   }
 };
 
+
+struct RGWFCGXRequest : public RGWRequest {
+  FCGX_Request fcgx;
+};
+
+struct RGWProcessEnv {
+  RGWRados *store;
+  RGWREST *rest;
+  OpsLogSocket *olog;
+};
+
 class RGWProcess {
   RGWRados *store;
   OpsLogSocket *olog;
-  deque<RGWRequest *> m_req_queue;
+  deque<RGWFCGXRequest *> m_req_queue;
   ThreadPool m_tp;
   Throttle req_throttle;
   RGWREST *rest;
   int sock_fd;
 
-  struct RGWWQ : public ThreadPool::WorkQueue<RGWRequest> {
+  RGWProcessEnv *process_env;
+
+  struct RGWWQ : public ThreadPool::WorkQueue<RGWFCGXRequest> {
     RGWProcess *process;
     RGWWQ(RGWProcess *p, time_t timeout, time_t suicide_timeout, ThreadPool *tp)
-      : ThreadPool::WorkQueue<RGWRequest>("RGWWQ", timeout, suicide_timeout, tp), process(p) {}
+      : ThreadPool::WorkQueue<RGWFCGXRequest>("RGWWQ", timeout, suicide_timeout, tp), process(p) {}
 
-    bool _enqueue(RGWRequest *req) {
+    bool _enqueue(RGWFCGXRequest *req) {
       process->m_req_queue.push_back(req);
       perfcounter->inc(l_rgw_qlen);
       dout(20) << "enqueued request req=" << hex << req << dec << dendl;
       _dump_queue();
       return true;
     }
-    void _dequeue(RGWRequest *req) {
+    void _dequeue(RGWFCGXRequest *req) {
       assert(0);
     }
     bool _empty() {
       return process->m_req_queue.empty();
     }
-    RGWRequest *_dequeue() {
+    RGWFCGXRequest *_dequeue() {
       if (process->m_req_queue.empty())
        return NULL;
-      RGWRequest *req = process->m_req_queue.front();
+      RGWFCGXRequest *req = process->m_req_queue.front();
       process->m_req_queue.pop_front();
       dout(20) << "dequeued request req=" << hex << req << dec << dendl;
       _dump_queue();
       perfcounter->inc(l_rgw_qlen, -1);
       return req;
     }
-    void _process(RGWRequest *req) {
+    void _process(RGWFCGXRequest *req) {
       perfcounter->inc(l_rgw_qactive);
       process->handle_request(req);
       process->req_throttle.put(1);
       perfcounter->inc(l_rgw_qactive, -1);
     }
     void _dump_queue() {
-      deque<RGWRequest *>::iterator iter;
+      deque<RGWFCGXRequest *>::iterator iter;
       if (process->m_req_queue.empty()) {
         dout(20) << "RGWWQ: empty" << dendl;
         return;
@@ -185,15 +200,15 @@ class RGWProcess {
   uint64_t max_req_id;
 
 public:
-  RGWProcess(CephContext *cct, RGWRados *rgwstore, OpsLogSocket *_olog, int num_threads, RGWREST *_rest)
-    : store(rgwstore), olog(_olog), m_tp(cct, "RGWProcess::m_tp", num_threads),
+  RGWProcess(CephContext *cct, RGWProcessEnv *pe, int num_threads)
+    : store(pe->store), olog(pe->olog), m_tp(cct, "RGWProcess::m_tp", num_threads),
       req_throttle(cct, "rgw_ops", num_threads * 2),
-      rest(_rest), sock_fd(-1),
+      rest(pe->rest), sock_fd(-1),
       req_wq(this, g_conf->rgw_op_thread_timeout,
             g_conf->rgw_op_thread_suicide_timeout, &m_tp),
       max_req_id(0) {}
   void run();
-  void handle_request(RGWRequest *req);
+  void handle_request(RGWFCGXRequest *req);
 
   void close_fd() {
     if (sock_fd >= 0)
@@ -241,7 +256,7 @@ void RGWProcess::run()
   m_tp.start();
 
   for (;;) {
-    RGWRequest *req = new RGWRequest;
+    RGWFCGXRequest *req = new RGWFCGXRequest;
     req->id = ++max_req_id;
     dout(10) << "allocated request req=" << hex << req << dec << dendl;
     FCGX_InitRequest(&req->fcgx, sock_fd, 0);
@@ -295,19 +310,20 @@ static int call_log_intent(RGWRados *store, void *ctx, rgw_obj& obj, RGWIntentEv
   return rgw_log_intent(store, s, obj, intent);
 }
 
-void RGWProcess::handle_request(RGWRequest *req)
+void RGWProcess::handle_request(RGWFCGXRequest *req)
 {
   FCGX_Request *fcgx = &req->fcgx;
   int ret;
-  RGWEnv rgw_env;
   RGWFCGX client_io(fcgx);
 
+  client_io.init(g_ceph_context);
+
   req->log_init();
 
   dout(1) << "====== starting new request req=" << hex << req << dec << " =====" << dendl;
   perfcounter->inc(l_rgw_req);
 
-  rgw_env.init(g_ceph_context, fcgx->envp);
+  RGWEnv& rgw_env = client_io.get_env();
 
   struct req_state *s = req->init_state(g_ceph_context, &rgw_env);
   s->obj_ctx = store->create_context(s);
@@ -414,6 +430,136 @@ done:
   delete req;
 }
 
+
+static int mongoose_callback(struct mg_event *event) {
+  RGWProcessEnv *pe = (RGWProcessEnv *)event->user_data;
+  RGWRados *store = pe->store;
+  RGWREST *rest = pe->rest;
+  OpsLogSocket *olog = pe->olog;
+
+  if (event->type != MG_REQUEST_BEGIN)
+    return 0;
+
+  RGWRequest *req = new RGWRequest;
+  int ret;
+  RGWMongoose client_io(event);
+
+  client_io.init(g_ceph_context);
+
+  req->log_init();
+
+  dout(1) << "====== starting new request req=" << hex << req << dec << " =====" << dendl;
+  perfcounter->inc(l_rgw_req);
+
+  RGWEnv& rgw_env = client_io.get_env();
+
+  struct req_state *s = req->init_state(g_ceph_context, &rgw_env);
+  s->obj_ctx = store->create_context(s);
+  store->set_intent_cb(s->obj_ctx, call_log_intent);
+
+  s->req_id = store->unique_id(req->id);
+
+  req->log(s, "initializing");
+
+  RGWOp *op = NULL;
+  int init_error = 0;
+  bool should_log = false;
+  RGWRESTMgr *mgr;
+  RGWHandler *handler = rest->get_handler(store, s, &client_io, &mgr, &init_error);
+  if (init_error != 0) {
+    abort_early(s, NULL, init_error);
+    goto done;
+  }
+
+  should_log = mgr->get_logging();
+
+  req->log(s, "getting op");
+  op = handler->get_op(store);
+  if (!op) {
+    abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED);
+    goto done;
+  }
+  req->op = op;
+
+  req->log(s, "authorizing");
+  ret = handler->authorize();
+  if (ret < 0) {
+    dout(10) << "failed to authorize request" << dendl;
+    abort_early(s, op, ret);
+    goto done;
+  }
+
+  if (s->user.suspended) {
+    dout(10) << "user is suspended, uid=" << s->user.user_id << dendl;
+    abort_early(s, op, -ERR_USER_SUSPENDED);
+    goto done;
+  }
+  req->log(s, "reading permissions");
+  ret = handler->read_permissions(op);
+  if (ret < 0) {
+    abort_early(s, op, ret);
+    goto done;
+  }
+
+  req->log(s, "init op");
+  ret = op->init_processing();
+  if (ret < 0) {
+    abort_early(s, op, ret);
+    goto done;
+  }
+
+  req->log(s, "verifying op mask");
+  ret = op->verify_op_mask();
+  if (ret < 0) {
+    abort_early(s, op, ret);
+    goto done;
+  }
+
+  req->log(s, "verifying op permissions");
+  ret = op->verify_permission();
+  if (ret < 0) {
+    if (s->system_request) {
+      dout(2) << "overriding permissions due to system operation" << dendl;
+    } else {
+      abort_early(s, op, ret);
+      goto done;
+    }
+  }
+
+  req->log(s, "verifying op params");
+  ret = op->verify_params();
+  if (ret < 0) {
+    abort_early(s, op, ret);
+    goto done;
+  }
+
+  if (s->expect_cont)
+    dump_continue(s);
+
+  req->log(s, "executing");
+  op->execute();
+  op->complete();
+done:
+  if (should_log) {
+    rgw_log_op(store, s, (op ? op->name() : "unknown"), olog);
+  }
+
+  int http_ret = s->err.http_ret;
+
+  req->log_format(s, "http status=%d", http_ret);
+
+  if (handler)
+    handler->put_op(op);
+  rest->put_handler(handler);
+  store->destroy_context(s->obj_ctx);
+
+  dout(1) << "====== req done req=" << hex << req << dec << " http_status=" << http_ret << " ======" << dendl;
+  delete req;
+
+// Mark as processed
+  return 1;
+}
+
 #ifdef HAVE_CURL_MULTI_WAIT
 static void check_curl()
 {
@@ -580,7 +726,15 @@ int main(int argc, const char **argv)
     olog->init(g_conf->rgw_ops_log_socket_path);
   }
 
-  pprocess = new RGWProcess(g_ceph_context, store, olog, g_conf->rgw_thread_pool_size, &rest);
+  struct mg_context *ctx;
+  const char *options[] = {"listening_ports", "8080", NULL};
+
+  RGWProcessEnv pe = { store, &rest, olog };
+
+  ctx = mg_start((const char **)&options, &mongoose_callback, &pe);
+  assert(ctx);
+
+  RGWProcess *pprocess = new RGWProcess(g_ceph_context, &pe, g_conf->rgw_thread_pool_size);
 
   init_async_signal_handler();
   register_async_signal_handler(SIGHUP, sighup_handler);
@@ -591,6 +745,9 @@ int main(int argc, const char **argv)
   sighandler_alrm = signal(SIGALRM, godown_alarm);
 
   pprocess->run();
+
+  mg_stop(ctx);
+
   derr << "shutting down" << dendl;
 
   unregister_async_signal_handler(SIGHUP, sighup_handler);
diff --git a/src/rgw/rgw_mongoose.cc b/src/rgw/rgw_mongoose.cc
new file mode 100644 (file)
index 0000000..cbbc192
--- /dev/null
@@ -0,0 +1,112 @@
+
+#include <string.h>
+
+#include "mongoose/mongoose.h"
+#include "rgw_mongoose.h"
+
+
+#define dout_subsys ceph_subsys_rgw
+
+int RGWMongoose::write_data(const char *buf, int len)
+{
+  if (!sent_header) {
+    header_data.append(buf, len);
+    return 0;
+  }
+  dout(0) << buf << dendl;
+  return mg_write(event->conn, buf, len);
+}
+
+RGWMongoose::RGWMongoose(mg_event *_event) : event(_event), sent_header(false) {
+}
+
+int RGWMongoose::read_data(char *buf, int len)
+{
+  return mg_read(event->conn, buf, len);
+}
+
+void RGWMongoose::flush()
+{
+}
+
+void RGWMongoose::init_env(CephContext *cct)
+{
+  env.init(cct);
+  struct mg_request_info *info = event->request_info;
+  if (!info)
+    return;
+
+  for (int i = 0; i < info->num_headers; i++) {
+    struct mg_request_info::mg_header *header = &info->http_headers[i];
+
+    if (strcasecmp(header->name, "content-length") == 0) {
+      env.set("CONTENT_LENGTH", header->value);
+      continue;
+    }
+
+    if (strcasecmp(header->name, "content-type") == 0) {
+      env.set("CONTENT_TYPE", header->value);
+      continue;
+    }
+
+    int len = strlen(header->name) + 5; /* HTTP_ prepended */
+    char buf[len + 1];
+    memcpy(buf, "HTTP_", 5);
+    const char *src = header->name;
+    char *dest = &buf[5];
+    for (; *src; src++, dest++) {
+      char c = *src;
+      switch (c) {
+       case '-':
+         c = '_';
+         break;
+       default:
+         c = toupper(c);
+         break;
+      }
+      *dest = c;
+    }
+    *dest = '\0';
+    
+    env.set(buf, header->value);
+  }
+
+  env.set("REQUEST_METHOD", info->request_method);
+  env.set("REQUEST_URI", info->uri);
+  env.set("QUERY_STRING", info->query_string);
+  env.set("REMOTE_USER", info->remote_user);
+  env.set("SCRIPT_URI", info->uri); /* FIXME */
+}
+
+int RGWMongoose::send_status(const char *status, const char *status_name)
+{
+  char buf[128];
+
+  if (!status_name)
+    status_name = "";
+
+  snprintf(buf, sizeof(buf), "HTTP/1.1 %s %s\n", status, status_name);
+
+  bufferlist bl;
+  bl.append(buf);
+  bl.append(header_data);
+  header_data = bl;
+
+  return 0;
+}
+
+int RGWMongoose::send_100_continue()
+{
+  char buf[] = "HTTP/1.1 100 CONTINUE\r\n\r\n";
+
+  return mg_write(event->conn, buf, sizeof(buf) - 1);
+}
+
+int RGWMongoose::complete_header()
+{
+  header_data.append("\r\n");
+
+  sent_header = true;
+
+  return write_data(header_data.c_str(), header_data.length());
+}
diff --git a/src/rgw/rgw_mongoose.h b/src/rgw/rgw_mongoose.h
new file mode 100644 (file)
index 0000000..33787d0
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef CEPH_RGW_MONGOOSE_H
+#define CEPH_RGW_MONGOOSE_H
+
+#include "rgw_client_io.h"
+
+
+struct mg_event;
+struct mg_connection;
+
+
+class RGWMongoose : public RGWClientIO
+{
+  mg_event *event;
+
+  bufferlist header_data;
+
+  bool sent_header;
+
+protected:
+  void init_env(CephContext *cct);
+
+  int write_data(const char *buf, int len);
+  int read_data(char *buf, int len);
+
+  int send_status(const char *status, const char *status_name);
+  int send_100_continue();
+  int complete_header();
+
+public:
+  RGWMongoose(mg_event *_event);
+  void flush();
+};
+
+
+#endif
index c750276596f8327765273b4f310cb2b396b18268..ad924c1b9f92eb4a73514b5bd04ab3fba884d05e 100644 (file)
@@ -2606,14 +2606,6 @@ int RGWHandler::init(RGWRados *_store, struct req_state *_s, RGWClientIO *cio)
   store = _store;
   s = _s;
 
-  if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 20)) {
-    const char *p;
-    const char **envp = cio->envp();
-    for (int i=0; (p = envp[i]); ++i) {
-      ldout(s->cct, 20) << p << dendl;
-    }
-  }
-
   return 0;
 }
 
index 30cb0d9b66e5e857a4b593a55ea7a1a9f8b4c314..f05728ec9fdb445685756cf3ebdd15b42dec36fa 100644 (file)
@@ -13,6 +13,7 @@
 #include "rgw_rest_s3.h"
 #include "rgw_swift_auth.h"
 #include "rgw_cors_s3.h"
+#include "rgw_http_errors.h"
 
 #include "rgw_client_io.h"
 #include "rgw_resolve.h"
@@ -59,6 +60,7 @@ struct generic_attr generic_attrs[] = {
 
 map<string, string> rgw_to_http_attrs;
 static map<string, string> generic_attrs_map;
+map<int, const char *> http_status_names;
 
 /*
  * make attrs look_like_this
@@ -155,13 +157,17 @@ void rgw_rest_init(CephContext *cct)
 
     generic_attrs_map[http_header] = rgw_attr;
   }
+
+  for (const struct rgw_http_status_code *h = http_codes; h->code; h++) {
+    http_status_names[h->code] = h->name;
+  }
 }
 
-static void dump_status(struct req_state *s, const char *status)
+static void dump_status(struct req_state *s, const char *status, const char *status_name)
 {
-  int r = s->cio->print("Status: %s\n", status);
+  int r = s->cio->send_status(status, status_name);
   if (r < 0) {
-    ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl;
+    ldout(s->cct, 0) << "ERROR: s->cio->send_status() returned err=" << r << dendl;
   }
 }
 
@@ -218,14 +224,14 @@ void dump_errno(struct req_state *s)
 {
   char buf[32];
   snprintf(buf, sizeof(buf), "%d", s->err.http_ret);
-  dump_status(s, buf);
+  dump_status(s, buf, http_status_names[s->err.http_ret]);
 }
 
 void dump_errno(struct req_state *s, int err)
 {
   char buf[32];
   snprintf(buf, sizeof(buf), "%d", err);
-  dump_status(s, buf);
+  dump_status(s, buf, http_status_names[s->err.http_ret]);
 }
 
 void dump_content_length(struct req_state *s, uint64_t len)
@@ -434,10 +440,15 @@ void end_header(struct req_state *s, RGWOp *op, const char *content_type)
     s->formatter->close_section();
     dump_content_length(s, s->formatter->get_len());
   }
-  int r = s->cio->print("Content-type: %s\r\n\r\n", content_type);
+  int r = s->cio->print("Content-type: %s\r\n", content_type);
   if (r < 0) {
     ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl;
   }
+  r = s->cio->complete_header();
+  if (r < 0) {
+    ldout(s->cct, 0) << "ERROR: s->cio->complete_header() returned err=" << r << dendl;
+  }
+
   s->cio->set_account(true);
   rgw_flush_formatter_and_reset(s, s->formatter);
 }
@@ -457,8 +468,7 @@ void abort_early(struct req_state *s, RGWOp *op, int err_no)
 
 void dump_continue(struct req_state *s)
 {
-  dump_status(s, "100");
-  s->cio->flush();
+  s->cio->send_100_continue();
 }
 
 void dump_range(struct req_state *s, uint64_t ofs, uint64_t end, uint64_t total)
index 7f4e2b6582dc1907686543e75252027ae7974e8f..256db77aba77148d01c598f09fb80d9b266b9818 100644 (file)
@@ -171,7 +171,7 @@ void RGWRESTSimpleRequest::get_params_str(map<string, string>& extra_args, strin
 
 int RGWRESTSimpleRequest::sign_request(RGWAccessKey& key, RGWEnv& env, req_info& info)
 {
-  map<string, string>& m = env.get_map();
+  map<string, string, ltstr_nocase>& m = env.get_map();
 
   map<string, string>::iterator i;
   for (i = m.begin(); i != m.end(); ++i) {
@@ -218,7 +218,7 @@ int RGWRESTSimpleRequest::forward_request(RGWAccessKey& key, req_info& info, siz
     return ret;
   }
 
-  map<string, string>& m = new_env.get_map();
+  map<string, string, ltstr_nocase>& m = new_env.get_map();
   map<string, string>::iterator iter;
   for (iter = m.begin(); iter != m.end(); ++iter) {
     headers.push_back(make_pair<string, string>(iter->first, iter->second));
@@ -364,7 +364,7 @@ static void grants_by_type_add_perm(map<int, string>& grants_by_type, int perm,
   }
 }
 
-static void add_grants_headers(map<int, string>& grants, map<string, string>& attrs, map<string, string>& meta_map)
+static void add_grants_headers(map<int, string>& grants, map<string, string, ltstr_nocase>& attrs, map<string, string>& meta_map)
 {
   struct grant_type_to_header *t;
 
@@ -405,7 +405,7 @@ int RGWRESTStreamWriteRequest::put_obj_init(RGWAccessKey& key, rgw_obj& obj, uin
   new_info.request_uri = new_info.script_uri;
   new_info.effective_uri = new_info.effective_uri;
 
-  map<string, string>& m = new_env.get_map();
+  map<string, string, ltstr_nocase>& m = new_env.get_map();
   map<string, bufferlist>::iterator bliter;
 
   /* merge send headers */
@@ -582,7 +582,7 @@ int RGWRESTStreamReadRequest::get_obj(RGWAccessKey& key, map<string, string>& ex
     return ret;
   }
 
-  map<string, string>& m = new_env.get_map();
+  map<string, string, ltstr_nocase>& m = new_env.get_map();
   map<string, string>::iterator iter;
   for (iter = m.begin(); iter != m.end(); ++iter) {
     headers.push_back(make_pair<string, string>(iter->first, iter->second));
index 35a8ac258e6350e33a95d38acaefbc2e13b44143..32bf0eaacd39001c748801feaa2aeb37b714a393 100644 (file)
@@ -92,7 +92,7 @@ int RGWRESTConn::get_obj(const string& uid, req_info *info /* optional */, rgw_o
   *req = new RGWRESTStreamReadRequest(cct, url, cb, NULL, &params);
   map<string, string> extra_headers;
   if (info) {
-    map<string, string>& orig_map = info->env->get_map();
+    map<string, string, ltstr_nocase>& orig_map = info->env->get_map();
 
     /* add original headers that start with HTTP_X_AMZ_ */
 #define SEARCH_AMZ_PREFIX "HTTP_X_AMZ_"