—package
Dancer::Serializer::XML;
our
$AUTHORITY
=
'cpan:SUKRIA'
;
#ABSTRACT: serializer for handling XML data
$Dancer::Serializer::XML::VERSION
=
'1.3521'
;
use
strict;
use
warnings;
use
Carp;
use
Dancer::ModuleLoader;
# singleton for the XML::Simple object
my
$_xs
;
# helpers
sub
from_xml {
my
$s
= Dancer::Serializer::XML->new;
$s
->deserialize(
@_
);
}
sub
to_xml {
my
$s
= Dancer::Serializer::XML->new;
$s
->serialize(
@_
);
}
# class definition
sub
loaded_xmlsimple {
Dancer::ModuleLoader->load(
'XML::Simple'
);
}
sub
loaded_xmlbackends {
# we need either XML::Parser or XML::SAX too
Dancer::ModuleLoader->load(
'XML::Parser'
) or
Dancer::ModuleLoader->load(
'XML::SAX'
);
}
sub
init {
my
(
$self
) =
@_
;
die
'XML::Simple is needed and is not installed'
unless
$self
->loaded_xmlsimple;
die
'XML::Simple needs XML::Parser or XML::SAX and neither is installed'
unless
$self
->loaded_xmlbackends;
# Disable fetching external entities, as that's a security hole: this allows
# someone to fetch remote websites from the server, or to read local files.
# This only works for XML::Parser when called directly from XML::Simple;
# for XML::SAX we'll need to do some even *more* horrible stuff later on.
$_xs
= XML::Simple->new(
ParserOpts
=> [
Handlers
=> {
ExternEnt
=>
sub
{
return
''
;
}
}
],
);
}
sub
serialize {
my
$self
=
shift
;
my
$entity
=
shift
;
my
%options
= (
RootName
=>
'data'
);
my
$s
= setting(
'engines'
) || {};
if
(
exists
(
$s
->{XMLSerializer}) &&
exists
(
$s
->{XMLSerializer}{serialize})) {
%options
= (
%options
, %{
$s
->{XMLSerializer}{serialize}});
}
%options
= (
%options
,
@_
);
$_xs
->XMLout(
$entity
,
%options
);
}
sub
deserialize {
my
$self
=
shift
;
my
$xml
=
shift
;
my
%options
= ();
my
$s
= setting(
'engines'
) || {};
if
(
exists
(
$s
->{XMLSerializer}) &&
exists
(
$s
->{XMLSerializer}{deserialize})) {
%options
= (
%options
, %{
$s
->{XMLSerializer}{deserialize}});
}
%options
= (
%options
,
@_
);
# This is the promised terrible hack: claim that the LWP-talking code has
# already been loaded, and make sure that the handler that's called when
# we're dealing with an external entity does nothing.
# For whichever reason, this handler is called despite XML::Parser
# (which on my machine is the only XML::SAX backend that can handle
# external entities) having a ParseParamEnt option which is off by default,
# but appears to only be used deep in the XML::Parser XS guts.
no
warnings
'redefine'
;
local
*XML::Parser::lwp_ext_ent_handler
=
sub
{
return
};
local
$INC
{
'XML/Parser/LWPExternEnt.pl'
}
=
'Dancer::Serializer::XML disabled loading this to patch around '
.
'XXE vulnerabilities'
;
$_xs
->XMLin(
$xml
,
%options
);
}
sub
content_type {
'text/xml'
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Dancer::Serializer::XML - serializer for handling XML data
=head1 VERSION
version 1.3521
=head1 SYNOPSIS
=head1 DESCRIPTION
=head2 METHODS
=head2 serialize
Serialize a data structure to an XML structure.
=head2 deserialize
Deserialize an XML structure to a data structure
=head2 content_type
Return 'text/xml'
=head2 CONFIG FILE
You can set XML::Simple options for serialize and deserialize in the
config file:
engines:
XMLSerializer:
serialize:
AttrIndent: 1
deserialize:
ForceArray: 1
=head1 AUTHOR
Dancer Core Developers
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by Alexis Sukrieh.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut