Apache-Request-I18N

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

	- Support was added for language specification in encoded words
	  (RFC 2184, section 5)

	Bugfixes:
	- Form fields in the query string are no longer decoded for
	  multipart/form-data
	- handler() now returns DECLINED instead of OK
	- instance() was ignoring any previously existing Apache::Request

0.03  Fri Nov 25 15:30:25 2005
	- Bugfix: upload(NAME) crashed if no upload by that name existed

0.02  Mon Aug  8 12:48:00 2005
	- Bugfix when erroneously supplying Apache::Request options

0.01  Sat Jul 16 14:06:47 2005
	- original version; created by h2xs 1.23 with options
		-AXn Apache::Request::I18N -b 5.8.0

I18N.pm  view on Meta::CPAN

	# parms() in list context returns an Apache::Table, which cannot
	# handle wide characters, so we croak if ENCODE_PARMS is empty.
	# (Maybe we could subclass Apache::Table and perform some magic?)

	carp 'Calling parms() with empty ENCODE_PARMS is unsupported'
		unless $self->encode_parms;
	
	return $self->SUPER::parms(@_);
}

sub upload {
	my ($self, $arg) = @_;

	my $upload_class = ref($self);
	$upload_class =~ s/\bRequest\b/Upload/;
	unless ($upload_class->isa('Apache::Upload::I18N')) {
		no strict 'refs';
		carp "\@$upload_class\::ISA should contain Apache::Upload::I18N";
		push @{"$upload_class\::ISA"}, 'Apache::Upload::I18N';
	}
	
	# upload(UPLOAD) is implemented, but undefined, so there's little
	# harm in not supporting it...
	if (UNIVERSAL::isa($arg, 'Apache::Upload')) {
		carp 'Calling upload($upload) is unsupported';
		return $self->SUPER::upload($arg);
	}

	unless ($self->{_uploads}) {
		my @uploads = $self->SUPER::upload;
		my %uploads;
		foreach (@uploads) {
			$upload_class->rebless($_, $self);
			push @{ $uploads{ $_->name } }, $_;
		}
		$self->{_uploads} = \@uploads;
		$self->{_uploads_hash} = \%uploads;
	}

	if (defined $arg) {
		my $uploads = $self->{_uploads_hash}{$arg};
		return unless $uploads;
		return wantarray ? @$uploads : $uploads->[0];
	} else {
		return wantarray
			? @{ $self->{_uploads} }
			: $self->{_uploads}[0];
	}
}

=head2 Additional methods

=over

=item decode_parms()

=item encode_parms()

I18N.pm  view on Meta::CPAN

		# differently.

		if ($is_urlenc || $args{$key}) {
			$key = $self->_decode($key, $charset);
		} else {
			$key = $self->_decode_value($key);
		}

		# Same thing for filenames

		if ($self->SUPER::upload($key)) {
			$val = $self->_decode_value($val)
		} else {
			$val = $self->_decode($val, $charset);
		}

		$_ = $self->_encode($_) foreach $key, $val;

		$new_parms->add($key, $val);

		return 1;

I18N.pm  view on Meta::CPAN


package Apache::Upload::I18N;

use Carp;
use Scalar::Util qw(refaddr);

our @ISA = 'Apache::Upload';

=head1 FILE UPLOADS

Uploads returned by the I<upload>() method are I<Apache::Upload::I18N>
objects; they behave like I<Apache::Upload> objects, and their I<name>() and
I<filename>() methods will return values according to ENCODE_PARMS.

(This is however not the case within the upload hook; see L<"BUGS"> below.)

=cut

# Apache::Upload objects are C structs, and no mechanism is provided to
# subclass them.  We therefore maintain a parallel storage area where each
# object can stash additional information about itself.

{
	my %stashes;

	sub _stash { $stashes{refaddr $_[0]} ||= {} }
	sub _delete_stash { delete $stashes{refaddr $_[0]} }
}

# Each upload object is reblessed into Apache::Upload::I18N, and remembers its
# new name and filename through its stash area.  ($req is needed so we know
# which encoding is used.)

sub rebless {
	my ($class, $upload, $req) = @_;

	return undef unless $upload;

	bless $upload, $class;

	my ($name, $filename) = ($upload->_old_name, $upload->_old_filename);
	foreach ($name, $filename) {
		$_ = $req->_decode_value($_);
		$_ = $req->_encode($_) if $req->encode_parms;
	}

	my $stash = $upload->_stash;
	%$stash = ( name => $name, filename => $filename );

	return $upload;
}

sub DESTROY { $_[0]->_delete_stash }

sub name          { $_[0]->_stash->{name}     }
sub filename      { $_[0]->_stash->{filename} }
sub _old_name     { $_[0]->SUPER::name        }
sub _old_filename { $_[0]->SUPER::filename    }

sub next { carp "next() is not supported"; $_[0]->SUPER::next }

I18N.pm  view on Meta::CPAN

I<Apache::Table> cannot handle character strings.  This also applies to
calling I<param>() in scalar context.

=item *

Query parameter keys may or may not be case-insensitive, depending on their
contents and on ENCODE_PARMS.

=item *

Calling I<next>() on an upload object is not currently supported.

=back


=head1 BUGS

=over

=item *

I18N.pm  view on Meta::CPAN


When using the B<multipart/form-data> encoding, each form field value may have
its character encoding specified via the I<charset> parameter of its
I<Content-Type> header.  This value is currently ignored.  (This is due to a
limitation in I<libapreq>.)

Similarly, the I<Content-Transfer-Encoding> header is also ignored.

=item *

When using upload hooks, the upload object supplied to UPLOAD_HOOK will not
have had its I<name>() and I<filename>() decoded yet.

=item *

When using the B<multipart/form-data> encoding, this module will get confused
if a form field appears in both the query string B<and> the request body.  In
other words, don't try to do this:

  <FORM METHOD=post ENCTYPE="multipart/form-data"
  	ACTION=".../my_script?foo=1">
  <INPUT NAME="foo" ...>
  ...

You should also avoid mixing file uploads and regular input within a single
field name.  In other words, don't try this either:

  <INPUT TYPE=text NAME="foo">
  <INPUT TYPE=file NAME="foo">

=item *

Since all query parameter keys are stored in encoded form within an
I<Apache::Table> (which is case-insensitive), it is possible for two distinct
keys to be fused together if their encoded representations are similar.

I18N.pm  view on Meta::CPAN

=for comment
Note that doing so within a Mason component will have no effect, as Mason will
have already parsed and remembered all form fields.

=for comment
We should probably make _mangle_parms lazy, and only call it from param() and
such.

=item *

