initial code repo
[stor4nfv.git] / src / ceph / src / rgw / rgw_formats.cc
diff --git a/src/ceph/src/rgw/rgw_formats.cc b/src/ceph/src/rgw/rgw_formats.cc
new file mode 100644 (file)
index 0000000..8a84083
--- /dev/null
@@ -0,0 +1,370 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include <boost/format.hpp>
+
+#include "common/escape.h"
+#include "common/Formatter.h"
+#include "rgw/rgw_common.h"
+#include "rgw/rgw_formats.h"
+#include "rgw/rgw_rest.h"
+
+#define LARGE_SIZE 8192
+
+#define dout_subsys ceph_subsys_rgw
+
+RGWFormatter_Plain::RGWFormatter_Plain(const bool ukv)
+  : use_kv(ukv)
+{
+}
+
+RGWFormatter_Plain::~RGWFormatter_Plain()
+{
+  free(buf);
+}
+
+void RGWFormatter_Plain::flush(ostream& os)
+{
+  if (!buf)
+    return;
+
+  if (len) {
+    os << buf;
+    os.flush();
+  }
+
+  reset_buf();
+}
+
+void RGWFormatter_Plain::reset_buf()
+{
+  free(buf);
+  buf = NULL;
+  len = 0;
+  max_len = 0;
+}
+
+void RGWFormatter_Plain::reset()
+{
+  reset_buf();
+  stack.clear();
+  min_stack_level = 0;
+}
+
+void RGWFormatter_Plain::open_array_section(const char *name)
+{
+  struct plain_stack_entry new_entry;
+  new_entry.is_array = true;
+  new_entry.size = 0;
+
+  if (use_kv && min_stack_level > 0 && !stack.empty()) {
+    struct plain_stack_entry& entry = stack.back();
+
+    if (!entry.is_array)
+      dump_format(name, "");
+  }
+
+  stack.push_back(new_entry);
+}
+
+void RGWFormatter_Plain::open_array_section_in_ns(const char *name, const char *ns)
+{
+  ostringstream oss;
+  oss << name << " " << ns;
+  open_array_section(oss.str().c_str());
+}
+
+void RGWFormatter_Plain::open_object_section(const char *name)
+{
+  struct plain_stack_entry new_entry;
+  new_entry.is_array = false;
+  new_entry.size = 0;
+
+  if (use_kv && min_stack_level > 0)
+    dump_format(name, "");
+
+  stack.push_back(new_entry);
+}
+
+void RGWFormatter_Plain::open_object_section_in_ns(const char *name,
+                                                  const char *ns)
+{
+  ostringstream oss;
+  oss << name << " " << ns;
+  open_object_section(oss.str().c_str());
+}
+
+void RGWFormatter_Plain::close_section()
+{
+  stack.pop_back();
+}
+
+void RGWFormatter_Plain::dump_unsigned(const char *name, uint64_t u)
+{
+  dump_value_int(name, "%" PRIu64, u);
+}
+
+void RGWFormatter_Plain::dump_int(const char *name, int64_t u)
+{
+  dump_value_int(name, "%" PRId64, u);
+}
+
+void RGWFormatter_Plain::dump_float(const char *name, double d)
+{
+  dump_value_int(name, "%f", d);
+}
+
+void RGWFormatter_Plain::dump_string(const char *name, const std::string& s)
+{
+  dump_format(name, "%s", s.c_str());
+}
+
+std::ostream& RGWFormatter_Plain::dump_stream(const char *name)
+{
+  // TODO: implement this!
+  ceph_abort();
+}
+
+void RGWFormatter_Plain::dump_format_va(const char *name, const char *ns, bool quoted, const char *fmt, va_list ap)
+{
+  char buf[LARGE_SIZE];
+
+  struct plain_stack_entry& entry = stack.back();
+
+  if (!min_stack_level)
+    min_stack_level = stack.size();
+
+  bool should_print = ((stack.size() == min_stack_level && !entry.size) || use_kv);
+
+  entry.size++;
+
+  if (!should_print)
+    return;
+
+  vsnprintf(buf, LARGE_SIZE, fmt, ap);
+
+  const char *eol;
+  if (wrote_something) {
+    if (use_kv && entry.is_array && entry.size > 1)
+      eol = ", ";
+    else
+      eol = "\n";
+  } else
+    eol = "";
+  wrote_something = true;
+
+  if (use_kv && !entry.is_array)
+    write_data("%s%s: %s", eol, name, buf);
+  else
+    write_data("%s%s", eol, buf);
+}
+
+int RGWFormatter_Plain::get_len() const
+{
+  // don't include null termination in length
+  return (len ? len - 1 : 0);
+}
+
+void RGWFormatter_Plain::write_raw_data(const char *data)
+{
+  write_data("%s", data);
+}
+
+void RGWFormatter_Plain::write_data(const char *fmt, ...)
+{
+#define LARGE_ENOUGH_LEN 128
+  int n, size = LARGE_ENOUGH_LEN;
+  char s[size + 8];
+  char *p, *np;
+  bool p_on_stack;
+  va_list ap;
+  int pos;
+
+  p = s;
+  p_on_stack = true;
+
+  while (1) {
+    va_start(ap, fmt);
+    n = vsnprintf(p, size, fmt, ap);
+    va_end(ap);
+
+    if (n > -1 && n < size)
+      goto done;
+    /* Else try again with more space. */
+    if (n > -1)    /* glibc 2.1 */
+      size = n+1; /* precisely what is needed */
+    else           /* glibc 2.0 */
+      size *= 2;  /* twice the old size */
+    if (p_on_stack)
+      np = (char *)malloc(size + 8);
+    else
+      np = (char *)realloc(p, size + 8);
+    if (!np)
+      goto done_free;
+    p = np;
+    p_on_stack = false;
+  }
+done:
+#define LARGE_ENOUGH_BUF 4096
+  if (!buf) {
+    max_len = max(LARGE_ENOUGH_BUF, size);
+    buf = (char *)malloc(max_len);
+    if (!buf) {
+      cerr << "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len << " bytes" << std::endl;
+      goto done_free;
+    }
+  }
+
+  if (len + size > max_len) {
+    max_len = len + size + LARGE_ENOUGH_BUF;
+    void *_realloc = NULL;
+    if ((_realloc = realloc(buf, max_len)) == NULL) {
+      cerr << "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len << " bytes" << std::endl;
+      goto done_free;
+    } else {
+      buf = (char *)_realloc;
+    }
+  }
+
+  pos = len;
+  if (len)
+    pos--; // squash null termination
+  strcpy(buf + pos, p);
+  len = pos + strlen(p) + 1;
+done_free:
+  if (!p_on_stack)
+    free(p);
+}
+
+void RGWFormatter_Plain::dump_value_int(const char *name, const char *fmt, ...)
+{
+  char buf[LARGE_SIZE];
+  va_list ap;
+
+  if (!min_stack_level)
+    min_stack_level = stack.size();
+
+  struct plain_stack_entry& entry = stack.back();
+  bool should_print = ((stack.size() == min_stack_level && !entry.size) || use_kv);
+
+  entry.size++;
+
+  if (!should_print)
+    return;
+
+  va_start(ap, fmt);
+  vsnprintf(buf, LARGE_SIZE, fmt, ap);
+  va_end(ap);
+
+  const char *eol;
+  if (wrote_something) {
+    eol = "\n";
+  } else
+    eol = "";
+  wrote_something = true;
+
+  if (use_kv && !entry.is_array)
+    write_data("%s%s: %s", eol, name, buf);
+  else
+    write_data("%s%s", eol, buf);
+
+}
+
+
+/* An utility class that serves as a mean to access the protected static
+ * methods of XMLFormatter. */
+class HTMLHelper : public XMLFormatter {
+public:
+  static std::string escape(const std::string& unescaped_str) {
+    return escape_xml_str(unescaped_str.c_str());
+  }
+};
+
+void RGWSwiftWebsiteListingFormatter::generate_header(
+  const std::string& dir_path,
+  const std::string& css_path)
+{
+  ss << R"(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 )"
+     << R"(Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">)";
+
+  ss << "<html><head><title>Listing of " << HTMLHelper::escape(dir_path)
+     << "</title>";
+
+  if (! css_path.empty()) {
+    ss << boost::format(R"(<link rel="stylesheet" type="text/css" href="%s" />)")
+                                % url_encode(css_path);
+  } else {
+    ss << R"(<style type="text/css">)"
+       << R"(h1 {font-size: 1em; font-weight: bold;})"
+       << R"(th {text-align: left; padding: 0px 1em 0px 1em;})"
+       << R"(td {padding: 0px 1em 0px 1em;})"
+       << R"(a {text-decoration: none;})"
+       << R"(</style>)";
+  }
+
+  ss << "</head><body>";
+
+  ss << R"(<h1 id="title">Listing of )" << HTMLHelper::escape(dir_path) << "</h1>"
+     << R"(<table id="listing">)"
+     << R"(<tr id="heading">)"
+     << R"(<th class="colname">Name</th>)"
+     << R"(<th class="colsize">Size</th>)"
+     << R"(<th class="coldate">Date</th>)"
+     << R"(</tr>)";
+
+  if (! prefix.empty()) {
+    ss << R"(<tr id="parent" class="item">)"
+       << R"(<td class="colname"><a href="../">../</a></td>)"
+       << R"(<td class="colsize">&nbsp;</td>)"
+       << R"(<td class="coldate">&nbsp;</td>)"
+       << R"(</tr>)";
+  }
+}
+
+void RGWSwiftWebsiteListingFormatter::generate_footer()
+{
+  ss << R"(</table></body></html>)";
+}
+
+std::string RGWSwiftWebsiteListingFormatter::format_name(
+  const std::string& item_name) const
+{
+  return item_name.substr(prefix.length());
+}
+
+void RGWSwiftWebsiteListingFormatter::dump_object(const rgw_bucket_dir_entry& objent)
+{
+  const auto name = format_name(objent.key.name);
+  ss << boost::format(R"(<tr class="item %s">)")
+                                % "default"
+     << boost::format(R"(<td class="colname"><a href="%s">%s</a></td>)")
+                                % url_encode(name)
+                                % HTMLHelper::escape(name)
+     << boost::format(R"(<td class="colsize">%lld</td>)") % objent.meta.size
+     << boost::format(R"(<td class="coldate">%s</td>)")
+                                % dump_time_to_str(objent.meta.mtime)
+     << R"(</tr>)";
+}
+
+void RGWSwiftWebsiteListingFormatter::dump_subdir(const std::string& name)
+{
+  const auto fname = format_name(name);
+  ss << R"(<tr class="item subdir">)"
+     << boost::format(R"(<td class="colname"><a href="%s">%s</a></td>)")
+                                % url_encode(fname)
+                                % HTMLHelper::escape(fname)
+     << R"(<td class="colsize">&nbsp;</td>)"
+     << R"(<td class="coldate">&nbsp;</td>)"
+     << R"(</tr>)";
+}