]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: rework lifecycle parsing
authorYehuda Sadeh <yehuda@redhat.com>
Fri, 2 Nov 2018 00:54:42 +0000 (17:54 -0700)
committerYehuda Sadeh <yehuda@redhat.com>
Fri, 4 Jan 2019 03:00:23 +0000 (19:00 -0800)
Use new style xml parsing, instead of inheriting from XMLParser.

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/common/Formatter.h
src/rgw/rgw_lc.h
src/rgw/rgw_lc_s3.cc
src/rgw/rgw_lc_s3.h
src/rgw/rgw_op.cc
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_tag_s3.cc
src/rgw/rgw_tag_s3.h
src/rgw/rgw_xml.cc
src/rgw/rgw_xml.h

index 9d984c11f87512e4bc4ddcafd9b7d06339e5e65d..266f00a643641d59d214f248de89c87731471f0e 100644 (file)
@@ -30,6 +30,9 @@ namespace ceph {
       ObjectSection(Formatter& f, const char *name) : formatter(f) {
         formatter.open_object_section(name);
       }
+      ObjectSection(Formatter& f, const char *name, const char *ns) : formatter(f) {
+        formatter.open_object_section_in_ns(name, ns);
+      }
       ~ObjectSection() {
         formatter.close_section();
       }
@@ -41,6 +44,9 @@ namespace ceph {
       ArraySection(Formatter& f, const char *name) : formatter(f) {
         formatter.open_array_section(name);
       }
+      ArraySection(Formatter& f, const char *name, const char *ns) : formatter(f) {
+        formatter.open_array_section_in_ns(name, ns);
+      }
       ~ArraySection() {
         formatter.close_section();
       }
index bbe855f74cb7958fd05c861b6c9a3ab048d6a3e0..21fd5d5b15165965fc2e2ce509114d7d07811fd4 100644 (file)
@@ -36,7 +36,7 @@ typedef enum {
   lc_processing,
   lc_failed,
   lc_complete,
-}LC_BUCKET_STATUS;
+} LC_BUCKET_STATUS;
 
 class LCExpiration
 {
@@ -46,7 +46,7 @@ protected:
   string date;
 public:
   LCExpiration() {}
-  ~LCExpiration() {}
+  LCExpiration(const string& _days, const string& _date) : days(_days), date(_date) {}
 
   void encode(bufferlist& bl) const {
     ENCODE_START(3, 2, bl);
@@ -92,7 +92,7 @@ public:
     return true;
   }
 };
-WRITE_CLASS_ENCODER(LCExpiration);
+WRITE_CLASS_ENCODER(LCExpiration)
 
 class LCTransition
 {
@@ -153,7 +153,7 @@ public:
   }
   void dump(Formatter *f) const;
 };
-WRITE_CLASS_ENCODER(LCTransition);
+WRITE_CLASS_ENCODER(LCTransition)
 
 class LCFilter
 {
@@ -209,7 +209,7 @@ class LCFilter
   }
   void dump(Formatter *f) const;
 };
-WRITE_CLASS_ENCODER(LCFilter);
+WRITE_CLASS_ENCODER(LCFilter)
 
 
 
index c78851a359f5131af02ba4e4871042b68ea755b9..c175e2ef54fa029d80d48750480a76384f138260 100644 (file)
@@ -27,77 +27,100 @@ static bool check_date(const string& _date)
   return true;
 }
 
