Apache-Request-I18N
view release on metacpan or search on metacpan
- 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
# 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()
# 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;
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 }
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 *
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.
=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 *
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)
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.813 second using v1.01-cache-2.11-cpan-b16cb0d3907 )