Automatically decode the contents of a B<text/*> file upload if a charset has
been provided.

=for comment
This should probably be optional, since we wouldn't know what to do with an
upload that doesn't have a charset.  (Neither DECODE_PARMS nor the local
native charset would be appropriate here.)  Besides, if ENCODE_PARMS was
defined, we'll still return a handle that spits out wide characters.  (Come to
think of it, do any user-agents even bother providing a charset anyway?)

=item *

Allow for more than one DECODE_PARMS, and try to guess which one is
appropriate.

=item *

MANIFEST  view on Meta::CPAN

README
t/00_load.t
t/apreqi18n/dump.t
t/conf/modperl_extra.pl
t/dump.d/01_get.in
t/dump.d/01_get.pl
t/dump.d/02_post.in
t/dump.d/02_post.pl
t/dump.d/03_multipart.in
t/dump.d/03_multipart.pl
t/dump.d/04_upload.in
t/dump.d/04_upload.pl
t/dump.d/05_decode.in
t/dump.d/05_decode.pl
t/dump.d/06_encode.in
t/dump.d/06_encode.pl
t/dump.d/charset_urlencoded.in
t/dump.d/charset_urlencoded.pl
t/dump.d/mime.in
t/dump.d/mime.pl
t/dump.d/mime_filename.in
t/dump.d/mime_filename.pl
t/dump.d/mime_lang.in
t/dump.d/mime_lang.pl
t/dump.d/multiple_params.in
t/dump.d/multiple_params.pl
t/dump.d/multiple_uploads.in
t/dump.d/multiple_uploads.pl
t/dump.d/nomime_query.in
t/dump.d/nomime_query.pl
t/dump.d/nomime_uploads.in
t/dump.d/nomime_uploads.pl
t/dump.d/nomime_urlencoded.in
t/dump.d/nomime_urlencoded.pl
t/lib/TestApReqI18N.pm
t/response/TestApReqI18N/dump.pm
t/TEST.PL
t/TODO
META.yml                                 Module meta-data (added by MakeMaker)

t/TODO  view on Meta::CPAN

Empty subclass
Check that uploads are subclassed too

Create with %args vs. SetVar
Calling instance twice
Calling instance after A::R
Calling param w/ and w/o encode_parms, w/ and w/o param, in list or scalar
Calling parms, checking table
Calling parms twice returns same table
Calling upload(), upload(UPLOAD) scalar/list
Calling Upload->next
Check decode_parms / encode_parms

Check handler

t/apreqi18n/dump.t  view on Meta::CPAN


my @sources;
if (@ARGV) {
	@sources = @ARGV;
} else {
	find( sub { push @sources, $File::Find::name if -f $_ && /\.in$/ }, DIR );
}
  
plan tests => 1 + TESTS_PER_FILE * @sources;
  
our (%vars, @uploads);

eval GET_BODY_ASSERT (URL . '?foo=bar');
is_deeply(\%vars, { foo => [ 'bar' ] }, 'Basic param() test');

foreach my $source (sort @sources) {
    SKIP: {
	my $target = $source;
	$target =~ s/\.in$/.pl/;

	-e $target || skip "Cannot find $target", TESTS_PER_FILE;

	(%vars, @uploads) = ();
	do $target;

	my %expected_vars = %vars;
	my @expected_uploads = @uploads;

	local $TODO;
	eval request_from_file($source, URL);

	is_deeply(\%vars, \%expected_vars, '[V] ' . last_test_name);
	is_deeply(\@uploads, \@expected_uploads, '[U] ' . last_test_name);
    }
}

t/dump.d/04_upload.in  view on Meta::CPAN

# Basic file upload
POST / HTTP/1.0
Content-Type: multipart/form-data; boundary="FOO FOO"

--FOO FOO
Content-Disposition: form-data; name="foo"; filename="foo.txt"

bar
--FOO FOO--

t/dump.d/04_upload.pl  view on Meta::CPAN

%vars = ( foo => [ 'foo.txt' ] );
@uploads = ( [ 'foo', 'foo.txt', 3 ] );

t/dump.d/mime_filename.pl  view on Meta::CPAN

%vars = ( foo => [ "\x{30d5}.txt" ] );
@uploads = ( [ 'foo', "\x{30d5}.txt", 3 ] );

t/dump.d/multiple_uploads.pl  view on Meta::CPAN

%vars = ( foo => [ "\x{30d5}.txt", "\x{30d5}2.txt" ] );
@uploads = (
	[ 'foo', "\x{30d5}.txt", 3 ],
	[ 'foo', "\x{30d5}2.txt", 4 ],
	);

t/dump.d/nomime_uploads.pl  view on Meta::CPAN

%vars = (
	foo	=> [ "foo.txt", "foo.txt" ],
	);
@uploads = (
	[ 'foo', "foo.txt", 8 ],
	[ 'foo', "foo.txt", 40 ],
	);

t/response/TestApReqI18N/dump.pm  view on Meta::CPAN

use Data::Dumper;

sub handler {
	my $r = shift;

	$r = Apache::Request::I18N->instance($r);

	$r->send_http_header('text/plain');

	my %vars = map +($_, [ $r->param($_) ]), $r->param;
	my @uploads = map [$_->name, $_->filename, $_->size], $r->upload;

	print Data::Dumper->Dump([\%vars, \@uploads], [qw(*vars *uploads)]);

	OK;
}

1;

__DATA__

<Location /TestApReqI18N__dump>
PerlSetVar DecodeParms ascii



( run in 1.515 second using v1.01-cache-2.11-cpan-b16cb0d3907 )