]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add rgw_log_http_headers option
authorMatt Benjamin <mbenjamin@redhat.com>
Fri, 12 Feb 2016 22:02:53 +0000 (17:02 -0500)
committerMatt Benjamin <mbenjamin@redhat.com>
Tue, 13 Dec 2016 23:13:42 +0000 (18:13 -0500)
Tracks headers that should be handled conditionally (currently,
can only log, so using minimal structure to represent the
mapping).

Adds map of custom headers to rgw_log_entry, and populate it with
headers pre-selected for custom logging in RGWREST.  Added to encoder
and Formatter output.

Some additional optimization possible.

Signed-off-by: Matt Benjamin <mbenjamin@redhat.com>
12 files changed:
src/common/config_opts.h
src/include/str_list.h
src/rgw/librgw.cc
src/rgw/rgw_env.cc
src/rgw/rgw_log.cc
src/rgw/rgw_log.h
src/rgw/rgw_main.cc
src/rgw/rgw_metadata.cc
src/rgw/rgw_period_history.cc
src/rgw/rgw_process.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h

index be19ec68984f29c838763d879f4421fd193a9572..c947b55a75c02ad98a41e145a692612b573c8d68 100644 (file)
@@ -1538,6 +1538,7 @@ OPTION(rgw_objexp_hints_num_shards, OPT_U32, 127) // maximum number of parts in
 OPTION(rgw_objexp_chunk_size, OPT_U32, 100) // maximum number of entries in a single operation when processing objexp data
 
 OPTION(rgw_enable_static_website, OPT_BOOL, false) // enable static website feature
+OPTION(rgw_log_http_headers, OPT_STR, "" ) // list of HTTP headers to log when seen, ignores case (e.g., http_x_forwarded_for
 
 OPTION(rgw_num_async_rados_threads, OPT_INT, 32) // num of threads to use for async rados operations
 OPTION(rgw_md_notify_interval_msec, OPT_INT, 200) // metadata changes notification interval to followers
index 4ba0cadd960ccc84db61e52a25d57920d9f0ade6..12cf1280854e7b061091136b1911fd4a50c66eda 100644 (file)
@@ -91,4 +91,12 @@ inline std::string str_join(const std::vector<std::string>& v, std::string sep)
   return r;
 }
 
+static inline std::vector<std::string> get_str_vec(const std::string& str)
+{
+  std::vector<std::string> str_vec;
+  const char *delims = ";,= \t";
+  get_str_vec(str, delims, str_vec);
+  return std::move(str_vec);
+}
+
 #endif
index 8b5f24c7dbaccd0a6b2501d3752dfc529d1e8107..9ddf99955f82d41160f66a6e35ea0ce0261dab19 100644 (file)
@@ -297,7 +297,8 @@ namespace rgw {
               << e.what() << dendl;
     }
     if (should_log) {
-      rgw_log_op(store, s, (op ? op->name() : "unknown"), olog);
+      rgw_log_op(store, nullptr /* !rest */, s,
+                (op ? op->name() : "unknown"), olog);
     }
 
     int http_ret = s->err.http_ret;
index 56ac6b3e9a0d52e61750ce3a17776fd2cba8e71f..63fce5185c50f51709cdb119170ede1895785fe3 100644 (file)
@@ -7,6 +7,8 @@
 #include <string>
 #include <map>
 
+#include "include/assert.h"
+
 #define dout_subsys ceph_subsys_rgw
 
 void RGWEnv::init(CephContext *cct)
index 79e9417115e64ed9fe7b59c08432b01b7fd1c4cd..3b91b0685bf851ca1cb87139a801d54e876ae6ec 100644 (file)
@@ -12,6 +12,7 @@
 #include "rgw_acl.h"
 #include "rgw_rados.h"
 #include "rgw_client_io.h"
+#include "rgw_rest.h"
 
 #define dout_subsys ceph_subsys_rgw
 
@@ -250,6 +251,15 @@ void rgw_format_ops_log_entry(struct rgw_log_entry& entry, Formatter *formatter)
   formatter->dump_int("total_time", total_time);
   formatter->dump_string("user_agent",  entry.user_agent);
   formatter->dump_string("referrer",  entry.referrer);
+  if (entry.x_headers.size() > 0) {
+    formatter->open_array_section("http_x_headers");
+    for (const auto& iter: entry.x_headers) {
+      formatter->open_object_section(iter.first.c_str());
+      formatter->dump_string(iter.first.c_str(), iter.second);
+      formatter->close_section();
+    }
+    formatter->close_section();
+  }
   formatter->close_section();
 }
 
