/usr/share/perl5/Web/Dispatch/HTTPMethods.pm is in libweb-simple-perl 0.031-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | package Web::Dispatch::HTTPMethods;
use strictures 1;
use Web::Dispatch::Predicates qw(match_method);
use Scalar::Util qw(blessed);
use Exporter 'import';
our @EXPORT = qw(GET HEAD POST PUT DELETE OPTIONS);
sub HEAD(&;@) { method_helper(HEAD => @_) }
sub GET(&;@) { method_helper(GET => @_) }
sub POST(&;@) { method_helper(POST => @_) }
sub PUT(&;@) { method_helper(PUT => @_) }
sub DELETE(&;@) { method_helper(DELETE => @_) }
sub OPTIONS(&;@) { method_helper(OPTIONS => @_) }
{
package Web::Dispatch::HTTPMethods::Endpoint;
sub new { bless { map { $_=>0 } @EXPORT }, shift }
sub hdrs { 'Content-Type' => 'text/plain' }
sub create_implicit_HEAD {
my $self = shift;
if($self->{GET} && not $self->{HEAD}) {
$self->{HEAD} = sub { [ @{$self->{GET}->(@_)}[0,1], []] };
}
}
sub create_implicit_OPTIONS {
my $self = shift;
$self->{OPTIONS} = sub {
[200, [$self->hdrs, Allow=>$self->allowed] , [] ];
};
}
sub allowed { join ',', grep { $_[0]->{$_} } @EXPORT }
sub to_app {
my $self = shift;
my $implicit_HEAD = $self->create_implicit_HEAD;
my $implicit_OPTIONS = $self->create_implicit_OPTIONS;
return sub {
my $env = shift;
if($env->{REQUEST_METHOD} eq 'HEAD') {
$implicit_HEAD->($env);
} elsif($env->{REQUEST_METHOD} eq 'OPTIONS') {
$implicit_OPTIONS->($env);
} else {
[405, [$self->hdrs, Allow=>$self->allowed] , ['Method Not Allowed'] ];
}
};
}
}
sub isa_endpoint {
blessed($_[0]) &&
$_[0]->isa('Web::Dispatch::HTTPMethods::Endpoint')
}
sub endpoint_from { return $_[-1] }
sub new_endpoint { Web::Dispatch::HTTPMethods::Endpoint->new(@_) }
sub method_helper {
my $predicate = match_method(my $method = shift);
my ($code, @following ) = @_;
endpoint_from( my @dispatchers =
scalar(@following) ? ($predicate, @_) : ($predicate, @_, new_endpoint)
)->{$method} = $code;
die "Non HTTP Method dispatcher detected in HTTP Method scope"
unless(isa_endpoint($dispatchers[-1]));
return @dispatchers;
}
1;
=head1 NAME
Web::Dispatch::HTTPMethods - Helpers to make RESTFul Dispatchers Easier
=head1 SYNOPSIS
package MyApp:WithHTTPMethods;
use Web::Simple;
use Web::Dispatch::HTTPMethods;
sub as_text {
[200, ['Content-Type' => 'text/plain'],
[$_[0]->{REQUEST_METHOD}, $_[0]->{REQUEST_URI}] ]
}
sub dispatch_request {
sub (/get) {
GET { as_text(pop) }
},
sub (/get-head) {
GET { as_text(pop) }
HEAD { [204,[],[]] },
},
sub (/get-post-put) {
GET { as_text(pop) } ## NOTE: no commas separating http methods
POST { as_text(pop) }
PUT { as_text(pop) }
},
}
=head1 DESCRIPTION
Exports the most commonly used HTTP methods as subroutine helpers into your
L<Web::Simple> based application.
Use of these methods additionally adds an automatic HTTP code 405
C<Method Not Allowed> response if none of the HTTP methods match for a given dispatch and
also adds a dispatch rule for C<HEAD> if no C<HEAD> exists but a C<GET> does
(in which case the C<HEAD> returns the C<GET> dispatch with an empty body.)
We also add support at the end of the chain for the OPTIONS method.
This defaults to HTTP 200 OK + Allows http headers.
We also try to set correct HTTP headers such as C<Allows> as makes sense based
on your dispatch chain.
The following dispatch chains are basically the same:
sub dispatch_request {
sub (/get-http-methods) {
GET { [200, ['Content-Type' => 'text/plain'], ['Hello World']] }
},
sub(/get-classic) {
sub (GET) { [200, ['Content-Type' => 'text/plain'], ['Hello World']] },
sub (HEAD) { [200, ['Content-Type' => 'text/plain'], []] },
sub (OPTIONS) {
[200, ['Content-Type' => 'text/plain', Allows=>'GET,HEAD,OPTIONS'], []];
},
sub () {
[405, ['Content-Type' => 'text/plain', Allows=>'GET,HEAD,OPTIONS'],
['Method Not Allowed']]
},
}
}
The idea here is less boilerplate to distract the reader from the main point of
the code and also to encapsulate some best practices.
B<NOTE> You currently cannot mix http method style and prototype sub style in
the same scope, as in the following example:
sub dispatch_request {
sub (/get-head) {
GET { ... }
sub (HEAD) { ... }
},
}
If you try this our code will notice and issue a C<die>. If you have a good use
case please bring it to the authors.
=head2 EXPORTS
This automatically exports the following subroutines:
GET
PUT
POST
HEAD
DELETE
OPTIONS
=head1 AUTHOR
See L<Web::Simple> for AUTHOR
=head1 CONTRIBUTORS
See L<Web::Simple> for CONTRIBUTORS
=head1 COPYRIGHT
See L<Web::Simple> for COPYRIGHT
=head1 LICENSE
See L<Web::Simple> for LICENSE
=cut
|