XML Parsing and Serialization in OpenDAL#
OpenDAL uses quick-xml as its XML engine for all storage backends that communicate over XML-based APIs. This includes S3-compatible services, Azure Blob/Files, Google Cloud Storage, Huawei OBS, WebDAV, and the oay gateway binary. The dependency is declared in core/Cargo.toml and bin/oay/Cargo.toml with the serialize and overlapped-lists features enabled.
Where quick-xml Is Used#
Service Backends (core crate)#
XML is used in two directions:
Deserialization (API responses → Rust structs): All S3-compatible backends — S3, OSS, COS, OBS — plus Azure Blob, Azure Files, and WebDAV use quick_xml::de::from_reader() or quick_xml::de::from_str() to parse list-objects, delete-objects, and error responses. GCS uses it for multipart upload initiation responses.
Serialization (Rust structs → XML request bodies): quick_xml::se::to_string() is called to build CompleteMultipartUploadRequest and DeleteObjectsRequest payloads for S3, OSS, COS, OBS, Azure Blob, and GCS .
Gateway (oay)#
The oay S3-frontend serializes ListBucketResult and error responses directly with quick_xml::se::to_string() .
Centralized Error Handling#
All XML errors feed through two helpers in core/src/raw/serde_util.rs:
new_xml_serialize_error— wrapsquick_xml::SeErrorinto anopendal::Errornew_xml_deserialize_error— wrapsquick_xml::DeErrorinto anopendal::Error
Both are re-exported from core/src/raw/mod.rs and used uniformly via .map_err(new_xml_deserialize_error) chains across every XML-parsing service.
The S3 lister additionally marks deserialization errors as temporary, enabling automatic retries when a server returns incomplete XML under high load.
WebDAV Character Encoding Workaround#
The WebDAV backend's deserialize_multistatus() function applies a pre-processing step before deserializing PROPFIND responses: it percent-encodes a set of special characters (&()_+-=;) in the raw bytes before handing off to quick_xml::de::from_str(). The code comments this as HACKS! HACKS! HACKS! and references upstream tafia/quick-xml#719.
Security: RUSTSEC-2026-0195 (Memory Allocation DoS)#
quick-xml v0.41.0 (released 2026-06-29) addressed two security-relevant issues relevant to OpenDAL deployments:
-
Memory allocation DoS via namespace flooding (#970):
NamespaceResolver::push(used by everyNsReaderStart/Empty event) previously allocated oneNamespaceBindingperxmlns/xmlns:*declaration with no upper bound. On a crafted M-byte start tag the resolver could allocate roughly 3×M bytes of heap before returning to the caller — enough to trigger out-of-memory conditions in servers with concurrentNsReaderusers. Fix: the default cap is now 256 declarations per element (DEFAULT_MAX_DECLARATIONS_PER_ELEMENT); excess declarations returnNamespaceError::TooManyDeclarations. The limit is configurable viaNamespaceResolver::set_max_declarations_per_element(). -
O(N²) duplicate-attribute scan (#969):
Attributesiterator previously performed an O(N²) scan for duplicate attributes on start tags with many attributes. v0.41.0 switches to a 64-bit hash pre-filter so the overall cost is O(N).
Advisory: RUSTSEC-2026-0195 tracks the namespace-binding vulnerability. As of 2026-07-08, OpenDAL's core and oay are still pinned to 0.37 ; a bump to ≥ 0.41.0 is required to remediate. A Dependabot PR (#7839) was opened to upgrade the Node.js bindings' quick-xml, and a separate bug report (#7885) tracks the upgrade for the core and oay crates.