1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include <boost/format.hpp>
17 #include "common/escape.h"
18 #include "common/Formatter.h"
19 #include "rgw/rgw_common.h"
20 #include "rgw/rgw_formats.h"
21 #include "rgw/rgw_rest.h"
23 #define LARGE_SIZE 8192
25 #define dout_subsys ceph_subsys_rgw
27 RGWFormatter_Plain::RGWFormatter_Plain(const bool ukv
)
32 RGWFormatter_Plain::~RGWFormatter_Plain()
37 void RGWFormatter_Plain::flush(ostream
& os
)
50 void RGWFormatter_Plain::reset_buf()
58 void RGWFormatter_Plain::reset()
65 void RGWFormatter_Plain::open_array_section(const char *name
)
67 struct plain_stack_entry new_entry
;
68 new_entry
.is_array
= true;
71 if (use_kv
&& min_stack_level
> 0 && !stack
.empty()) {
72 struct plain_stack_entry
& entry
= stack
.back();
75 dump_format(name
, "");
78 stack
.push_back(new_entry
);
81 void RGWFormatter_Plain::open_array_section_in_ns(const char *name
, const char *ns
)
84 oss
<< name
<< " " << ns
;
85 open_array_section(oss
.str().c_str());
88 void RGWFormatter_Plain::open_object_section(const char *name
)
90 struct plain_stack_entry new_entry
;
91 new_entry
.is_array
= false;
94 if (use_kv
&& min_stack_level
> 0)
95 dump_format(name
, "");
97 stack
.push_back(new_entry
);
100 void RGWFormatter_Plain::open_object_section_in_ns(const char *name
,
104 oss
<< name
<< " " << ns
;
105 open_object_section(oss
.str().c_str());
108 void RGWFormatter_Plain::close_section()
113 void RGWFormatter_Plain::dump_unsigned(const char *name
, uint64_t u
)
115 dump_value_int(name
, "%" PRIu64
, u
);
118 void RGWFormatter_Plain::dump_int(const char *name
, int64_t u
)
120 dump_value_int(name
, "%" PRId64
, u
);
123 void RGWFormatter_Plain::dump_float(const char *name
, double d
)
125 dump_value_int(name
, "%f", d
);
128 void RGWFormatter_Plain::dump_string(const char *name
, boost::string_view s
)
130 dump_format(name
, "%s", s
.data());
133 std::ostream
& RGWFormatter_Plain::dump_stream(const char *name
)
135 // TODO: implement this!
139 void RGWFormatter_Plain::dump_format_va(const char *name
, const char *ns
, bool quoted
, const char *fmt
, va_list ap
)
141 char buf
[LARGE_SIZE
];
143 struct plain_stack_entry
& entry
= stack
.back();
145 if (!min_stack_level
)
146 min_stack_level
= stack
.size();
148 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
155 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
158 if (wrote_something
) {
159 if (use_kv
&& entry
.is_array
&& entry
.size
> 1)
165 wrote_something
= true;
167 if (use_kv
&& !entry
.is_array
)
168 write_data("%s%s: %s", eol
, name
, buf
);
170 write_data("%s%s", eol
, buf
);
173 int RGWFormatter_Plain::get_len() const
175 // don't include null termination in length
176 return (len
? len
- 1 : 0);
179 void RGWFormatter_Plain::write_raw_data(const char *data
)
181 write_data("%s", data
);
184 void RGWFormatter_Plain::write_data(const char *fmt
, ...)
186 #define LARGE_ENOUGH_LEN 128
187 int n
, size
= LARGE_ENOUGH_LEN
;
199 n
= vsnprintf(p
, size
, fmt
, ap
);
202 if (n
> -1 && n
< size
)
204 /* Else try again with more space. */
205 if (n
> -1) /* glibc 2.1 */
206 size
= n
+1; /* precisely what is needed */
208 size
*= 2; /* twice the old size */
210 np
= (char *)malloc(size
+ 8);
212 np
= (char *)realloc(p
, size
+ 8);
219 #define LARGE_ENOUGH_BUF 4096
221 max_len
= max(LARGE_ENOUGH_BUF
, size
);
222 buf
= (char *)malloc(max_len
);
224 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
229 if (len
+ size
> max_len
) {
230 max_len
= len
+ size
+ LARGE_ENOUGH_BUF
;
231 void *_realloc
= NULL
;
232 if ((_realloc
= realloc(buf
, max_len
)) == NULL
) {
233 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
236 buf
= (char *)_realloc
;
242 pos
--; // squash null termination
243 strcpy(buf
+ pos
, p
);
244 len
= pos
+ strlen(p
) + 1;
250 void RGWFormatter_Plain::dump_value_int(const char *name
, const char *fmt
, ...)
252 char buf
[LARGE_SIZE
];
255 if (!min_stack_level
)
256 min_stack_level
= stack
.size();
258 struct plain_stack_entry
& entry
= stack
.back();
259 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
267 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
271 if (wrote_something
) {
275 wrote_something
= true;
277 if (use_kv
&& !entry
.is_array
)
278 write_data("%s%s: %s", eol
, name
, buf
);
280 write_data("%s%s", eol
, buf
);
285 /* An utility class that serves as a mean to access the protected static
286 * methods of XMLFormatter. */
287 class HTMLHelper
: public XMLFormatter
{
289 static std::string
escape(const std::string
& unescaped_str
) {
290 return escape_xml_str(unescaped_str
.c_str());
294 void RGWSwiftWebsiteListingFormatter::generate_header(
295 const std::string
& dir_path
,
296 const std::string
& css_path
)
298 ss
<< R
"(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 )"
299 << R
"(Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">)";
301 ss << "<html
><head
><title
>Listing of
" << HTMLHelper::escape(dir_path)
304 if (! css_path.empty()) {
305 ss << boost::format(R"(<link rel
="stylesheet" type
="text/css" href
="%s" />)")
306 % url_encode(css_path);
308 ss << R"(<style type
="text/css">)"
309 << R"(h1
{font
-size
: 1em
; font
-weight
: bold
;})"
310 << R"(th
{text
-align
: left
; padding
: 0px
1em
0px
1em
;})"
311 << R"(td
{padding
: 0px
1em
0px
1em
;})"
312 << R"(a
{text
-decoration
: none
;})"
316 ss << "</head
><body
>";
318 ss << R"(<h1 id
="title">Listing of
)" << HTMLHelper::escape(dir_path) << "</h1
>"
319 << R"(<table id
="listing">)"
320 << R"(<tr id
="heading">)"
321 << R"(<th
class="colname">Name
</th
>)"
322 << R"(<th
class="colsize">Size
</th
>)"
323 << R"(<th
class="coldate">Date
</th
>)"
326 if (! prefix.empty()) {
327 ss << R"(<tr id
="parent" class="item">)"
328 << R"(<td
class="colname"><a href
="../">../</a
></td
>)"
329 << R"(<td
class="colsize"> 
;</td
>)"
330 << R"(<td
class="coldate"> 
;</td
>)"
335 void RGWSwiftWebsiteListingFormatter::generate_footer()
337 ss << R"(</table
></body
></html
>)";
340 std::string RGWSwiftWebsiteListingFormatter::format_name(
341 const std::string& item_name) const
343 return item_name.substr(prefix.length());
346 void RGWSwiftWebsiteListingFormatter::dump_object(const rgw_bucket_dir_entry& objent)
348 const auto name = format_name(objent.key.name);
349 ss << boost::format(R"(<tr
class="item %s">)")
351 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
353 % HTMLHelper::escape(name)
354 << boost::format(R"(<td
class="colsize">%lld
</td
>)") % objent.meta.size
355 << boost::format(R"(<td
class="coldate">%s
</td
>)")
356 % dump_time_to_str(objent.meta.mtime)
360 void RGWSwiftWebsiteListingFormatter::dump_subdir(const std::string& name)
362 const auto fname = format_name(name);
363 ss << R"(<tr
class="item subdir">)"
364 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
366 % HTMLHelper::escape(fname)
367 << R"(<td
class="colsize"> 
;</td
>)"
368 << R"(<td
class="coldate"> 
;</td
>)"