1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 * Ceph - scalable distributed file system
7 * Copyright (C) 2011 New Dream Network
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
16 #include <boost/format.hpp>
18 #include "common/escape.h"
19 #include "common/Formatter.h"
20 #include "rgw/rgw_common.h"
21 #include "rgw/rgw_formats.h"
22 #include "rgw/rgw_rest.h"
24 #define LARGE_SIZE 8192
26 #define dout_subsys ceph_subsys_rgw
30 RGWFormatter_Plain::RGWFormatter_Plain(const bool ukv
)
35 RGWFormatter_Plain::~RGWFormatter_Plain()
40 void RGWFormatter_Plain::flush(ostream
& os
)
53 void RGWFormatter_Plain::reset_buf()
61 void RGWFormatter_Plain::reset()
68 void RGWFormatter_Plain::open_array_section(std::string_view name
)
70 struct plain_stack_entry new_entry
;
71 new_entry
.is_array
= true;
74 if (use_kv
&& min_stack_level
> 0 && !stack
.empty()) {
75 struct plain_stack_entry
& entry
= stack
.back();
78 dump_format(name
, "");
81 stack
.push_back(new_entry
);
84 void RGWFormatter_Plain::open_array_section_in_ns(std::string_view name
, const char *ns
)
87 oss
<< name
<< " " << ns
;
88 open_array_section(oss
.str().c_str());
91 void RGWFormatter_Plain::open_object_section(std::string_view name
)
93 struct plain_stack_entry new_entry
;
94 new_entry
.is_array
= false;
97 if (use_kv
&& min_stack_level
> 0)
98 dump_format(name
, "");
100 stack
.push_back(new_entry
);
103 void RGWFormatter_Plain::open_object_section_in_ns(std::string_view name
,
107 oss
<< name
<< " " << ns
;
108 open_object_section(oss
.str().c_str());
111 void RGWFormatter_Plain::close_section()
116 void RGWFormatter_Plain::dump_unsigned(std::string_view name
, uint64_t u
)
118 dump_value_int(name
, "%" PRIu64
, u
);
121 void RGWFormatter_Plain::dump_int(std::string_view name
, int64_t u
)
123 dump_value_int(name
, "%" PRId64
, u
);
126 void RGWFormatter_Plain::dump_float(std::string_view name
, double d
)
128 dump_value_int(name
, "%f", d
);
131 void RGWFormatter_Plain::dump_string(std::string_view name
, std::string_view s
)
133 dump_format(name
, "%.*s", s
.size(), s
.data());
136 std::ostream
& RGWFormatter_Plain::dump_stream(std::string_view name
)
138 // TODO: implement this!
142 void RGWFormatter_Plain::dump_format_va(std::string_view name
, const char *ns
, bool quoted
, const char *fmt
, va_list ap
)
144 char buf
[LARGE_SIZE
];
146 struct plain_stack_entry
& entry
= stack
.back();
148 if (!min_stack_level
)
149 min_stack_level
= stack
.size();
151 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
158 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
161 if (wrote_something
) {
162 if (use_kv
&& entry
.is_array
&& entry
.size
> 1)
168 wrote_something
= true;
170 if (use_kv
&& !entry
.is_array
)
171 write_data("%s%.*s: %s", eol
, name
.size(), name
.data(), buf
);
173 write_data("%s%s", eol
, buf
);
176 int RGWFormatter_Plain::get_len() const
178 // don't include null termination in length
179 return (len
? len
- 1 : 0);
182 void RGWFormatter_Plain::write_raw_data(const char *data
)
184 write_data("%s", data
);
187 void RGWFormatter_Plain::write_data(const char *fmt
, ...)
189 #define LARGE_ENOUGH_LEN 128
190 int n
, size
= LARGE_ENOUGH_LEN
;
202 n
= vsnprintf(p
, size
, fmt
, ap
);
205 if (n
> -1 && n
< size
)
207 /* Else try again with more space. */
208 if (n
> -1) /* glibc 2.1 */
209 size
= n
+1; /* precisely what is needed */
211 size
*= 2; /* twice the old size */
213 np
= (char *)malloc(size
+ 8);
215 np
= (char *)realloc(p
, size
+ 8);
222 #define LARGE_ENOUGH_BUF 4096
224 max_len
= std::max(LARGE_ENOUGH_BUF
, size
);
225 buf
= (char *)malloc(max_len
);
227 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
232 if (len
+ size
> max_len
) {
233 max_len
= len
+ size
+ LARGE_ENOUGH_BUF
;
234 void *_realloc
= NULL
;
235 if ((_realloc
= realloc(buf
, max_len
)) == NULL
) {
236 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
239 buf
= (char *)_realloc
;
245 pos
--; // squash null termination
246 strcpy(buf
+ pos
, p
);
247 len
= pos
+ strlen(p
) + 1;
253 void RGWFormatter_Plain::dump_value_int(std::string_view name
, const char *fmt
, ...)
255 char buf
[LARGE_SIZE
];
258 if (!min_stack_level
)
259 min_stack_level
= stack
.size();
261 struct plain_stack_entry
& entry
= stack
.back();
262 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
270 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
274 if (wrote_something
) {
278 wrote_something
= true;
280 if (use_kv
&& !entry
.is_array
)
281 write_data("%s%.*s: %s", eol
, name
.size(), name
.data(), buf
);
283 write_data("%s%s", eol
, buf
);
288 /* An utility class that serves as a mean to access the protected static
289 * methods of XMLFormatter. */
290 class HTMLHelper
: public XMLFormatter
{
292 static std::string
escape(const std::string
& unescaped_str
) {
293 int len
= escape_xml_attr_len(unescaped_str
.c_str());
294 std::string
escaped(len
, 0);
295 escape_xml_attr(unescaped_str
.c_str(), escaped
.data());
300 void RGWSwiftWebsiteListingFormatter::generate_header(
301 const std::string
& dir_path
,
302 const std::string
& css_path
)
304 ss
<< R
"(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 )"
305 << R
"(Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">)";
307 ss << "<html
><head
><title
>Listing of
" << xml_stream_escaper(dir_path)
310 if (! css_path.empty()) {
311 ss << boost::format(R"(<link rel
="stylesheet" type
="text/css" href
="%s" />)")
312 % url_encode(css_path);
314 ss << R"(<style type
="text/css">)"
315 << R"(h1
{font
-size
: 1em
; font
-weight
: bold
;})"
316 << R"(th
{text
-align
: left
; padding
: 0px
1em
0px
1em
;})"
317 << R"(td
{padding
: 0px
1em
0px
1em
;})"
318 << R"(a
{text
-decoration
: none
;})"
322 ss << "</head
><body
>";
324 ss << R"(<h1 id
="title">Listing of
)" << xml_stream_escaper(dir_path) << "</h1
>"
325 << R"(<table id
="listing">)"
326 << R"(<tr id
="heading">)"
327 << R"(<th
class="colname">Name
</th
>)"
328 << R"(<th
class="colsize">Size
</th
>)"
329 << R"(<th
class="coldate">Date
</th
>)"
332 if (! prefix.empty()) {
333 ss << R"(<tr id
="parent" class="item">)"
334 << R"(<td
class="colname"><a href
="../">../</a
></td
>)"
335 << R"(<td
class="colsize"> 
;</td
>)"
336 << R"(<td
class="coldate"> 
;</td
>)"
341 void RGWSwiftWebsiteListingFormatter::generate_footer()
343 ss << R"(</table
></body
></html
>)";
346 std::string RGWSwiftWebsiteListingFormatter::format_name(
347 const std::string& item_name) const
349 return item_name.substr(prefix.length());
352 void RGWSwiftWebsiteListingFormatter::dump_object(const rgw_bucket_dir_entry& objent)
354 const auto name = format_name(objent.key.name);
355 ss << boost::format(R"(<tr
class="item %s">)")
357 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
359 % HTMLHelper::escape(name)
360 << boost::format(R"(<td
class="colsize">%lld
</td
>)") % objent.meta.size
361 << boost::format(R"(<td
class="coldate">%s
</td
>)")
362 % dump_time_to_str(objent.meta.mtime)
366 void RGWSwiftWebsiteListingFormatter::dump_subdir(const std::string& name)
368 const auto fname = format_name(name);
369 ss << R"(<tr
class="item subdir">)"
370 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
372 % HTMLHelper::escape(fname)
373 << R"(<td
class="colsize"> 
;</td
>)"
374 << R"(<td
class="coldate"> 
;</td
>)"