-bool LCExpiration_S3::xml_end(const char * el) {
-  LCDays_S3 *lc_days = static_cast<LCDays_S3 *>(find_first("Days"));
-  LCDeleteMarker_S3 *lc_dm = static_cast<LCDeleteMarker_S3 *>(find_first("ExpiredObjectDeleteMarker"));
-  LCDate_S3 *lc_date = static_cast<LCDate_S3 *>(find_first("Date"));
+void LCExpiration_S3::dump_xml(Formatter *f) const {
+  if (dm_expiration) {
+    encode_xml("ExpiredObjectDeleteMarker", "true", f);
+  } else if (!days.empty()) {
+    encode_xml("Days", days, f);
+  } else {
+    encode_xml("Date", date, f);
+  }
+}
 
-  if ((!lc_days && !lc_dm && !lc_date) || (lc_days && lc_dm) 
-      || (lc_days && lc_date) || (lc_dm && lc_date)) {
-    return false;
+void LCExpiration_S3::decode_xml(XMLObj *obj)
+{
+  bool has_days = RGWXMLDecoder::decode_xml("Days", days, obj);
+  bool has_date = RGWXMLDecoder::decode_xml("Date", date, obj);
+  string dm;
+  bool has_dm = RGWXMLDecoder::decode_xml("ExpiredObjectDeleteMarker", dm, obj);
+
+  if ((!has_days && !has_dm && !has_date) || (has_days && has_dm) 
+      || (has_days && has_date) || (has_dm && has_date)) {
+    throw RGWXMLDecoder::err("bad Expiration section");
   }
-  if (lc_days) {
-    days = lc_days->get_data();
-  } else if (lc_dm) {
-    dm_expiration = lc_dm->get_data().compare("true") == 0;
-    if (!dm_expiration) {
-      return false;
-    }
-  } else {
-    date = lc_date->get_data();
+
+  if (has_date && !check_date(date)) {
     //We need return xml error according to S3
-    if (!check_date(date)) {
-      return false;
-    }
+    throw RGWXMLDecoder::err("bad date in Date section");
   }
-  return true;
 }
 
-bool LCNoncurExpiration_S3::xml_end(const char *el) {
-  LCDays_S3 *lc_noncur_days = static_cast<LCDays_S3 *>(find_first("NoncurrentDays"));
-  if (!lc_noncur_days) {
-    return false;
-  }
-  days = lc_noncur_days->get_data();
-  return true;
+void LCNoncurExpiration_S3::decode_xml(XMLObj *obj)
+{
+  RGWXMLDecoder::decode_xml("NoncurrentDays", days, obj, true);
 }
 
-bool LCMPExpiration_S3::xml_end(const char *el) {
-  LCDays_S3 *lc_mp_days = static_cast<LCDays_S3 *>(find_first("DaysAfterInitiation"));
-  if (!lc_mp_days) {
-    return false;
-  }
-  days = lc_mp_days->get_data();
-  return true;
+void LCNoncurExpiration_S3::dump_xml(Formatter *f) const
+{
+  encode_xml("NoncurrentDays", days, f);
 }
 
-bool RGWLifecycleConfiguration_S3::xml_end(const char *el) {
-  XMLObjIter iter = find("Rule");
-  LCRule_S3 *rule = static_cast<LCRule_S3 *>(iter.get_next());
-  if (!rule)
-    return false;
-  while (rule) {
-    add_rule(rule);
-    rule = static_cast<LCRule_S3 *>(iter.get_next());
+void LCMPExpiration_S3::decode_xml(XMLObj *obj)
+{
+  RGWXMLDecoder::decode_xml("DaysAfterInitiation", days, obj, true);
+}
+
+void LCMPExpiration_S3::dump_xml(Formatter *f) const
+{
+  encode_xml("DaysAfterInitiation", days, f);
+}
+
+void RGWLifecycleConfiguration_S3::decode_xml(XMLObj *obj)
+{
+  vector<LCRule_S3> rules;
+
+  RGWXMLDecoder::decode_xml("Rule", rules, obj, true);
+
+  for (auto& rule : rules) {
+    add_rule(&rule);
   }
+
   if (cct->_conf->rgw_lc_max_rules < rule_map.size()) {
-    ldout(cct, 5) << "Warn: The lifecycle config has too many rules, rule number is:" 
-                  << rule_map.size() << ", max number is:" << cct->_conf->rgw_lc_max_rules << dendl;
-    return false;
+    stringstream ss;
+    ss << "Warn: The lifecycle config has too many rules, rule number is:" 
+      << rule_map.size() << ", max number is:" << cct->_conf->rgw_lc_max_rules;
+    throw RGWXMLDecoder::err(ss.str());
   }
-  return true;
 }
 
-bool LCFilter_S3::xml_end(const char* el) {
+void LCFilter_S3::dump_xml(Formatter *f) const
+{
+  if (has_prefix()) {
+    encode_xml("Prefix", prefix, f);
+  }
+  bool multi = has_multi_condition();
+  if (multi) {
+    f->open_array_section("And");
+  }
+  if (has_tags()) {
+    const auto& tagset_s3 = static_cast<const RGWObjTagSet_S3 &>(obj_tags);
+    tagset_s3.dump_xml(f);
+  }
+  if (multi) {
+    f->close_section();
+  }
+}
 
-  XMLObj *o = find_first("And");
+void LCFilter_S3::decode_xml(XMLObj *obj)
+{
+  XMLObj *o = obj->find_first("And");
   bool single_cond = false;
   int num_conditions = 0;
   // If there is an AND condition, every tag is a child of and
   // else we only support single conditions and return false if we see multiple
 
   if (o == nullptr){
-    o = this;
+    o = obj;
     single_cond = true;
   }
 
@@ -114,65 +137,56 @@ bool LCFilter_S3::xml_end(const char* el) {
     num_conditions++;
   }
 
-  return !(single_cond && num_conditions > 1);
+  if (single_cond && num_conditions > 1) {
+    throw RGWXMLDecoder::err("Bad filter: badly formed multiple conditions");
+  }
 }
 
-bool LCTransition_S3::xml_end(const char* el) {
-  LCDays_S3 *lc_days = static_cast<LCDays_S3 *>(find_first("Days"));
-  LCDate_S3 *lc_date = static_cast<LCDate_S3 *>(find_first("Date"));
-  if ((lc_days && lc_date) || (!lc_days && !lc_date)) {
-    return false;
+void LCTransition_S3::decode_xml(XMLObj *obj)
+{
+  bool has_days = RGWXMLDecoder::decode_xml("Days", days, obj);
+  bool has_date = RGWXMLDecoder::decode_xml("Date", date, obj);
+  if ((has_days && has_date) || (!has_days && !has_date)) {
+    throw RGWXMLDecoder::err("bad Transition section");
   }
-  if (lc_days) {
-    days = lc_days->get_data();
-  } else {
-    date = lc_date->get_data();
+
+  if (has_date && !check_date(date)) {
     //We need return xml error according to S3
-    if (!check_date(date)) {
-      return false;
-    }
+    throw RGWXMLDecoder::err("bad Date in Transition section");
   }
-  LCStorageClass_S3 *lc_storage_class = static_cast<LCStorageClass_S3 *>(find_first("StorageClass"));
-  if (!lc_storage_class) {
-    return false;
-  }
-  storage_class = lc_storage_class->get_data();
-  if (storage_class.compare("STANDARD_IA") != 0 && storage_class.compare("ONEZONE_IA") != 0 &&
-      storage_class.compare("GLACIER") != 0) {
-    return false;
+
+  if (!RGWXMLDecoder::decode_xml("StorageClass", storage_class, obj)) {
+    throw RGWXMLDecoder::err("missing StorageClass in Transition section");
   }
-  return true;
 }
 
-bool LCNoncurTransition_S3::xml_end(const char* el) {
-  LCDays_S3 *lc_noncur_days = static_cast<LCDays_S3 *>(find_first("NoncurrentDays"));
-  if (!lc_noncur_days) {
-    return false;
+void LCTransition_S3::dump_xml(Formatter *f) const {
+  if (!days.empty()) {
+    encode_xml("Days", days, f);
+  } else {
+    encode_xml("Date", date, f);
   }
-  days = lc_noncur_days->get_data();
-  LCStorageClass_S3 *lc_storage_class = static_cast<LCStorageClass_S3 *>(find_first("StorageClass"));
-  if (!lc_storage_class) {
-    return false;
+  encode_xml("StorageClass", storage_class, f);
+}
+
+void LCNoncurTransition_S3::decode_xml(XMLObj *obj)
+{
+  if (!RGWXMLDecoder::decode_xml("NoncurrentDays", days, obj)) {
+    throw RGWXMLDecoder::err("missing NoncurrentDays in NoncurrentVersionTransition section");
   }
-  storage_class = lc_storage_class->get_data();
-  if (storage_class.compare("STANDARD_IA") != 0 && storage_class.compare("ONEZONE_IA") != 0 &&
-      storage_class.compare("GLACIER") != 0) {
-    return false;
+  if (!RGWXMLDecoder::decode_xml("StorageClass", storage_class, obj)) {
+    throw RGWXMLDecoder::err("missing StorageClass in NoncurrentVersionTransition section");
   }
-  return true;
 }
 
+void LCNoncurTransition_S3::dump_xml(Formatter *f) const
+{
+  encode_xml("NoncurrentDays", days, f);
+  encode_xml("StorageClass", storage_class, f);
+}
 
-bool LCRule_S3::xml_end(const char *el) {
-  LCID_S3 *lc_id;
-  LCPrefix_S3 *lc_prefix;
-  LCStatus_S3 *lc_status;
-  LCExpiration_S3 *lc_expiration;
-  LCNoncurExpiration_S3 *lc_noncur_expiration;
-  LCMPExpiration_S3 *lc_mp_expiration;
-  LCFilter_S3 *lc_filter;
-  LCTransition_S3 *lc_transition;
-  LCNoncurTransition_S3 *lc_noncur_transition;
+void LCRule_S3::decode_xml(XMLObj *obj)
+{
   id.clear();
   prefix.clear();
   status.clear();
@@ -181,19 +195,12 @@ bool LCRule_S3::xml_end(const char *el) {
   // S3 generates a 48 bit random ID, maybe we could generate shorter IDs
   static constexpr auto LC_ID_LENGTH = 48;
 
-  lc_id = static_cast<LCID_S3 *>(find_first("ID"));
-  if (lc_id){
-    id = lc_id->get_data();
-  } else {
+  if (!RGWXMLDecoder::decode_xml("ID", id, obj)) {
     gen_rand_alphanumeric_lower(cct, &id, LC_ID_LENGTH);
   }
 
-
-  lc_filter = static_cast<LCFilter_S3 *>(find_first("Filter"));
-
-  if (lc_filter){
-    filter = *lc_filter;
-  } else {
+  LCFilter_S3 filter_s3;
+  if (!RGWXMLDecoder::decode_xml("Filter", filter_s3, obj)) {
     // Ideally the following code should be deprecated and we should return
     // False here, The new S3 LC configuration xml spec. makes Filter mandatory
     // and Prefix optional. However older clients including boto2 still generate
@@ -202,101 +209,103 @@ bool LCRule_S3::xml_end(const char *el) {
     // argument. A day will come when S3 enforces their own xml-spec, but it is
     // not this day
 
-    lc_prefix = static_cast<LCPrefix_S3 *>(find_first("Prefix"));
-
-    if (!lc_prefix){
-      return false;
+    if (!RGWXMLDecoder::decode_xml("Prefix", prefix, obj)) {
+      throw RGWXMLDecoder::err("missing Prefix in Filter");
     }
+  }
+  filter = (LCFilter)filter_s3;
 
-    prefix = lc_prefix->get_data();
+  if (!RGWXMLDecoder::decode_xml("Status", status, obj)) {
+    throw RGWXMLDecoder::err("missing Status in Filter");
+  }
+  if (status.compare("Enabled") != 0 && status.compare("Disabled") != 0) {
+    throw RGWXMLDecoder::err("bad Status in Filter");
   }
 
 
-  lc_status = static_cast<LCStatus_S3 *>(find_first("Status"));
-  if (!lc_status)
-    return false;
-  status = lc_status->get_data();
-  if (status.compare("Enabled") != 0 && status.compare("Disabled") != 0)
-    return false;
+  LCExpiration_S3 s3_expiration;
+  LCExpiration_S3 s3_noncur_expiration;
+  LCExpiration_S3 s3_mp_expiration;
+  LCFilter_S3 s3_filter;
 
-  lc_expiration = static_cast<LCExpiration_S3 *>(find_first("Expiration"));
-  lc_noncur_expiration = static_cast<LCNoncurExpiration_S3 *>(find_first("NoncurrentVersionExpiration"));
-  lc_mp_expiration = static_cast<LCMPExpiration_S3 *>(find_first("AbortIncompleteMultipartUpload"));
+  bool has_expiration = RGWXMLDecoder::decode_xml("Expiration", s3_expiration, obj);
+  bool has_noncur_expiration = RGWXMLDecoder::decode_xml("NoncurrentVersionExpiration", s3_noncur_expiration, obj);
+  bool has_mp_expiration = RGWXMLDecoder::decode_xml("AbortIncompleteMultipartUpload", s3_mp_expiration, obj);
 
-  XMLObjIter iter = find("Transition");
-  lc_transition = static_cast<LCTransition_S3 *>(iter.get_next());
-  XMLObjIter noncur_iter = find("NoncurrentVersionTransition");
-  lc_noncur_transition = static_cast<LCNoncurTransition_S3 *>(noncur_iter.get_next());
+  vector<LCTransition_S3> transitions;
+  vector<LCNoncurTransition_S3> noncur_transitions;
 
-  if (!lc_expiration && !lc_noncur_expiration && !lc_mp_expiration && !lc_transition && !lc_noncur_transition) {
-    return false;
-  } else {
-    if (lc_expiration) {
-      if (lc_expiration->has_days()) {
-        expiration.set_days(lc_expiration->get_days_str());
-      } else if (lc_expiration->has_date()) {
-        expiration.set_date(lc_expiration->get_date());
-      } else {
-        dm_expiration = lc_expiration->get_dm_expiration();
-      }
-    }
-    if (lc_noncur_expiration) {
-      noncur_expiration = *lc_noncur_expiration;
-    }
-    if (lc_mp_expiration) {
-      mp_expiration = *lc_mp_expiration;
+  bool has_transition = RGWXMLDecoder::decode_xml("Transition", transitions, obj);
+  bool has_noncur_transition = RGWXMLDecoder::decode_xml("NoncurrentVersionTransition", noncur_transitions, obj);
+
+  if (!has_expiration &&
+      !has_noncur_expiration &&
+      !has_mp_expiration &&
+      !has_transition &&
+      !has_noncur_transition) {
+    throw RGWXMLDecoder::err("bad Rule");
+  }
+
+  if (has_expiration) {
+    if (s3_expiration.has_days() ||
+        s3_expiration.has_date()) {
+      expiration = s3_expiration;
+    } else {
+      dm_expiration = s3_expiration.get_dm_expiration();
     }
-    while (lc_transition) {
-      if (!add_transition(lc_transition)) {
-        return false;
-      }
-      lc_transition = static_cast<LCTransition_S3 *>(iter.get_next());
+  }
+  if (has_noncur_expiration) {
+    noncur_expiration = s3_noncur_expiration;
+  }
+  if (has_mp_expiration) {
+    mp_expiration = s3_mp_expiration;
+  }
+  for (auto& t : transitions) {
+    if (!add_transition(&t)) {
+      throw RGWXMLDecoder::err("Failed to add transition");
     }
-    while (lc_noncur_transition) {
-      if (!add_noncur_transition(lc_noncur_transition)) {
-        return false;
-      }
-      lc_noncur_transition = static_cast<LCNoncurTransition_S3 *>(noncur_iter.get_next());
+  }
+  for (auto& t : noncur_transitions) {
+    if (!add_noncur_transition(&t)) {
+      throw RGWXMLDecoder::err("Failed to add non-current version transition");
     }
   }
-  return true;
 }
 
-void LCRule_S3::to_xml(ostream& out) {
-  out << "<Rule>" ;
-  out << "<ID>" << id << "</ID>";
+void LCRule_S3::dump_xml(Formatter *f) const {
+  encode_xml("ID", id, f);
+  // In case of an empty filter and an empty Prefix, we defer to Prefix.
   if (!filter.empty()) {
-    LCFilter_S3& lc_filter = static_cast<LCFilter_S3&>(filter);
-    lc_filter.to_xml(out);
+    const LCFilter_S3& lc_filter = static_cast<const LCFilter_S3&>(filter);
+    encode_xml("Filter", lc_filter, f);
   } else {
-    out << "<Prefix>" << prefix << "</Prefix>";
+    encode_xml("Prefix", prefix, f);
   }
-  out << "<Status>" << status << "</Status>";
+  encode_xml("Status", status, f);
   if (!expiration.empty() || dm_expiration) {
     LCExpiration_S3 expir(expiration.get_days_str(), expiration.get_date(), dm_expiration);
-    expir.to_xml(out);
+    encode_xml("Expiration", expir, f);
   }
   if (!noncur_expiration.empty()) {
-    LCNoncurExpiration_S3& noncur_expir = static_cast<LCNoncurExpiration_S3&>(noncur_expiration);
-    noncur_expir.to_xml(out);
+    const LCNoncurExpiration_S3& noncur_expir = static_cast<const LCNoncurExpiration_S3&>(noncur_expiration);
+    encode_xml("NoncurrentVersionExpiration", noncur_expir, f);
   }
   if (!mp_expiration.empty()) {
-    LCMPExpiration_S3& mp_expir = static_cast<LCMPExpiration_S3&>(mp_expiration);
-    mp_expir.to_xml(out);
+    const LCMPExpiration_S3& mp_expir = static_cast<const LCMPExpiration_S3&>(mp_expiration);
+    encode_xml("AbortIncompleteMultipartUpload", mp_expir, f);
   }
   if (!transitions.empty()) {
     for (auto &elem : transitions) {
-      LCTransition_S3& tran = static_cast<LCTransition_S3&>(elem.second);
-      tran.to_xml(out);
+      const LCTransition_S3& tran = static_cast<const LCTransition_S3&>(elem.second);
+      encode_xml("Transition", tran, f);
     }
   }
   if (!noncur_transitions.empty()) {
     for (auto &elem : noncur_transitions) {
-      LCNoncurTransition_S3& noncur_tran = static_cast<LCNoncurTransition_S3&>(elem.second);
-      noncur_tran.to_xml(out);
+      const LCNoncurTransition_S3& noncur_tran = static_cast<const LCNoncurTransition_S3&>(elem.second);
+      encode_xml("NoncurrentVersionTransition", noncur_tran, f);
     }
   }
-  out << "</Rule>";
 }
 
 int RGWLifecycleConfiguration_S3::rebuild(RGWRados *store, RGWLifecycleConfiguration& dest)
@@ -316,58 +325,11 @@ int RGWLifecycleConfiguration_S3::rebuild(RGWRados *store, RGWLifecycleConfigura
 }
 
 
-
 void RGWLifecycleConfiguration_S3::dump_xml(Formatter *f) const
 {
-       f->open_object_section_in_ns("LifecycleConfiguration", XMLNS_AWS_S3);
-
-    for (auto iter = rule_map.begin(); iter != rule_map.end(); ++iter) {
-               const LCRule_S3& rule = static_cast<const LCRule_S3&>(iter->second);
-               rule.dump_xml(f);
-       }
-
-       f->close_section(); // Lifecycle
-}
-
-XMLObj *RGWLCXMLParser_S3::alloc_obj(const char *el)
-{
-  XMLObj * obj = NULL;
-  if (strcmp(el, "LifecycleConfiguration") == 0) {
-    obj = new RGWLifecycleConfiguration_S3(cct);
-  } else if (strcmp(el, "Rule") == 0) {
-    obj = new LCRule_S3(cct);
-  } else if (strcmp(el, "ID") == 0) {
-    obj = new LCID_S3();
-  } else if (strcmp(el, "Prefix") == 0) {
-    obj = new LCPrefix_S3();
-  } else if (strcmp(el, "Filter") == 0) {
-    obj = new LCFilter_S3();
-  } else if (strcmp(el, "Status") == 0) {
-    obj = new LCStatus_S3();
-  } else if (strcmp(el, "Expiration") == 0) {
-    obj = new LCExpiration_S3();
-  } else if (strcmp(el, "Days") == 0) {
-    obj = new LCDays_S3();
-  } else if (strcmp(el, "Date") == 0) {
-    obj = new LCDate_S3();
-  } else if (strcmp(el, "ExpiredObjectDeleteMarker") == 0) {
-    obj = new LCDeleteMarker_S3();
-  } else if (strcmp(el, "NoncurrentVersionExpiration") == 0) {
-    obj = new LCNoncurExpiration_S3();
-  } else if (strcmp(el, "NoncurrentDays") == 0) {
-    obj = new LCDays_S3();
-  } else if (strcmp(el, "AbortIncompleteMultipartUpload") == 0) {
-    obj = new LCMPExpiration_S3();
-  } else if (strcmp(el, "DaysAfterInitiation") == 0) {
-    obj = new LCDays_S3();
-  } else if (strcmp(el, "StorageClass") == 0) {
-    obj = new LCStorageClass_S3();
-  } else if (strcmp(el, "Transition") == 0) {
-    obj = new LCTransition_S3();
-  } else if (strcmp(el, "NoncurrentVersionTransition") == 0) {
-    obj = new LCNoncurTransition_S3();
-  }
-  return obj;
+  for (auto iter = rule_map.begin(); iter != rule_map.end(); ++iter) {
+    const LCRule_S3& rule = static_cast<const LCRule_S3&>(iter->second);
+    encode_xml("Rule", rule, f);
+  }
 }
 
-
index e9815e2fc3ea0d6b3f4e028a349b21c1af50da38..8fbeba8df732414b68e0747ad641d342b821cf99 100644 (file)
 #include "rgw_xml.h"
 #include "rgw_tag_s3.h"
 
-class LCID_S3 : public XMLObj
+class LCFilter_S3 : public LCFilter
 {
 public:
-  LCID_S3() {}
-  ~LCID_S3() override {}
-  string& to_str() { return data; }
-};
-
-class LCPrefix_S3 : public XMLObj
-{
-public:
-  LCPrefix_S3() {}
-  ~LCPrefix_S3() override {}
-  string& to_str() { return data; }
-};
-
-class LCFilter_S3 : public LCFilter, public XMLObj
-{
- public:
-  ~LCFilter_S3() override {}
-  string& to_str() { return data; }
-  void to_xml(ostream& out){
-    out << "<Filter>";
-    stringstream ss;
-    if (has_prefix())
-      out << "<Prefix>" << prefix << "</Prefix>";
-    if (has_tags()){
-      for (const auto&kv : obj_tags.get_tags()){
-        ss << "<Tag>";
-        ss << "<Key>" << kv.first << "</Key>";
-        ss << "<Value>" << kv.second << "</Value>";
-        ss << "</Tag>";
-      }
-    }
-
-    if (has_multi_condition()) {
-      out << "<And>" << ss.str() << "</And>";
-    } else {
-      out << ss.str();
-    }
-
-    out << "</Filter>";
-  }
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("Filter");
-    if (has_multi_condition())
-      f->open_object_section("And");
-    if (!prefix.empty())
-      encode_xml("Prefix", prefix, f);
-    if (has_tags()){
-      const auto& tagset_s3 = static_cast<const RGWObjTagSet_S3 &>(obj_tags);
-      tagset_s3.dump_xml(f);
-    }
-    if (has_multi_condition())
-      f->close_section(); // And;
-    f->close_section(); // Filter
-  }
-  bool xml_end(const char *el) override;
-};
-
-class LCStatus_S3 : public XMLObj
-{
-public:
-  LCStatus_S3() {}
-  ~LCStatus_S3() override {}
-  string& to_str() { return data; }
-};
-
-class LCDays_S3 : public XMLObj
-{
-public:
-  LCDays_S3() {}
-  ~LCDays_S3() override {}
-  string& to_str() { return data; }
-};
-
-class LCDate_S3 : public XMLObj
-{
-public:
-  LCDate_S3() {}
-  ~LCDate_S3() override {}
-  string& to_str() { return data; }
-};
-
-class LCDeleteMarker_S3 : public XMLObj
-{
-public:
-  LCDeleteMarker_S3() {}
-  ~LCDeleteMarker_S3() override {}
-  string& to_str() { return data; }
+  void dump_xml(Formatter *f) const;
+  void decode_xml(XMLObj *obj);
 };
 
-class LCExpiration_S3 : public LCExpiration, public XMLObj
+class LCExpiration_S3 : public LCExpiration
 {
 private:
-  bool dm_expiration;
+  bool dm_expiration{false};
 public:
-  LCExpiration_S3(): dm_expiration(false) {}
-  LCExpiration_S3(string _days, string _date, bool _dm_expiration) {
-    days = _days;
-    date = _date;
-    dm_expiration = _dm_expiration;
-  }
-  ~LCExpiration_S3() override {}
+  LCExpiration_S3() {}
+  LCExpiration_S3(string _days, string _date, bool _dm_expiration) : LCExpiration(_days, _date), dm_expiration(_dm_expiration) {}
 
-  bool xml_end(const char *el) override;
-  void to_xml(ostream& out) {
-    out << "<Expiration>";
-    if (dm_expiration) {
-      out << "<ExpiredObjectDeleteMarker>" << "true" << "</ExpiredObjectDeleteMarker>";
-    } else if (!days.empty()){
-      out << "<Days>" << days << "</Days>";
-    } else {
-      out << "<Date>" << date << "</Date>";
-    }
-    out << "</Expiration>";
-  }
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("Expiration");
-    if (dm_expiration) {
-      encode_xml("ExpiredObjectDeleteMarker", "true", f);
-    } else if (!days.empty()) {
-      encode_xml("Days", days, f);
-    } else {
-      encode_xml("Date", date, f);
-    }
-    f->close_section(); // Expiration
-  }
+  void dump_xml(Formatter *f) const;
+  void decode_xml(XMLObj *obj);
 
   void set_dm_expiration(bool _dm_expiration) {
     dm_expiration = _dm_expiration;
@@ -152,180 +41,67 @@ public:
   }
 };
 
-class LCNoncurExpiration_S3 : public LCExpiration, public XMLObj
+class LCNoncurExpiration_S3 : public LCExpiration
 {
 public:
   LCNoncurExpiration_S3() {}
-  ~LCNoncurExpiration_S3() override {}
   
-  bool xml_end(const char *el) override;
-  void to_xml(ostream& out) {
-    out << "<NoncurrentVersionExpiration>" << "<NoncurrentDays>" << days << "</NoncurrentDays>"<< "</NoncurrentVersionExpiration>";
-  }
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("NoncurrentVersionExpiration");
-    encode_xml("NoncurrentDays", days, f);
-    f->close_section(); 
-  }
+  void decode_xml(XMLObj *obj);
+  void dump_xml(Formatter *f) const;
 };
 
-class LCMPExpiration_S3 : public LCExpiration, public XMLObj
+class LCMPExpiration_S3 : public LCExpiration
 {
 public:
   LCMPExpiration_S3() {}
-  ~LCMPExpiration_S3() {}
 
-  bool xml_end(const char *el) override;
-  void to_xml(ostream& out) {
-    out << "<AbortIncompleteMultipartUpload>" << "<DaysAfterInitiation>" << days << "</DaysAfterInitiation>" << "</AbortIncompleteMultipartUpload>";
-  }
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("AbortIncompleteMultipartUpload");
-    encode_xml("DaysAfterInitiation", days, f);
-    f->close_section();
-  }
-};
-
-class LCStorageClass_S3 : public XMLObj
-{
-public:
-  LCStorageClass_S3() {}
-  ~LCStorageClass_S3() override {}
-  string& to_str() { return data; }
+  void decode_xml(XMLObj *obj);
+  void dump_xml(Formatter *f) const;
 };
 
-class LCTransition_S3 : public LCTransition, public XMLObj
+class LCTransition_S3 : public LCTransition
 {
 public:
   LCTransition_S3() {}
-  ~LCTransition_S3() {}
 
-  bool xml_end(const char *el) override;
-  void to_xml(ostream& out) {
-    out << "<Transition>";
-    if (!days.empty()) {
-      out << "<Days>" << days << "</Days>";
-    } else {
-      out << "<Date>" << date << "</Date>";
-    }
-    out << "<StorageClass>" << storage_class << "</StorageClass>" << "</Transition>";
-  }
-
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("Transition");
-    if (!days.empty()) {
-      encode_xml("Days", days, f);
-    } else {
-      encode_xml("Date", date, f);
-    }
-    encode_xml("StorageClass", storage_class, f);
-    f->close_section();
-  }
+  void decode_xml(XMLObj *obj);
+  void dump_xml(Formatter *f) const;
 };
 
-class LCNoncurTransition_S3 : public LCTransition, public XMLObj
+class LCNoncurTransition_S3 : public LCTransition
 {
 public:
   LCNoncurTransition_S3() {}
   ~LCNoncurTransition_S3() {}
 
-  bool xml_end(const char *el) override;
-  void to_xml(ostream& out) {
-    out << "<NoncurrentVersionTransition>" << "<NoncurrentDays>" << days << "</NoncurrentDays>"
-        << "<StorageClass>" << storage_class << "</StorageClass>" << "</NoncurrentVersionTransition>";
-  }
-
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("NoncurrentVersionTransition");
-    encode_xml("NoncurrentDays", days, f);
-    encode_xml("StorageClass", storage_class, f);
-    f->close_section();
-  }
+  void decode_xml(XMLObj *obj);
+  void dump_xml(Formatter *f) const;
 };
 
 
-class LCRule_S3 : public LCRule, public XMLObj
+class LCRule_S3 : public LCRule
 {
 private:
   CephContext *cct;
 public:
   LCRule_S3(): cct(nullptr) {}
   explicit LCRule_S3(CephContext *_cct): cct(_cct) {}
-  ~LCRule_S3() override {}
 
-  void to_xml(ostream& out);
-  bool xml_end(const char *el) override;
-  bool xml_start(const char *el, const char **attr);
-  void dump_xml(Formatter *f) const {
-    f->open_object_section("Rule");
-    encode_xml("ID", id, f);
-    // In case of an empty filter and an empty Prefix, we defer to Prefix.
-    if (!filter.empty()) {
-      const LCFilter_S3& lc_filter = static_cast<const LCFilter_S3&>(filter);
-      lc_filter.dump_xml(f);
-    } else {
-      encode_xml("Prefix", prefix, f);
-    }
-    encode_xml("Status", status, f);
-    if (!expiration.empty() || dm_expiration) {
-      LCExpiration_S3 expir(expiration.get_days_str(), expiration.get_date(), dm_expiration);
-      expir.dump_xml(f);
-    }
-    if (!noncur_expiration.empty()) {
-      const LCNoncurExpiration_S3& noncur_expir = static_cast<const LCNoncurExpiration_S3&>(noncur_expiration);
-      noncur_expir.dump_xml(f);
-    }
-    if (!mp_expiration.empty()) {
-      const LCMPExpiration_S3& mp_expir = static_cast<const LCMPExpiration_S3&>(mp_expiration);
-      mp_expir.dump_xml(f);
-    }
-    if (!transitions.empty()) {
-      for (auto &elem : transitions) {
-        const LCTransition_S3& tran = static_cast<const LCTransition_S3&>(elem.second);
-        tran.dump_xml(f);
-      }
-    }
-    if (!noncur_transitions.empty()) {
-      for (auto &elem : noncur_transitions) {
-        const LCNoncurTransition_S3& noncur_tran = static_cast<const LCNoncurTransition_S3&>(elem.second);
-        noncur_tran.dump_xml(f);
-      }
-    }
-    f->close_section(); // Rule
-  }
+  void dump_xml(Formatter *f) const;
+  void decode_xml(XMLObj *obj);
 
   void set_ctx(CephContext *ctx) {
     cct = ctx;
   }
 };
 
-class RGWLCXMLParser_S3 : public RGWXMLParser
-{
-  CephContext *cct;
-
-  XMLObj *alloc_obj(const char *el) override;
-public:
-  explicit RGWLCXMLParser_S3(CephContext *_cct) : cct(_cct) {}
-};
-
-class RGWLifecycleConfiguration_S3 : public RGWLifecycleConfiguration, public XMLObj
+class RGWLifecycleConfiguration_S3 : public RGWLifecycleConfiguration
 {
 public:
   explicit RGWLifecycleConfiguration_S3(CephContext *_cct) : RGWLifecycleConfiguration(_cct) {}
-  RGWLifecycleConfiguration_S3() : RGWLifecycleConfiguration(NULL) {}
-  ~RGWLifecycleConfiguration_S3() override {}
-
-  bool xml_end(const char *el) override;
+  RGWLifecycleConfiguration_S3() : RGWLifecycleConfiguration(nullptr) {}
 
-  void to_xml(ostream& out) {
-    out << "<LifecycleConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">";
-    multimap<string, LCRule>::iterator iter;
-    for (iter = rule_map.begin(); iter != rule_map.end(); ++iter) {
-      LCRule_S3& rule = static_cast<LCRule_S3&>(iter->second);
-      rule.to_xml(out);
-    }
-    out << "</LifecycleConfiguration>";
-  }
+  void decode_xml(XMLObj *obj);
   int rebuild(RGWRados *store, RGWLifecycleConfiguration& dest);
   void dump_xml(Formatter *f) const;
 };
index fea79e9cecfdb1a007e0bb0eda7cb748b942bdfd..71caf89b40883742e202d722f0ce2b25e8a88af2 100644 (file)
@@ -5118,8 +5118,8 @@ void RGWPutLC::execute()
 {
   bufferlist bl;
   
-  RGWLifecycleConfiguration_S3 *config = NULL;
-  RGWLCXMLParser_S3 parser(s->cct);
+  RGWLifecycleConfiguration_S3 config;
+  RGWXMLParser parser;
   RGWLifecycleConfiguration_S3 new_config(s->cct);
 
   content_md5 = s->info.env->get("HTTP_CONTENT_MD5");
@@ -5172,20 +5172,25 @@ void RGWPutLC::execute()
     op_ret = -ERR_MALFORMED_XML;
     return;
   }
-  config = static_cast<RGWLifecycleConfiguration_S3 *>(parser.find_first("LifecycleConfiguration"));
-  if (!config) {
-    op_ret = -ERR_MALFORMED_XML;
+
+  try {
+    RGWXMLDecoder::decode_xml("LifecycleConfiguration", config, &parser);
+  } catch (RGWXMLDecoder::err& err) {
+    ldpp_dout(this, 5) << "Bad lifecycle configuration: " << err << dendl;
+    op_ret = -EINVAL;
     return;
   }
 
-  op_ret = config->rebuild(store, new_config);
+  op_ret = config.rebuild(store, new_config);
   if (op_ret < 0)
     return;
 
   if (s->cct->_conf->subsys.should_gather<ceph_subsys_rgw, 15>()) {
-    ldpp_dout(this, 15) << "New LifecycleConfiguration:";
-    new_config.to_xml(*_dout);
-    *_dout << dendl;
+    XMLFormatter xf;
+    new_config.dump_xml(&xf);
+    stringstream ss;
+    xf.flush(ss);
+    ldpp_dout(this, 15) << "New LifecycleConfiguration:" << ss.str() << dendl;
   }
 
   op_ret = store->get_lc()->set_bucket_config(s->bucket_info, s->bucket_attrs, &new_config);
index c87b0cb13d34a452925dfdc61d22f5744644f47c..c65175788db8bf6fea4189cf525f342f2631f030 100644 (file)
@@ -402,7 +402,7 @@ void RGWGetObjTags_ObjStore_S3::send_response_data(bufferlist& bl)
 
 int RGWPutObjTags_ObjStore_S3::get_params()
 {
-  RGWObjTagsXMLParser parser;
+  RGWXMLParser parser;
 
   if (!parser.init()){
     return -EINVAL;
@@ -421,17 +421,17 @@ int RGWPutObjTags_ObjStore_S3::get_params()
     return -ERR_MALFORMED_XML;
   }
 
-  RGWObjTagSet_S3 *obj_tags_s3;
-  RGWObjTagging_S3 *tagging;
+  RGWObjTagging_S3 tagging;
 
-  tagging = static_cast<RGWObjTagging_S3 *>(parser.find_first("Tagging"));
-  obj_tags_s3 = static_cast<RGWObjTagSet_S3 *>(tagging->find_first("TagSet"));
-  if(!obj_tags_s3){
+  try {
+    RGWXMLDecoder::decode_xml("Tagging", tagging, &parser);
+  } catch (RGWXMLDecoder::err& err) {
+    ldout(s->cct, 5) << "Malformed tagging request: " << err << dendl;
     return -ERR_MALFORMED_XML;
   }
 
   RGWObjTags obj_tags;
-  r = obj_tags_s3->rebuild(obj_tags);
+  r = tagging.rebuild(obj_tags);
   if (r < 0)
     return r;
 
@@ -1758,7 +1758,7 @@ int RGWPostObj_ObjStore_S3::get_tags()
 {
   string tags_str;
   if (part_str(parts, "tagging", &tags_str)) {
-    RGWObjTagsXMLParser parser;
+    RGWXMLParser parser;
     if (!parser.init()){
       ldout(s->cct, 0) << "Couldn't init RGWObjTags XML parser" << dendl;
       err_msg = "Server couldn't process the request";
@@ -1770,17 +1770,17 @@ int RGWPostObj_ObjStore_S3::get_tags()
       return -EINVAL;
     }
 
-    RGWObjTagSet_S3 *obj_tags_s3;
-    RGWObjTagging_S3 *tagging;
+    RGWObjTagging_S3 tagging;
 
-    tagging = static_cast<RGWObjTagging_S3 *>(parser.find_first("Tagging"));
-    obj_tags_s3 = static_cast<RGWObjTagSet_S3 *>(tagging->find_first("TagSet"));
-    if(!obj_tags_s3){
-      return -ERR_MALFORMED_XML;
+    try {
+      RGWXMLDecoder::decode_xml("Tagging", tagging, &parser);
+    } catch (RGWXMLDecoder::err& err) {
+      ldout(s->cct, 5) << "Malformed tagging request: " << err << dendl;
+      return -EINVAL;
     }
 
     RGWObjTags obj_tags;
-    int r = obj_tags_s3->rebuild(obj_tags);
+    int r = tagging.rebuild(obj_tags);
     if (r < 0)
       return r;
 
index d9f52b7af857a56465f197f1c0b1e4a8e671d855..c5ad87caed60f14f312bd75907b787da1006f8b0 100644 (file)
@@ -9,43 +9,41 @@
 
 #include "rgw_tag_s3.h"
 
-bool RGWObjTagEntry_S3::xml_end(const char*){
-  RGWObjTagKey_S3 *key_obj = static_cast<RGWObjTagKey_S3 *>(find_first("Key"));
-  RGWObjTagValue_S3 *val_obj = static_cast<RGWObjTagValue_S3 *>(find_first("Value"));
+void RGWObjTagEntry_S3::decode_xml(XMLObj *obj) {
+  RGWXMLDecoder::decode_xml("Key", key, obj, true);
+  RGWXMLDecoder::decode_xml("Value", val, obj, true);
+}
 
-  if (!key_obj)
-    return false;
+void RGWObjTagEntry_S3::dump_xml(Formatter *f) const {
+  encode_xml("Key", key, f);
+  encode_xml("Value", val, f);
 
-  string s = key_obj->get_data();
-  if (s.empty()){
-    return false;
+  if (key.empty()) {
+    throw RGWXMLDecoder::err("empty key");
   }
 
-  key = s;
-  if (val_obj) {
-    val = val_obj->get_data();
+  if (val.empty()) {
+    throw RGWXMLDecoder::err("empty val");
   }
-
-  return true;
 }
 
-bool RGWObjTagSet_S3::xml_end(const char*){
-  XMLObjIter iter = find("Tag");
-  RGWObjTagEntry_S3 *tagentry = static_cast<RGWObjTagEntry_S3 *>(iter.get_next());
-  while (tagentry) {
-    const std::string& key = tagentry->get_key();
-    const std::string& val = tagentry->get_val();
-    if (!add_tag(key,val))
-      return false;
+void RGWObjTagSet_S3::decode_xml(XMLObj *obj) {
+  vector<RGWObjTagEntry_S3> entries;
 
-    tagentry = static_cast<RGWObjTagEntry_S3 *>(iter.get_next());
+  RGWXMLDecoder::decode_xml("Tag", entries, obj, true);
+
+  for (auto& entry : entries) {
+    const std::string& key = entry.get_key();
+    const std::string& val = entry.get_val();
+    if (!add_tag(key,val)) {
+      throw RGWXMLDecoder::err("failed to add tag");
+    }
   }
-  return true;
 }
 
-int RGWObjTagSet_S3::rebuild(RGWObjTags& dest){
+int RGWObjTagSet_S3::rebuild(RGWObjTags& dest) {
   int ret;
-  for (const auto &it: tag_map){
+  for (const auto &it : tag_map){
     ret = dest.check_and_add_tag(it.first, it.second);
     if (ret < 0)
       return ret;
@@ -53,34 +51,15 @@ int RGWObjTagSet_S3::rebuild(RGWObjTags& dest){
   return 0;
 }
 
-bool RGWObjTagging_S3::xml_end(const char*){
-  RGWObjTagSet_S3 *tagset = static_cast<RGWObjTagSet_S3 *> (find_first("TagSet"));
-  return tagset != nullptr;
-
+void RGWObjTagging_S3::decode_xml(XMLObj *obj) {
+  RGWXMLDecoder::decode_xml("TagSet", tagset, obj, true);
 }
 
 void RGWObjTagSet_S3::dump_xml(Formatter *f) const {
-  for (const auto& tag: tag_map){
-    f->open_object_section("Tag");
-    f->dump_string("Key", tag.first);
-    f->dump_string("Value", tag.second);
-    f->close_section();
+  for (const auto& tag : tag_map){
+    Formatter::ObjectSection os(*f, "Tag");
+    encode_xml("Key", tag.first, f);
+    encode_xml("Value", tag.second, f);
   }
 }
 
-XMLObj *RGWObjTagsXMLParser::alloc_obj(const char *el){
-  XMLObj* obj = nullptr;
-  if(strcmp(el,"Tagging") == 0) {
-    obj = new RGWObjTagging_S3();
-  } else if (strcmp(el,"TagSet") == 0) {
-    obj = new RGWObjTagSet_S3();
-  } else if (strcmp(el,"Tag") == 0) {
-    obj = new RGWObjTagEntry_S3();
-  } else if (strcmp(el,"Key") == 0) {
-    obj = new RGWObjTagKey_S3();
-  } else if (strcmp(el,"Value") == 0) {
-    obj = new RGWObjTagValue_S3();
-  }
-
-  return obj;
-}
index 8afca46d2c702820706006f9c772b36f0bb7d36e..7ed022776d8ffcbc388944dde5dc735ff3740207 100644 (file)
 #include "rgw_tag.h"
 #include "rgw_xml.h"
 
-struct RGWObjTagKey_S3: public XMLObj
-{
-};
-
-struct RGWObjTagValue_S3: public XMLObj
-{
-};
-
-class RGWObjTagEntry_S3: public XMLObj
+class RGWObjTagEntry_S3
 {
   std::string key;
   std::string val;
@@ -31,32 +23,31 @@ public:
   RGWObjTagEntry_S3(const std::string &k, const std::string &v):key(k),val(v) {};
   ~RGWObjTagEntry_S3() {}
 
-  bool xml_end(const char*) override;
-  const std::string& get_key () const { return key;}
-  const std::string& get_val () const { return val;}
-  //void to_xml(CephContext *cct, ostream& out) const;
-};
+  const std::string& get_key () const { return key; }
+  const std::string& get_val () const { return val; }
 
-class RGWObjTagSet_S3: public RGWObjTags, public XMLObj
-{
-public:
-  bool xml_end(const char*) override;
   void dump_xml(Formatter *f) const;
-  int rebuild(RGWObjTags& dest);
+  void decode_xml(XMLObj *obj);
 };
 
-class RGWObjTagging_S3: public XMLObj
+class RGWObjTagSet_S3: public RGWObjTags
 {
 public:
-  bool xml_end(const char*) override;
+  int rebuild(RGWObjTags& dest);
+
+  void dump_xml(Formatter *f) const;
+  void decode_xml(XMLObj *obj);
 };
 
-class RGWObjTagsXMLParser : public RGWXMLParser
+class RGWObjTagging_S3
 {
-  XMLObj *alloc_obj(const char *el) override;
+  RGWObjTagSet_S3 tagset;
 public:
-  RGWObjTagsXMLParser() {}
-  ~RGWObjTagsXMLParser() {}
+  void decode_xml(XMLObj *obj);
+  int rebuild(RGWObjTags& dest) {
+    return tagset.rebuild(dest);
+  }
 };
 
+
 #endif /* RGW_TAG_S3_H */
index a1e85bac8b20e01853337277c4aa85e47a71ef8f..cc85286355f9776fab0fba284642203d83ccd5dd 100755 (executable)
@@ -120,6 +120,20 @@ find(string name)
   return iter;
 }
 
+XMLObjIter XMLObj::find_first()
+{
+  XMLObjIter iter;
+  map<string, XMLObj *>::iterator first;
+  map<string, XMLObj *>::iterator last;
+  first = children.begin();
+  if (first != children.end()) {
+    last = children.upper_bound(first->first);
+  }else
+    last = children.end();
+  iter.set(first, last);
+  return iter;
+}
+
 XMLObj *XMLObj::
 find_first(string name)
 {
index 00425cd583bb1054a1137b68f7238aed9c2a25b1..38b2c702ecfd76d7e5a1f44e7d0bfff970f942bf 100644 (file)
@@ -51,6 +51,7 @@ public:
   void add_child(string el, XMLObj *obj);
   bool get_attr(string name, string& attr);
   XMLObjIter find(string name);
+  XMLObjIter find_first();
   XMLObj *find_first(string name);
 
   friend ostream& operator<<(ostream &out, const XMLObj &obj);
@@ -117,6 +118,11 @@ public:
   static void decode_xml(const char *name, T& val, T& default_val, XMLObj *obj);
 };
 
+static inline ostream& operator<<(ostream &out, RGWXMLDecoder::err& err)
+{
+  return out << err.message;
+}
+
 template<class T>
 void decode_xml_obj(T& val, XMLObj *obj)
 {
@@ -155,17 +161,17 @@ void do_decode_xml_obj(list<T>& l, const string& name, XMLObj *obj)
 }
 
 template<class T>
-void do_decode_xml_obj(vector<T>& l, const string& name, XMLObj *obj)
+void decode_xml_obj(std::vector<T>& v, XMLObj *obj)
 {
-  l.clear();
+  v.clear();
 
-  XMLObjIter iter = obj->find(name);
+  XMLObjIter iter = obj->find_first();
   XMLObj *o;
 
-  while (o = iter.get_next()) {
+  while ((o = iter.get_next())) {
     T val;
     decode_xml_obj(val, o);
-    l.push_back(val);
+    v.push_back(val);
   }
 }