2022-12-07 00:40:01 +03:00
#!/usr/bin/env python3
2013-02-25 11:54:25 +04:00
#
# This tests custom input callbacks
#
import sys
2023-08-15 13:49:27 +03:00
import setup_test
2013-02-25 11:54:25 +04:00
import libxml2
2013-03-30 17:38:20 +04:00
try :
import StringIO
str_io = StringIO . StringIO
except :
import io
str_io = io . StringIO
2013-02-25 11:54:25 +04:00
# We implement a new scheme, py://strings/ that will reference this dictionary
pystrings = {
' catalogs/catalog.xml ' :
''' <?xml version= " 1.0 " encoding= " utf-8 " ?>
< ! DOCTYPE catalog PUBLIC " -//OASIS//DTD Entity Resolution XML Catalog V1.0//EN " " http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd " >
< catalog xmlns = " urn:oasis:names:tc:entity:xmlns:xml:catalog " >
< rewriteSystem systemIdStartString = " http://example.com/dtds/ " rewritePrefix = " ../dtds/ " / >
< / catalog > ''' ,
' xml/sample.xml ' :
''' <?xml version= " 1.0 " encoding= " utf-8 " ?>
< ! DOCTYPE root SYSTEM " http://example.com/dtds/sample.dtd " >
< root > & sample . entity ; < / root > ''' ,
' dtds/sample.dtd ' :
'''
< ! ELEMENT root ( #PCDATA)>
< ! ENTITY sample . entity " replacement text " > '''
}
prefix = " py://strings/ "
2013-02-27 09:11:47 +04:00
startURL = prefix + " xml/sample.xml "
catURL = prefix + " catalogs/catalog.xml "
2013-02-25 11:54:25 +04:00
def my_input_cb ( URI ) :
2013-02-27 09:11:47 +04:00
if not ( URI . startswith ( prefix ) ) :
2013-02-25 11:54:25 +04:00
return None
path = URI [ len ( prefix ) : ]
if path not in pystrings :
return None
2013-03-30 17:38:20 +04:00
return str_io ( pystrings [ path ] )
2013-02-25 11:54:25 +04:00
2013-02-27 09:11:47 +04:00
def run_test ( desc , docpath , catalog , exp_status = " verified " , exp_err = [ ] , test_callback = None ,
root_name = " root " , root_content = " replacement text " ) :
opts = libxml2 . XML_PARSE_DTDLOAD | libxml2 . XML_PARSE_NONET | libxml2 . XML_PARSE_COMPACT
actual_err = [ ]
def my_global_error_cb ( ctx , msg ) :
actual_err . append ( ( - 1 , msg ) )
def my_ctx_error_cb ( arg , msg , severity , reserved ) :
actual_err . append ( ( severity , msg ) )
libxml2 . registerErrorHandler ( my_global_error_cb , None )
try :
parser = libxml2 . createURLParserCtxt ( docpath , opts )
parser . setErrorHandler ( my_ctx_error_cb , None )
if catalog is not None :
parser . addLocalCatalog ( catalog )
if test_callback is not None :
test_callback ( )
parser . parseDocument ( )
doc = parser . doc ( )
actual_status = " loaded "
e = doc . getRootElement ( )
if e . name == root_name and e . content == root_content :
actual_status = " verified "
doc . freeDoc ( )
except libxml2 . parserError :
actual_status = " not loaded "
if actual_status != exp_status :
2013-03-30 17:38:20 +04:00
print ( " Test ' %s ' failed: expect status ' %s ' , actual ' %s ' " % ( desc , exp_status , actual_status ) )
2013-02-27 09:11:47 +04:00
sys . exit ( 1 )
elif actual_err != exp_err :
2013-03-30 17:38:20 +04:00
print ( " Test ' %s ' failed " % desc )
print ( " Expect errors: " )
for s , m in exp_err : print ( " [ %2d ] ' %s ' " % ( s , m ) )
print ( " Actual errors: " )
for s , m in actual_err : print ( " [ %2d ] ' %s ' " % ( s , m ) )
2013-02-27 09:11:47 +04:00
sys . exit ( 1 )
2013-02-25 11:54:25 +04:00
# Check that we cannot read custom schema without custom callback
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading entity without custom callback " ,
docpath = startURL , catalog = None ,
exp_status = " not loaded " , exp_err = [
( - 1 , " I/O " ) ,
2024-06-14 20:42:40 +03:00
( - 1 , " warning : " ) ,
2023-12-19 17:41:37 +03:00
( - 1 , " failed to load \" py://strings/xml/sample.xml \" : No such file or directory \n " )
2013-02-27 09:11:47 +04:00
] )
2013-02-25 11:54:25 +04:00
# Register handler and try to load the same entity
libxml2 . registerInputCallback ( my_input_cb )
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading entity with custom callback " ,
docpath = startURL , catalog = None ,
exp_status = " loaded " , exp_err = [
2024-07-04 16:15:17 +03:00
( 4 , ' failed to load " http://example.com/dtds/sample.dtd " : Attempt to load network entity \n ' ) ,
2024-05-02 17:23:04 +03:00
( 4 , " Entity ' sample.entity ' not defined \n " )
2013-02-27 09:11:47 +04:00
] )
2013-02-25 11:54:25 +04:00
# Register a catalog (also accessible via pystr://) and retry
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading entity with custom callback and catalog " ,
docpath = startURL , catalog = catURL )
2013-02-25 11:54:25 +04:00
# Unregister custom callback when parser is already created
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading entity and unregistering callback " ,
docpath = startURL , catalog = catURL ,
test_callback = lambda : libxml2 . popInputCallbacks ( ) ,
exp_status = " loaded " , exp_err = [
2023-12-19 17:41:37 +03:00
( 3 , " failed to load \" py://strings/dtds/sample.dtd \" : No such file or directory \n " ) ,
2024-05-02 17:23:04 +03:00
( 4 , " Entity ' sample.entity ' not defined \n " )
2013-02-27 09:11:47 +04:00
] )
2013-02-25 11:54:25 +04:00
# Try to load the document again
2013-02-27 09:11:47 +04:00
run_test ( desc = " Retry loading document after unregistering callback " ,
docpath = startURL , catalog = catURL ,
exp_status = " not loaded " , exp_err = [
( - 1 , " I/O " ) ,
2024-06-14 20:42:40 +03:00
( - 1 , " warning : " ) ,
2023-12-19 17:41:37 +03:00
( - 1 , " failed to load \" py://strings/xml/sample.xml \" : No such file or directory \n " )
2013-02-27 09:11:47 +04:00
] )
2013-02-25 11:54:25 +04:00
# But should be able to read standard I/O yet...
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading using standard i/o after unregistering callback " ,
docpath = " tst.xml " , catalog = None ,
root_name = ' doc ' , root_content = ' bar ' )
2013-02-25 11:54:25 +04:00
# Now pop ALL input callbacks, should fail to load even standard I/O
try :
while True :
libxml2 . popInputCallbacks ( )
2013-04-02 06:27:57 +04:00
except IndexError :
2013-02-25 11:54:25 +04:00
pass
2013-02-27 09:11:47 +04:00
run_test ( desc = " Loading using standard i/o after unregistering all callbacks " ,
docpath = " tst.xml " , catalog = None ,
exp_status = " not loaded " , exp_err = [
( - 1 , " I/O " ) ,
2024-06-14 20:42:40 +03:00
( - 1 , " warning : " ) ,
2023-12-19 17:41:37 +03:00
( - 1 , " failed to load \" tst.xml \" : No such file or directory \n " )
2013-02-27 09:11:47 +04:00
] )
2013-03-30 17:38:20 +04:00
print ( " OK " )
2013-02-27 09:11:47 +04:00
sys . exit ( 0 ) ;