# Hardened XML parsing. What these tests pin down is documented at the top of
# R/xmlsafe.R: neither XXE nor billion laughs works against xml2's defaults,
# but both defences depend on defaults staying defaults. This file is what
# turns that from an accident into a contract.
test_that("entity declarations are rejected", {
bomb <- paste0(
'',
'',
']>&lol2;'
)
expect_error(arg_read_xml(bomb), class = "argentum_error_xml")
# Case and internal whitespace do not dodge the check.
expect_error(
arg_read_xml(']>'),
class = "argentum_error_xml"
)
})
test_that("an external entity declaration is rejected before parsing", {
xxe <- paste0(
'',
']>',
'&xxe;'
)
expect_error(arg_read_xml(xxe), class = "argentum_error_xml")
})
test_that("a bare DOCTYPE without entities still parses", {
# WFS 1.0.0 / WMS 1.1.1 capabilities legitimately declare the OGC DTD.
doc <- paste0(
'',
'',
'ok',
''
)
parsed <- arg_read_xml(doc)
expect_s3_class(parsed, "xml_document")
expect_equal(xml2::xml_attr(xml2::xml_root(parsed), "version"), "1.1.1")
})
test_that("a normal capabilities document does not trip the detection", {
doc <- ''
expect_s3_class(arg_read_xml(doc), "xml_document")
})
test_that("oversized documents are rejected", {
expect_error(
arg_read_xml("abc", max_bytes = 5),
class = "argentum_error_xml"
)
# The cap is measured in bytes, not characters.
expect_error(
arg_read_xml("รกรกรกรก", max_bytes = 10),
class = "argentum_error_xml"
)
})
test_that("broken XML raises the package's own error class", {
expect_error(arg_read_xml("this is not xml"), class = "argentum_error_xml")
expect_error(arg_read_xml(""), class = "argentum_error_xml")
})