@@ -290,7 +300,8 @@ void OpsLogSocket::log(struct rgw_log_entry& entry)
   append_output(bl);
 }
 
-int rgw_log_op(RGWRados *store, struct req_state *s, const string& op_name, OpsLogSocket *olog)
+int rgw_log_op(RGWRados *store, RGWREST* const rest, struct req_state *s,
+              const string& op_name, OpsLogSocket *olog)
 {
   struct rgw_log_entry entry;
   string bucket_id;
@@ -339,6 +350,18 @@ int rgw_log_op(RGWRados *store, struct req_state *s, const string& op_name, OpsL
   set_param_str(s, "REQUEST_URI", entry.uri);
   set_param_str(s, "REQUEST_METHOD", entry.op);
 
+  /* custom header logging */
+  if (rest) {
+    if (rest->log_x_headers()) {
+      for (const auto& iter : s->info.env->get_map()) {
+       if (rest->log_x_header(iter.first)) {
+         entry.x_headers.insert(
+           rgw_log_entry::headers_map::value_type(iter.first, iter.second));
+       }
+      }
+    }
+  }
+
   entry.user = s->user->user_id.to_str();
   if (s->object_acl)
     entry.object_owner = s->object_acl->get_owner().get_id();
index 51acfdf8f9d491e2f72acfd3478707610f31fd08..ab800c7fa2ab1d815eaefed31633cad76d4f79b4 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef CEPH_RGW_LOG_H
 #define CEPH_RGW_LOG_H
 
+#include <boost/container/flat_set.hpp>
 #include "rgw_common.h"
 #include "include/utime.h"
 #include "common/Formatter.h"
@@ -12,6 +13,9 @@
 class RGWRados;
 
 struct rgw_log_entry {
+
+  using headers_map = std::map<std::string, std::string>;
+
   rgw_user object_owner;
   rgw_user bucket_owner;
   string bucket;
@@ -30,9 +34,10 @@ struct rgw_log_entry {
   string user_agent;
   string referrer;
   string bucket_id;
+  headers_map x_headers;
 
   void encode(bufferlist &bl) const {
-    ENCODE_START(8, 5, bl);
+    ENCODE_START(9, 5, bl);
     ::encode(object_owner.id, bl);
     ::encode(bucket_owner.id, bl);
     ::encode(bucket, bl);
@@ -54,6 +59,7 @@ struct rgw_log_entry {
     ::encode(obj, bl);
     ::encode(object_owner, bl);
     ::encode(bucket_owner, bl);
+    ::encode(x_headers, bl);
     ENCODE_FINISH(bl);
   }
   void decode(bufferlist::iterator &p) {
@@ -100,6 +106,9 @@ struct rgw_log_entry {
       ::decode(object_owner, p);
       ::decode(bucket_owner, p);
     }
+    if (struct_v >= 9) {
+      ::decode(x_headers, p);
+    }
     DECODE_FINISH(p);
   }
   void dump(Formatter *f) const;
@@ -123,10 +132,14 @@ public:
   void log(struct rgw_log_entry& entry);
 };
 
-int rgw_log_op(RGWRados *store, struct req_state *s, const string& op_name, OpsLogSocket *olog);
+class RGWREST;
+
+int rgw_log_op(RGWRados *store, RGWREST* const rest, struct req_state *s,
+              const string& op_name, OpsLogSocket *olog);
 void rgw_log_usage_init(CephContext *cct, RGWRados *store);
 void rgw_log_usage_finalize();
-void rgw_format_ops_log_entry(struct rgw_log_entry& entry, Formatter *formatter);
+void rgw_format_ops_log_entry(struct rgw_log_entry& entry,
+                             Formatter *formatter);
 
-#endif
+#endif /* CEPH_RGW_LOG_H */
 
index c2678e8cc91d16ab1ea2205f6dcec447a1e080bd..8138b8798d8c05911e41292a2958985d0e259443 100644 (file)
@@ -421,6 +421,9 @@ int main(int argc, const char **argv)
     rest.register_resource(g_conf->rgw_admin_entry, admin_resource);
   }
 
+  /* Header custom behavior */
+  rest.register_x_headers(g_conf->rgw_log_http_headers);
+
   OpsLogSocket *olog = NULL;
 
   if (!g_conf->rgw_ops_log_socket_path.empty()) {
index 5772246bd2e4b2cf9177e2ddaf4cf6a6ad27b710..8459c56d1447d864a912db72fd7fba7e5f72fdf0 100644 (file)
@@ -14,6 +14,8 @@
 #include "rgw_cr_rados.h"
 #include "rgw_boost_asio_yield.h"
 
+#include "include/assert.h"
+
 #define dout_subsys ceph_subsys_rgw
 
 void LogStatusDump::dump(Formatter *f) const {
index 29926236b46ade1f613ccfcda669c25d6761195b..eff0e78ad9dee2fef48b3919acff79f34c4cd218 100644 (file)
@@ -4,6 +4,8 @@
 #include "rgw_period_history.h"
 #include "rgw_rados.h"
 
+#include "include/assert.h"
+
 #define dout_subsys ceph_subsys_rgw
 
 #undef dout_prefix
index 55c390aae58f586712a4aa454a45aee90965cc89..6b2c79d5939304800082a4e6c256e1e29a44096e 100644 (file)
@@ -162,6 +162,7 @@ int process_request(RGWRados* const store,
     abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED, handler);
     goto done;
   }
+
   req->op = op;
   dout(10) << "op=" << typeid(*op).name() << dendl;
 
@@ -209,7 +210,7 @@ done:
   }
 
   if (should_log) {
-    rgw_log_op(store, s, (op ? op->name() : "unknown"), olog);
+    rgw_log_op(store, rest, s, (op ? op->name() : "unknown"), olog);
   }
 
   int http_ret = s->err.http_ret;
index 7520b6a56921e360fa5524b09f5ce97fb7b0e436..2ca556e20b8df4d6d753a8ed1a2bba5b43024695 100644 (file)
@@ -4,6 +4,7 @@
 #include <errno.h>
 #include <limits.h>
 
+#include <boost/algorithm/string.hpp>
 #include "common/Formatter.h"
 #include "common/HTMLFormatter.h"
 #include "common/utf8.h"
@@ -1790,6 +1791,15 @@ RGWRESTMgr* RGWRESTMgr::get_resource_mgr(struct req_state* const s,
   return this;
 }
 
+void RGWREST::register_x_headers(const string& s_headers)
+{
+  std::vector<std::string> hdrs = get_str_vec(s_headers);
+  for (auto& hdr : hdrs) {
+    boost::algorithm::to_upper(hdr); // XXX
+    (void) x_headers.insert(hdr);
+  }
+}
+
 RGWRESTMgr::~RGWRESTMgr()
 {
   map<string, RGWRESTMgr *>::iterator iter;
index ec178d246d87a11e8e4a5f98f2ffd33a503c1f62..293b5268de2e6b9f810e11e3b32069533af25bfb 100644 (file)
@@ -7,7 +7,8 @@
 #define TIME_BUF_SIZE 128
 
 #include <boost/utility/string_ref.hpp>
-
+#include <boost/container/flat_set.hpp>
+#include "common/sstring.hh"
 #include "common/ceph_json.h"
 #include "include/assert.h" /* needed because of common/ceph_json.h */
 #include "rgw_op.h"
@@ -403,6 +404,7 @@ public:
 
 class RGWHandler_REST : public RGWHandler {
 protected:
+
   virtual bool is_obj_update_op() { return false; }
   virtual RGWOp *op_get() { return NULL; }
   virtual RGWOp *op_put() { return NULL; }
@@ -439,6 +441,7 @@ class RGWHandler_REST_S3;
 
 class RGWRESTMgr {
   bool should_log;
+
 protected:
   std::map<std::string, RGWRESTMgr*> resource_mgrs;
   std::multimap<size_t, std::string> resources_by_size;
@@ -495,6 +498,8 @@ class RGWLibIO;
 class RGWRestfulIO;
 
 class RGWREST {
+  using x_header = basic_sstring<char, uint16_t, 32>;
+  boost::container::flat_set<x_header> x_headers;
   RGWRESTMgr mgr;
 
   static int preprocess(struct req_state *s, rgw::io::BasicClient* rio);
@@ -511,6 +516,7 @@ public:
                          RGWLibIO *io, RGWRESTMgr **pmgr,
                          int *init_error);
 #endif
+
   void put_handler(RGWHandler_REST *handler) {
     mgr.put_handler(handler);
   }
@@ -522,9 +528,20 @@ public:
 
     mgr.register_resource(resource, m);
   }
+
   void register_default_mgr(RGWRESTMgr *m) {
     mgr.register_default_mgr(m);
   }
+
+  void register_x_headers(const std::string& headers);
+
+  bool log_x_headers(void) {
+    return (x_headers.size() > 0);
+  }
+
+  bool log_x_header(const std::string& header) {
+    return (x_headers.find(header) != x_headers.end());
+  }
 };
 
 static constexpr int64_t NO_CONTENT_LENGTH = -1;