use 5.008001; use strict; use warnings; use Plack::Request (); package Plack::Middleware::MethodOverride; $Plack::Middleware::MethodOverride::VERSION = '0.20'; # ABSTRACT: Override REST methods to Plack apps via POST use parent 'Plack::Middleware'; use Plack::Util::Accessor 'param'; my %allowed_method = map { $_ => undef } qw(GET HEAD PUT DELETE OPTIONS TRACE CONNECT PATCH); sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{param} = 'x-tunneled-method' unless exists $self->{param}; $self->{header} = 'X-HTTP-Method-Override' unless exists $self->{header}; $self->header($self->{header}); # munge it return $self; } sub call { my ($self, $env) = @_; my $meth = $env->{'plack.original_request_method'} = $env->{REQUEST_METHOD}; if ($meth and uc $meth eq 'POST') { no warnings 'uninitialized'; my $override = uc ( $env->{$self->header} or $env->{QUERY_STRING} && Plack::Request->new($env)->query_parameters->{$self->param} ); $env->{REQUEST_METHOD} = $override if exists $allowed_method{$override}; } $self->app->($env); } sub header { my $self = shift; return $self->{header} if not @_; return $self->{header} = '' if not $_[0]; (my $key = 'HTTP_'.$_[0]) =~ tr/-a-z/_A-Z/; return $self->{header} = $key; } 1; __END__ =pod =encoding UTF-8 =head1 Name Plack::Middleware::MethodOverride - Override REST methods to Plack apps via POST =head1 Version version 0.20 =head1 Synopsis In your Plack app: use Plack::Builder; builder { enable MethodOverride; $app; }; PUT via a query parameter in your POST forms:
Or override it via the C header in a request: my $req = HTTP::Request->new(POST => '/foo', [ 'X-HTTP-Method-Override' => 'PUT' ]); =head1 Description Writing Lful apps is a good thing, but if you're also trying to support web browsers, it would be nice not to be reduced to C and C for everything. This middleware allows for C requests that pretend to be something else: by adding either a header named C to the request, or a query parameter named C to the URI, the client can say what method it actually meant. That is, as long as it meant one of these: =over =item * GET =item * POST =item * HEAD =item * PUT =item * DELETE =item * OPTIONS =item * TRACE =item * CONNECT =item * PATCH =back If so, then the C in the PSGI environment will be replaced with the client's desired value. The original request method is always stored under the C key. =head1 Configuration These are the named arguments you can pass to C. Or, more likely, on the C line in your C block, as in enable 'MethodOverride', header => 'X-HTTP-Method', param => 'my_method'; =head2 C
Specifies the HTTP header name which specifies the overriding HTTP method. Defaults to C, as used by Google for its APIs. =head2 C Specifies the query parameter name to specify the overriding HTTP method. Defaults to C. =head1 Acknowledgements This module gleefully steals from L by Dave Rolsky and the original version by Tatsuhiko Miyagawa (which in turn stole from L). Thanks to L for the shove in this direction, to L for suggesting that it be implemented as middleware, and to L for convincing me not to parse body parameters. =head1 Authors =over 4 =item * Tatsuhiko Miyagawa =item * David E. Wheeler =item * Aristotle Pagaltzis =back =head1 Copyright and License This software is copyright (c) 2015 by Tatsuhiko Miyagawa, David E. Wheeler, Aristotle Pagaltzis. 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