]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae FG |
3 | |
4 | #include <string.h> | |
5 | ||
6 | #include <iostream> | |
7 | #include <map> | |
8 | ||
9 | #include <expat.h> | |
10 | ||
11 | #include "include/types.h" | |
11fdf7f2 | 12 | #include "include/utime.h" |
7c673cae | 13 | |
7c673cae FG |
14 | #include "rgw_xml.h" |
15 | ||
20effc67 TL |
16 | using namespace std; |
17 | ||
7c673cae FG |
18 | XMLObjIter:: |
19 | XMLObjIter() | |
20 | { | |
21 | } | |
22 | ||
23 | XMLObjIter:: | |
24 | ~XMLObjIter() | |
25 | { | |
26 | } | |
27 | ||
28 | void XMLObjIter:: | |
29 | set(const XMLObjIter::map_iter_t &_cur, const XMLObjIter::map_iter_t &_end) | |
30 | { | |
31 | cur = _cur; | |
32 | end = _end; | |
33 | } | |
34 | ||
35 | XMLObj *XMLObjIter:: | |
36 | get_next() | |
37 | { | |
38 | XMLObj *obj = NULL; | |
39 | if (cur != end) { | |
40 | obj = cur->second; | |
41 | ++cur; | |
42 | } | |
43 | return obj; | |
44 | } | |
45 | ||
11fdf7f2 TL |
46 | bool XMLObjIter::get_name(std::string& name) const |
47 | { | |
48 | if (cur == end) { | |
49 | return false; | |
50 | } | |
51 | ||
52 | name = cur->first; | |
53 | return true; | |
54 | } | |
55 | ||
7c673cae FG |
56 | ostream& operator<<(ostream &out, const XMLObj &obj) { |
57 | out << obj.obj_type << ": " << obj.data; | |
58 | return out; | |
59 | } | |
60 | ||
61 | XMLObj:: | |
62 | ~XMLObj() | |
63 | { | |
64 | } | |
65 | ||
66 | bool XMLObj:: | |
67 | xml_start(XMLObj *parent, const char *el, const char **attr) | |
68 | { | |
69 | this->parent = parent; | |
70 | obj_type = el; | |
71 | for (int i = 0; attr[i]; i += 2) { | |
11fdf7f2 | 72 | attr_map[attr[i]] = std::string(attr[i + 1]); |
7c673cae FG |
73 | } |
74 | return true; | |
75 | } | |
76 | ||
77 | bool XMLObj:: | |
78 | xml_end(const char *el) | |
79 | { | |
80 | return true; | |
81 | } | |
82 | ||
83 | void XMLObj:: | |
84 | xml_handle_data(const char *s, int len) | |
85 | { | |
86 | data.append(s, len); | |
87 | } | |
88 | ||
11fdf7f2 TL |
89 | const std::string& XMLObj:: |
90 | XMLObj::get_data() const | |
7c673cae FG |
91 | { |
92 | return data; | |
93 | } | |
94 | ||
11fdf7f2 TL |
95 | const std::string& XMLObj:: |
96 | XMLObj::get_obj_type() const | |
97 | { | |
98 | return obj_type; | |
99 | } | |
100 | ||
7c673cae FG |
101 | XMLObj *XMLObj:: |
102 | XMLObj::get_parent() | |
103 | { | |
104 | return parent; | |
105 | } | |
106 | ||
107 | void XMLObj:: | |
11fdf7f2 | 108 | add_child(const std::string& el, XMLObj *obj) |
7c673cae | 109 | { |
11fdf7f2 | 110 | children.insert(std::pair<std::string, XMLObj *>(el, obj)); |
7c673cae FG |
111 | } |
112 | ||
113 | bool XMLObj:: | |
11fdf7f2 | 114 | get_attr(const std::string& name, std::string& attr) const |
7c673cae | 115 | { |
11fdf7f2 | 116 | const std::map<std::string, std::string>::const_iterator iter = attr_map.find(name); |
7c673cae FG |
117 | if (iter == attr_map.end()) |
118 | return false; | |
119 | attr = iter->second; | |
120 | return true; | |
121 | } | |
122 | ||
123 | XMLObjIter XMLObj:: | |
11fdf7f2 | 124 | find(const std::string& name) |
7c673cae FG |
125 | { |
126 | XMLObjIter iter; | |
11fdf7f2 TL |
127 | const XMLObjIter::const_map_iter_t first = children.find(name); |
128 | XMLObjIter::const_map_iter_t last; | |
7c673cae FG |
129 | if (first != children.end()) { |
130 | last = children.upper_bound(name); | |
131 | }else | |
132 | last = children.end(); | |
133 | iter.set(first, last); | |
134 | return iter; | |
135 | } | |
136 | ||
11fdf7f2 | 137 | XMLObjIter XMLObj::find_first() |
7c673cae FG |
138 | { |
139 | XMLObjIter iter; | |
11fdf7f2 TL |
140 | const XMLObjIter::const_map_iter_t first = children.begin(); |
141 | const XMLObjIter::const_map_iter_t last = children.end(); | |
142 | iter.set(first, last); | |
143 | return iter; | |
7c673cae | 144 | } |
7c673cae | 145 | |
11fdf7f2 TL |
146 | XMLObj *XMLObj:: |
147 | find_first(const std::string& name) | |
148 | { | |
149 | const XMLObjIter::const_map_iter_t first = children.find(name); | |
150 | if (first != children.end()) | |
151 | return first->second; | |
152 | return nullptr; | |
7c673cae FG |
153 | } |
154 | ||
155 | RGWXMLParser:: | |
11fdf7f2 | 156 | RGWXMLParser() : buf(nullptr), buf_len(0), cur_obj(nullptr), success(true), init_called(false) |
7c673cae | 157 | { |
11fdf7f2 | 158 | p = XML_ParserCreate(nullptr); |
7c673cae FG |
159 | } |
160 | ||
161 | RGWXMLParser:: | |
162 | ~RGWXMLParser() | |
163 | { | |
164 | XML_ParserFree(p); | |
165 | ||
166 | free(buf); | |
11fdf7f2 | 167 | std::list<XMLObj *>::const_iterator iter; |
7c673cae FG |
168 | for (iter = allocated_objs.begin(); iter != allocated_objs.end(); ++iter) { |
169 | XMLObj *obj = *iter; | |
170 | delete obj; | |
171 | } | |
172 | } | |
173 | ||
11fdf7f2 TL |
174 | void RGWXMLParser::call_xml_start(void* user_data, const char *el, const char **attr) { |
175 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
176 | XMLObj * obj = handler->alloc_obj(el); | |
7c673cae | 177 | if (!obj) { |
11fdf7f2 TL |
178 | handler->unallocated_objs.push_back(XMLObj()); |
179 | obj = &handler->unallocated_objs.back(); | |
7c673cae | 180 | } else { |
11fdf7f2 | 181 | handler->allocated_objs.push_back(obj); |
7c673cae | 182 | } |
11fdf7f2 TL |
183 | if (!obj->xml_start(handler->cur_obj, el, attr)) { |
184 | handler->success = false; | |
185 | return; | |
186 | } | |
187 | if (handler->cur_obj) { | |
188 | handler->cur_obj->add_child(el, obj); | |
7c673cae | 189 | } else { |
11fdf7f2 | 190 | handler->children.insert(std::pair<std::string, XMLObj *>(el, obj)); |
7c673cae | 191 | } |
11fdf7f2 | 192 | handler->cur_obj = obj; |
7c673cae | 193 | |
11fdf7f2 | 194 | handler->objs.push_back(obj); |
7c673cae FG |
195 | } |
196 | ||
11fdf7f2 TL |
197 | void RGWXMLParser::call_xml_end(void* user_data, const char *el) { |
198 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
199 | XMLObj *parent_obj = handler->cur_obj->get_parent(); | |
200 | if (!handler->cur_obj->xml_end(el)) { | |
201 | handler->success = false; | |
202 | return; | |
203 | } | |
204 | handler->cur_obj = parent_obj; | |
7c673cae FG |
205 | } |
206 | ||
11fdf7f2 | 207 | void RGWXMLParser::call_xml_handle_data(void* user_data, const char *s, int len) |
7c673cae | 208 | { |
11fdf7f2 TL |
209 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); |
210 | handler->cur_obj->xml_handle_data(s, len); | |
7c673cae FG |
211 | } |
212 | ||
7c673cae FG |
213 | bool RGWXMLParser::init() |
214 | { | |
215 | if (!p) { | |
216 | return false; | |
217 | } | |
11fdf7f2 TL |
218 | init_called = true; |
219 | XML_SetElementHandler(p, RGWXMLParser::call_xml_start, RGWXMLParser::call_xml_end); | |
220 | XML_SetCharacterDataHandler(p, RGWXMLParser::call_xml_handle_data); | |
7c673cae FG |
221 | XML_SetUserData(p, (void *)this); |
222 | return true; | |
223 | } | |
224 | ||
225 | bool RGWXMLParser::parse(const char *_buf, int len, int done) | |
226 | { | |
11fdf7f2 | 227 | ceph_assert(init_called); |
7c673cae FG |
228 | int pos = buf_len; |
229 | char *tmp_buf; | |
230 | tmp_buf = (char *)realloc(buf, buf_len + len); | |
231 | if (tmp_buf == NULL){ | |
232 | free(buf); | |
233 | buf = NULL; | |
234 | return false; | |
235 | } else { | |
236 | buf = tmp_buf; | |
237 | } | |
238 | ||
239 | memcpy(&buf[buf_len], _buf, len); | |
240 | buf_len += len; | |
241 | ||
242 | success = true; | |
243 | if (!XML_Parse(p, &buf[pos], len, done)) { | |
244 | fprintf(stderr, "Parse error at line %d:\n%s\n", | |
245 | (int)XML_GetCurrentLineNumber(p), | |
246 | XML_ErrorString(XML_GetErrorCode(p))); | |
247 | success = false; | |
248 | } | |
249 | ||
250 | return success; | |
251 | } | |
252 | ||
253 | void decode_xml_obj(unsigned long& val, XMLObj *obj) | |
254 | { | |
11fdf7f2 | 255 | auto& s = obj->get_data(); |
7c673cae FG |
256 | const char *start = s.c_str(); |
257 | char *p; | |
258 | ||
259 | errno = 0; | |
260 | val = strtoul(start, &p, 10); | |
261 | ||
262 | /* Check for various possible errors */ | |
263 | ||
264 | if ((errno == ERANGE && val == ULONG_MAX) || | |
265 | (errno != 0 && val == 0)) { | |
266 | throw RGWXMLDecoder::err("failed to number"); | |
267 | } | |
268 | ||
269 | if (p == start) { | |
270 | throw RGWXMLDecoder::err("failed to parse number"); | |
271 | } | |
272 | ||
273 | while (*p != '\0') { | |
274 | if (!isspace(*p)) { | |
275 | throw RGWXMLDecoder::err("failed to parse number"); | |
276 | } | |
277 | p++; | |
278 | } | |
279 | } | |
280 | ||
281 | ||
282 | void decode_xml_obj(long& val, XMLObj *obj) | |
283 | { | |
11fdf7f2 | 284 | const std::string s = obj->get_data(); |
7c673cae FG |
285 | const char *start = s.c_str(); |
286 | char *p; | |
287 | ||
288 | errno = 0; | |
289 | val = strtol(start, &p, 10); | |
290 | ||
291 | /* Check for various possible errors */ | |
292 | ||
293 | if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || | |
294 | (errno != 0 && val == 0)) { | |
295 | throw RGWXMLDecoder::err("failed to parse number"); | |
296 | } | |
297 | ||
298 | if (p == start) { | |
299 | throw RGWXMLDecoder::err("failed to parse number"); | |
300 | } | |
301 | ||
302 | while (*p != '\0') { | |
303 | if (!isspace(*p)) { | |
304 | throw RGWXMLDecoder::err("failed to parse number"); | |
305 | } | |
306 | p++; | |
307 | } | |
308 | } | |
309 | ||
310 | void decode_xml_obj(long long& val, XMLObj *obj) | |
311 | { | |
11fdf7f2 | 312 | const std::string s = obj->get_data(); |
7c673cae FG |
313 | const char *start = s.c_str(); |
314 | char *p; | |
315 | ||
316 | errno = 0; | |
317 | val = strtoll(start, &p, 10); | |
318 | ||
319 | /* Check for various possible errors */ | |
320 | ||
321 | if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) || | |
322 | (errno != 0 && val == 0)) { | |
323 | throw RGWXMLDecoder::err("failed to parse number"); | |
324 | } | |
325 | ||
326 | if (p == start) { | |
327 | throw RGWXMLDecoder::err("failed to parse number"); | |
328 | } | |
329 | ||
330 | while (*p != '\0') { | |
331 | if (!isspace(*p)) { | |
332 | throw RGWXMLDecoder::err("failed to parse number"); | |
333 | } | |
334 | p++; | |
335 | } | |
336 | } | |
337 | ||
338 | void decode_xml_obj(unsigned long long& val, XMLObj *obj) | |
339 | { | |
11fdf7f2 | 340 | const std::string s = obj->get_data(); |
7c673cae FG |
341 | const char *start = s.c_str(); |
342 | char *p; | |
343 | ||
344 | errno = 0; | |
345 | val = strtoull(start, &p, 10); | |
346 | ||
347 | /* Check for various possible errors */ | |
348 | ||
349 | if ((errno == ERANGE && val == ULLONG_MAX) || | |
350 | (errno != 0 && val == 0)) { | |
11fdf7f2 | 351 | throw RGWXMLDecoder::err("failed to parse number"); |
7c673cae FG |
352 | } |
353 | ||
354 | if (p == start) { | |
355 | throw RGWXMLDecoder::err("failed to parse number"); | |
356 | } | |
357 | ||
358 | while (*p != '\0') { | |
359 | if (!isspace(*p)) { | |
360 | throw RGWXMLDecoder::err("failed to parse number"); | |
361 | } | |
362 | p++; | |
363 | } | |
364 | } | |
365 | ||
366 | void decode_xml_obj(int& val, XMLObj *obj) | |
367 | { | |
368 | long l; | |
369 | decode_xml_obj(l, obj); | |
370 | #if LONG_MAX > INT_MAX | |
371 | if (l > INT_MAX || l < INT_MIN) { | |
372 | throw RGWXMLDecoder::err("integer out of range"); | |
373 | } | |
374 | #endif | |
375 | ||
376 | val = (int)l; | |
377 | } | |
378 | ||
379 | void decode_xml_obj(unsigned& val, XMLObj *obj) | |
380 | { | |
381 | unsigned long l; | |
382 | decode_xml_obj(l, obj); | |
383 | #if ULONG_MAX > UINT_MAX | |
384 | if (l > UINT_MAX) { | |
385 | throw RGWXMLDecoder::err("unsigned integer out of range"); | |
386 | } | |
387 | #endif | |
388 | ||
389 | val = (unsigned)l; | |
390 | } | |
391 | ||
392 | void decode_xml_obj(bool& val, XMLObj *obj) | |
393 | { | |
11fdf7f2 TL |
394 | const std::string s = obj->get_data(); |
395 | if (strncasecmp(s.c_str(), "true", 8) == 0) { | |
7c673cae FG |
396 | val = true; |
397 | return; | |
398 | } | |
11fdf7f2 | 399 | if (strncasecmp(s.c_str(), "false", 8) == 0) { |
7c673cae FG |
400 | val = false; |
401 | return; | |
402 | } | |
403 | int i; | |
404 | decode_xml_obj(i, obj); | |
405 | val = (bool)i; | |
406 | } | |
407 | ||
408 | void decode_xml_obj(bufferlist& val, XMLObj *obj) | |
409 | { | |
11fdf7f2 | 410 | const std::string s = obj->get_data(); |
7c673cae FG |
411 | |
412 | bufferlist bl; | |
413 | bl.append(s.c_str(), s.size()); | |
414 | try { | |
415 | val.decode_base64(bl); | |
416 | } catch (buffer::error& err) { | |
417 | throw RGWXMLDecoder::err("failed to decode base64"); | |
418 | } | |
419 | } | |
420 | ||
421 | void decode_xml_obj(utime_t& val, XMLObj *obj) | |
422 | { | |
11fdf7f2 | 423 | const std::string s = obj->get_data(); |
7c673cae FG |
424 | uint64_t epoch; |
425 | uint64_t nsec; | |
426 | int r = utime_t::parse_date(s, &epoch, &nsec); | |
427 | if (r == 0) { | |
428 | val = utime_t(epoch, nsec); | |
429 | } else { | |
430 | throw RGWXMLDecoder::err("failed to decode utime_t"); | |
431 | } | |
432 | } | |
433 | ||
434 | void encode_xml(const char *name, const string& val, Formatter *f) | |
435 | { | |
436 | f->dump_string(name, val); | |
437 | } | |
438 | ||
439 | void encode_xml(const char *name, const char *val, Formatter *f) | |
440 | { | |
441 | f->dump_string(name, val); | |
442 | } | |
443 | ||
444 | void encode_xml(const char *name, bool val, Formatter *f) | |
445 | { | |
11fdf7f2 | 446 | std::string s; |
7c673cae FG |
447 | if (val) |
448 | s = "True"; | |
449 | else | |
450 | s = "False"; | |
451 | ||
452 | f->dump_string(name, s); | |
453 | } | |
454 | ||
455 | void encode_xml(const char *name, int val, Formatter *f) | |
456 | { | |
457 | f->dump_int(name, val); | |
458 | } | |
459 | ||
460 | void encode_xml(const char *name, long val, Formatter *f) | |
461 | { | |
462 | f->dump_int(name, val); | |
463 | } | |
464 | ||
465 | void encode_xml(const char *name, unsigned val, Formatter *f) | |
466 | { | |
467 | f->dump_unsigned(name, val); | |
468 | } | |
469 | ||
470 | void encode_xml(const char *name, unsigned long val, Formatter *f) | |
471 | { | |
472 | f->dump_unsigned(name, val); | |
473 | } | |
474 | ||
475 | void encode_xml(const char *name, unsigned long long val, Formatter *f) | |
476 | { | |
477 | f->dump_unsigned(name, val); | |
478 | } | |
479 | ||
480 | void encode_xml(const char *name, long long val, Formatter *f) | |
481 | { | |
482 | f->dump_int(name, val); | |
483 | } | |
484 | ||
485 | void encode_xml(const char *name, const utime_t& val, Formatter *f) | |
486 | { | |
487 | val.gmtime(f->dump_stream(name)); | |
488 | } | |
489 | ||
490 | void encode_xml(const char *name, const bufferlist& bl, Formatter *f) | |
491 | { | |
492 | /* need to copy data from bl, as it is const bufferlist */ | |
493 | bufferlist src = bl; | |
494 | ||
495 | bufferlist b64; | |
496 | src.encode_base64(b64); | |
497 | ||
11fdf7f2 | 498 | const std::string s(b64.c_str(), b64.length()); |
7c673cae FG |
499 | |
500 | encode_xml(name, s, f); | |
501 | } | |
502 |