1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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
28 RGWFormatter_Plain::RGWFormatter_Plain(const bool ukv
)
33 RGWFormatter_Plain::~RGWFormatter_Plain()
38 void RGWFormatter_Plain::flush(ostream
& os
)
51 void RGWFormatter_Plain::reset_buf()
59 void RGWFormatter_Plain::reset()
66 void RGWFormatter_Plain::open_array_section(const char *name
)
68 struct plain_stack_entry new_entry
;
69 new_entry
.is_array
= true;
72 if (use_kv
&& min_stack_level
> 0 && !stack
.empty()) {
73 struct plain_stack_entry
& entry
= stack
.back();
76 dump_format(name
, "");
79 stack
.push_back(new_entry
);
82 void RGWFormatter_Plain::open_array_section_in_ns(const char *name
, const char *ns
)
85 oss
<< name
<< " " << ns
;
86 open_array_section(oss
.str().c_str());
89 void RGWFormatter_Plain::open_object_section(const char *name
)
91 struct plain_stack_entry new_entry
;
92 new_entry
.is_array
= false;
95 if (use_kv
&& min_stack_level
> 0)
96 dump_format(name
, "");
98 stack
.push_back(new_entry
);
101 void RGWFormatter_Plain::open_object_section_in_ns(const char *name
,
105 oss
<< name
<< " " << ns
;
106 open_object_section(oss
.str().c_str());
109 void RGWFormatter_Plain::close_section()
114 void RGWFormatter_Plain::dump_unsigned(const char *name
, uint64_t u
)
116 dump_value_int(name
, "%" PRIu64
, u
);
119 void RGWFormatter_Plain::dump_int(const char *name
, int64_t u
)
121 dump_value_int(name
, "%" PRId64
, u
);
124 void RGWFormatter_Plain::dump_float(const char *name
, double d
)
126 dump_value_int(name
, "%f", d
);
129 void RGWFormatter_Plain::dump_string(const char *name
, std::string_view s
)
131 dump_format(name
, "%s", s
.data());
134 std::ostream
& RGWFormatter_Plain::dump_stream(const char *name
)
136 // TODO: implement this!
140 void RGWFormatter_Plain::dump_format_va(const char *name
, const char *ns
, bool quoted
, const char *fmt
, va_list ap
)
142 char buf
[LARGE_SIZE
];
144 struct plain_stack_entry
& entry
= stack
.back();
146 if (!min_stack_level
)
147 min_stack_level
= stack
.size();
149 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
156 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
159 if (wrote_something
) {
160 if (use_kv
&& entry
.is_array
&& entry
.size
> 1)
166 wrote_something
= true;
168 if (use_kv
&& !entry
.is_array
)
169 write_data("%s%s: %s", eol
, name
, buf
);
171 write_data("%s%s", eol
, buf
);
174 int RGWFormatter_Plain::get_len() const
176 // don't include null termination in length
177 return (len
? len
- 1 : 0);
180 void RGWFormatter_Plain::write_raw_data(const char *data
)
182 write_data("%s", data
);
185 void RGWFormatter_Plain::write_data(const char *fmt
, ...)
187 #define LARGE_ENOUGH_LEN 128
188 int n
, size
= LARGE_ENOUGH_LEN
;
200 n
= vsnprintf(p
, size
, fmt
, ap
);
203 if (n
> -1 && n
< size
)
205 /* Else try again with more space. */
206 if (n
> -1) /* glibc 2.1 */
207 size
= n
+1; /* precisely what is needed */
209 size
*= 2; /* twice the old size */
211 np
= (char *)malloc(size
+ 8);
213 np
= (char *)realloc(p
, size
+ 8);
220 #define LARGE_ENOUGH_BUF 4096
222 max_len
= std::max(LARGE_ENOUGH_BUF
, size
);
223 buf
= (char *)malloc(max_len
);
225 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
230 if (len
+ size
> max_len
) {
231 max_len
= len
+ size
+ LARGE_ENOUGH_BUF
;
232 void *_realloc
= NULL
;
233 if ((_realloc
= realloc(buf
, max_len
)) == NULL
) {
234 cerr
<< "ERROR: RGWFormatter_Plain::write_data: failed allocating " << max_len
<< " bytes" << std::endl
;
237 buf
= (char *)_realloc
;
243 pos
--; // squash null termination
244 strcpy(buf
+ pos
, p
);
245 len
= pos
+ strlen(p
) + 1;
251 void RGWFormatter_Plain::dump_value_int(const char *name
, const char *fmt
, ...)
253 char buf
[LARGE_SIZE
];
256 if (!min_stack_level
)
257 min_stack_level
= stack
.size();
259 struct plain_stack_entry
& entry
= stack
.back();
260 bool should_print
= ((stack
.size() == min_stack_level
&& !entry
.size
) || use_kv
);
268 vsnprintf(buf
, LARGE_SIZE
, fmt
, ap
);
272 if (wrote_something
) {
276 wrote_something
= true;
278 if (use_kv
&& !entry
.is_array
)
279 write_data("%s%s: %s", eol
, name
, buf
);
281 write_data("%s%s", eol
, buf
);
286 /* An utility class that serves as a mean to access the protected static
287 * methods of XMLFormatter. */
288 class HTMLHelper
: public XMLFormatter
{
290 static std::string
escape(const std::string
& unescaped_str
) {
291 int len
= escape_xml_attr_len(unescaped_str
.c_str());
292 std::string
escaped(len
, 0);
293 escape_xml_attr(unescaped_str
.c_str(), escaped
.data());
298 void RGWSwiftWebsiteListingFormatter::generate_header(
299 const std::string
& dir_path
,
300 const std::string
& css_path
)
302 ss
<< R
"(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 )"
303 << R
"(Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">)";
305 ss << "<html
><head
><title
>Listing of
" << xml_stream_escaper(dir_path)
308 if (! css_path.empty()) {
309 ss << boost::format(R"(<link rel
="stylesheet" type
="text/css" href
="%s" />)")
310 % url_encode(css_path);
312 ss << R"(<style type
="text/css">)"
313 << R"(h1
{font
-size
: 1em
; font
-weight
: bold
;})"
314 << R"(th
{text
-align
: left
; padding
: 0px
1em
0px
1em
;})"
315 << R"(td
{padding
: 0px
1em
0px
1em
;})"
316 << R"(a
{text
-decoration
: none
;})"
320 ss << "</head
><body
>";
322 ss << R"(<h1 id
="title">Listing of
)" << xml_stream_escaper(dir_path) << "</h1
>"
323 << R"(<table id
="listing">)"
324 << R"(<tr id
="heading">)"
325 << R"(<th
class="colname">Name
</th
>)"
326 << R"(<th
class="colsize">Size
</th
>)"
327 << R"(<th
class="coldate">Date
</th
>)"
330 if (! prefix.empty()) {
331 ss << R"(<tr id
="parent" class="item">)"
332 << R"(<td
class="colname"><a href
="../">../</a
></td
>)"
333 << R"(<td
class="colsize"> 
;</td
>)"
334 << R"(<td
class="coldate"> 
;</td
>)"
339 void RGWSwiftWebsiteListingFormatter::generate_footer()
341 ss << R"(</table
></body
></html
>)";
344 std::string RGWSwiftWebsiteListingFormatter::format_name(
345 const std::string& item_name) const
347 return item_name.substr(prefix.length());
350 void RGWSwiftWebsiteListingFormatter::dump_object(const rgw_bucket_dir_entry& objent)
352 const auto name = format_name(objent.key.name);
353 ss << boost::format(R"(<tr
class="item %s">)")
355 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
357 % HTMLHelper::escape(name)
358 << boost::format(R"(<td
class="colsize">%lld
</td
>)") % objent.meta.size
359 << boost::format(R"(<td
class="coldate">%s
</td
>)")
360 % dump_time_to_str(objent.meta.mtime)
364 void RGWSwiftWebsiteListingFormatter::dump_subdir(const std::string& name)
366 const auto fname = format_name(name);
367 ss << R"(<tr
class="item subdir">)"
368 << boost::format(R"(<td
class="colname"><a href
="%s">%s
</a
></td
>)")
370 % HTMLHelper::escape(fname)
371 << R"(<td
class="colsize"> 
;</td
>)"
372 << R"(<td
class="coldate"> 
;</td
>)"