# $Id: XPointer.pm,v 1.10 2004/11/13 21:13:40 asc Exp $ use strict; package Apache::XPointer; $Apache::XPointer::VERSION = '1.0'; =head1 NAME Apache::XPointer - mod_perl handler to address XML fragments. =head1 SYNOPSIS SetHandler perl-script PerlHandler Apache::XPointer::XPath # my $ua = LWP::UserAgent->new(); my $req = HTTP::Request->new(GET => "http://example.com/foo/bar/baz.xml"); $req->header("Range" => qq(xmlns("x=x-urn:example")xpointer(*//x:thingy))); my $res = $ua->request($req); =head1 DESCRIPTION Apache::XPointer is a mod_perl handler to address XML fragments using the HTTP 1.1 I header, as described in the paper : I. Additionally, the handler may also be configured to recognize a conventional CGI parameter as a valid range identifier. If no 'range' property is found, then the original document is sent unaltered. =head1 IMPORTANT This package is a base class and not expected to be invoked directly. Please use one of the scheme-specific handlers instead. =head1 SUPPPORTED SCHEMES =head2 XPath Consult L =head1 MOD_PERL COMPATIBILITY This handler will work with both mod_perl 1.x and mod_perl 2.x; it works better in 1.x because it supports Apache::Request which does a better job of parsing CGI parameters. =cut require 5.6.0; use mod_perl; use constant MP2 => ($mod_perl::VERSION >= 1.99) ? 1 : 0; BEGIN { if (MP2) { require Apache2; require Apache::RequestRec; require Apache::RequestIO; require Apache::RequestUtil; require Apache::Const; require Apache::Log; require Apache::URI; require APR::Table; require APR::URI; Apache::Const->import(-compile => qw(OK DECLINED HTTP_NOT_FOUND HTTP_INTERNAL_SERVER_ERROR)); } else { require Apache; require Apache::Constants; require Apache::Log; require Apache::Request; Apache::Constants->import(qw(OK DECLINED NOT_FOUND SERVER_ERROR)); } } sub handler : method { my $pkg = shift; my $apache = shift; my $range = $pkg->_header_in($apache,"Range"); if ((! $range) && ($apache->dir_config("XPointerAllowCGIRange") =~ /^on$/i)) { my $rparam = $apache->dir_config("XPointerCGIRangeParam") || "range"; # Waiting for Apache::Request to be ported # to mod_perl2 because default query parser # doesn't do a very good job of handling stuff # like range=xmlns(foo=x-urn:bar) if ($pkg->_mp2()) { $apache->parsed_uri()->query() =~ /^$rparam=(.*)$/; $range = $1; } else { my $request = Apache::Request->new($apache); $range = $request->param($rparam); } } if (! $range) { return $pkg->_declined(); } # my ($ns,$pointer) = $pkg->parse_range($apache,$range); if (! $pointer) { $apache->log()->error(sprintf("failed to parse range '%s'", $range)); return $pkg->_server_error(); } # my $res = $pkg->range($apache,$ns,$pointer); if ((! $res) || (! $res->{success})) { return $res->{response}; } $pkg->send_results($apache,$res); return $pkg->_ok(); } sub parse_range { my $pkg = shift; return $pkg->_nometh(@_); } sub range { my $pkg = shift; return $pkg->_nometh(@_); } sub send_results { my $pkg = shift; return $pkg->_nometh(@_); } sub _mp2 { return MP2; } sub _nometh { my $pkg = shift; my $apache = shift; my $caller = (caller(1))[3]; $caller =~ s/.*:://; $apache->log()->error(sprintf("package %s does not define a '%s' method", $pkg,$caller)); return 0; } sub _declined { my $pkg = shift; return ($pkg->_mp2()) ? Apache::DECLINED() : Apache::Constants::DECLINED(); } sub _server_error { my $pkg = shift; return ($pkg->_mp2()) ? Apache::HTTP_INTERNAL_SERVER_ERROR() : Apache::Constants::SERVER_ERROR(); } sub _not_found { my $pkg = shift; return ($pkg->_mp2()) ? Apache::HTTP_NOT_FOUND() : Apache::Constants::NOT_FOUND(); } sub _ok { my $pkg = shift; return ($pkg->_mp2()) ? Apache::OK() : Apache::Constants::OK(); } sub _header_in { my $pkg = shift; my $apache = shift; my $field = shift; return ($pkg->_mp2()) ? $apache->headers_in()->{$field} : $apache->header_in($field); } sub _header_out { my $pkg = shift; my $apache = shift; my $field = shift; my $value = shift; ($pkg->_mp2()) ? $apache->headers_out()->{$field} = $value: $apache->header_out($field,$value); } =head1 VERSION 1.0 =head1 DATE $Date: 2004/11/13 21:13:40 $ =head1 AUTHOR Aaron Straup Cope Eascope@cpan.orgE =head1 SEE ALSO http://www.mindswap.org/papers/swrp-iswc04.pdf http://www.w3.org/TR/WD-xptr =head1 LICENSE Copyright (c) 2004 Aaron Straup Cope. All rights reserved. This is free software, you may use it and distribute it under the same terms as Perl itself. =cut return 1;