{"id":16307841,"url":"https://github.com/ap/plack-middleware-rewrite","last_synced_at":"2025-03-22T20:33:31.733Z","repository":{"id":56840551,"uuid":"1372678","full_name":"ap/Plack-Middleware-Rewrite","owner":"ap","description":"mod_rewrite for Plack","archived":false,"fork":false,"pushed_at":"2022-09-04T15:59:04.000Z","size":58,"stargazers_count":10,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T14:22:58.355Z","etag":null,"topics":["perl","plack","psgi"],"latest_commit_sha":null,"homepage":"https://metacpan.org/release/Plack-Middleware-Rewrite","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ap.png","metadata":{"files":{"readme":"README.pod","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-02-16T05:41:43.000Z","updated_at":"2024-03-14T15:56:06.000Z","dependencies_parsed_at":"2022-08-29T01:51:13.735Z","dependency_job_id":null,"html_url":"https://github.com/ap/Plack-Middleware-Rewrite","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FPlack-Middleware-Rewrite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FPlack-Middleware-Rewrite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FPlack-Middleware-Rewrite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FPlack-Middleware-Rewrite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ap","download_url":"https://codeload.github.com/ap/Plack-Middleware-Rewrite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245020147,"owners_count":20548154,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["perl","plack","psgi"],"created_at":"2024-10-10T21:15:28.619Z","updated_at":"2025-03-22T20:33:31.394Z","avatar_url":"https://github.com/ap.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"use 5.006; use strict; use warnings;\n\npackage Plack::Middleware::Rewrite;\n\nour $VERSION = '2.102';\n\nBEGIN { require Plack::Middleware; our @ISA = 'Plack::Middleware' }\n\nuse Plack::Util::Accessor qw( request response rules );\nuse Plack::Request ();\nuse Plack::Util ();\nuse overload ();\n\nsub call {\n\tmy $self = shift;\n\tmy ( $env ) = @_;\n\n\tmy ( $app, $res, $legacy );\n\tmy ( $rules, $modify_cb ) = ( $self-\u003erequest, $self-\u003eresponse );\n\n\tunless ( $rules or $modify_cb ) {\n\t\t$rules = $self-\u003erules;\n\t\t$legacy = 1;\n\t}\n\n\t# call rules with $_ aliased to PATH_INFO\n\t( $res ) = map { scalar $rules-\u003e( $env ) } $env-\u003e{'PATH_INFO'}\n\t\tif $rules;\n\n\tif ( $legacy ) {\n\t\tif    ( 'CODE'  eq ref $res ) { ( $modify_cb, $res ) = $res }\n\t\telsif ( 'ARRAY' eq ref $res ) { undef $res if not @$res }\n\t\telsif ( ref $res )            { undef $res }\n\t\telse {\n\t\t\t# upgrade scalar to response if it looks like an HTTP status\n\t\t\t$res = ( defined $res and $res =~ /\\A[1-5][0-9][0-9]\\z/ )\n\t\t\t\t? [ $res, [], [] ]\n\t\t\t\t: undef;\n\t\t}\n\t}\n\telse {\n\t\tif    ( 'CODE'  eq ref $res ) { ( $app, $res ) = $res }\n\t\telsif ( 'ARRAY' eq ref $res ) { @$res = ( 303, [], [] ) if not @$res }\n\t\telsif ( ref $res )            { die 'Unhandled reference type in request rewrite: ', overload::StrVal( $res ), \"\\n\" }\n\t\telse                          { undef $res }\n\t}\n\n\tif ( $res ) { # external redirect, or explicit response\n\t\tpush @$res, map { [] } @$res .. 2;\n\n\t\tif ( $res-\u003e[0] =~ /\\A3(?:0[0-35-9]|[1-9][0-9])\\z/ ) {\n\t\t\tmy $dest = Plack::Util::header_get( $res-\u003e[1], 'Location' );\n\t\t\tif ( not $dest ) {\n\t\t\t\t$dest = Plack::Request-\u003enew( $env )-\u003euri;\n\t\t\t\tPlack::Util::header_set( $res-\u003e[1], Location =\u003e $dest );\n\t\t\t}\n\n\t\t\tunless (\n\t\t\t\tPlack::Util::content_length( $res-\u003e[2] )\n\t\t\t\tor Plack::Util::header_exists( $res-\u003e[1], 'Content-Length' )\n\t\t\t) {\n\t\t\t\tmy $href = Plack::Util::encode_html( $dest );\n\t\t\t\tPlack::Util::header_set( $res-\u003e[1], qw( Content-Type text/html ) );\n\t\t\t\t$res-\u003e[2] = [ qq'\u003c!DOCTYPE html\u003e\u003ctitle\u003eMoved\u003c/title\u003eThis resource has moved to \u003ca href=\"$href\"\u003ea new address\u003c/a\u003e.' ];\n\t\t\t}\n\t\t}\n\t}\n\telse { # internal redirect\n\t\t$app ||= $self-\u003eapp;\n\t\t$res = $app-\u003e( $env );\n\t}\n\n\treturn $res if not $modify_cb;\n\tPlack::Util::response_cb( $res, sub {\n\t\tmy $response = $_[0];\n\t\tmy $hdrs = Plack::Util::headers( $response-\u003e[1] );\n\t\t$hdrs-\u003e{'status'} = sub { @_ ? $response-\u003e[0] = $_[0] : $response-\u003e[0] };\n\t\tmy ( $result ) = map $modify_cb-\u003e( $env ), $hdrs;\n\t\treturn 'CODE' eq ref $result ? $result : ();\n\t} );\n}\n\n1;\n\n__END__\n\n=pod\n\n=encoding UTF-8\n\n=head1 NAME\n\nPlack::Middleware::Rewrite - mod_rewrite for Plack\n\n=head1 SYNOPSIS\n\n # in app.psgi\n use Plack::Builder;\n \n builder {\n     enable 'Rewrite', request =\u003e sub {\n         s{^/here(?=/|$)}{/there};\n\n         return [303]\n             if s{^/foo/?$}{/bar/}\n             or s{^/baz/?$}{/quux/};\n\n         return [301, [ Location =\u003e 'http://example.org/' ], []]\n             if m{^/example/?$};\n\n         return [201] if $_ eq '/favicon.ico';\n\n         return [503] if -e '/path/to/app/maintenance.lock';\n\n         return [200, [qw(Content-Type text/plain)], ['You found it!']]\n             if $_ eq '/easter-egg';\n     },\n     response =\u003e sub {\n         $_-\u003estatus( 303 )\n             if $_-\u003estatus eq 201 and $_-\u003eget( 'Location' );\n\n         $_-\u003eset( 'Content-Type', 'application/xhtml+xml' )\n             if ( $_[0]{'HTTP_ACCEPT'} || '' ) =~ m{application/xhtml\\+xml(?!\\s*;\\s*q=0)};\n     };\n     $app;\n };\n\n=head1 DESCRIPTION\n\nThis middleware provides a convenient way to modify requests in flight in Plack\napps. Rewrite rules are simply written in Perl, which means everything that can\nbe done with mod_rewrite can be done with this middleware much more intuitively\n(if in syntactically wordier ways). Its primary purpose is rewriting paths, but\nalmost anything is possible very easily.\n\n=head1 CONFIGURATION OPTIONS\n\n=head2 C\u003crequest\u003e\n\nTakes a reference to a function that will be called in scalar context for each\nrequest. On call, C\u003c$_\u003e will be aliased to C\u003cPATH_INFO\u003e, so that you can easily\nuse regexp matches and subtitutions to examine and modify it. The L\u003cPSGI\u003e\nenvironment will be passed to the function as its first and only argument.\n\nThe function may return three kinds of valid value:\n\n=over 4\n\n=item A plain scalar\n\nIgnored. The value will be thrown away and any path rewriting (or any other\nmodifications of the PSGI environment) will take effect during the current\nrequest cycle, invisibly to the client user agent.\n\n=item An array reference\n\nA L\u003cPSGI\u003e array response to return immediately without invoking the wrapped\nPSGI application.\n\nThe array may have fewer than 3 elements, in which case it will be filled to\n3E\u003cnbsp\u003eelements by pushing the default values: an empty body array, empty\nheaders array, and a 303E\u003cnbsp\u003estatusE\u003cnbsp\u003ecode.\n\nIf the C\u003cLocation\u003e header is missing from a redirect response (i.e. one with\n3xxE\u003cnbsp\u003estatusE\u003cnbsp\u003ecode), it will be filled in automatically from the value\nleft in C\u003cPATH_INFO\u003e by your callback. (Note that this only allows you to\nredirect to URLs with the same hostname. To redirect the client to a different\nhost, you will have to supply a C\u003cLocation\u003e header manually.)\n\n=item A code reference\n\nA PSGI application which will be called to process the request. This prevents\nthe wrapped application from being called.\n\n=item Any other kind of reference\n\nError. An exception will be thrown.\n\n=back\n\n=head2 C\u003cresponse\u003e\n\nTakes a reference to a function that will be called I\u003cafter\u003e the request has\nbeen processed and the response is ready to be returned.\n\nOn call, C\u003c$_\u003e will be aliased to a specially extended\na L\u003cC\u003cPlack::Util::headers\u003e|Plack::Util/headers\u003e object for the response, for\nconvenient alteration of headers.\nThe extension is a C\u003cstatus\u003e method, which allows you to inspect and modify the\nresponse status code.\n\nJust as in L\u003c/C\u003crequest\u003e\u003e, the L\u003cPSGI\u003e environment is passed as first and only\nargument.\n\nAny return value from this function will be ignored unless it is a code\nreference. In that case it will be used to filter the response body, as\ndocumented in L\u003cPlack::Middleware/RESPONSE CALLBACK\u003e:\n\n=over 4\n\n return sub {\n     my $chunk = shift;\n     return unless defined $chunk;\n     $chunk =~ s/Foo/Bar/g;\n     return $chunk;\n };\n\nThe callback takes one argument C\u003c$chunk\u003e and your callback is expected to\nreturn the updated chunk. If the given C\u003c$chunk\u003e is undef, it means the stream\nhas reached the end, so your callback should also return undef, or return the\nfinal chunk and return undef when called next time.\n\n=back\n\n=head1 LEGACY INTERFACE\n\nThe old interface uses a single attribute, C\u003crules\u003e, instead of the C\u003crequest\u003e\nand C\u003cresponse\u003e pair, with a more complex set of return values, containing an\nambiguity. It is also less expressive than the new interface.\n\nThe old interface is documented here for the purposes of maintaining old code;\nits use in new code is L\u003cdiscouraged|perlpolicy/Terminology\u003e. In the far future\nit may get removed entirely, and in the meantime it will not gain new features.\n\nThe return value of the C\u003crules\u003e callback is interpreted as follows:\n\n=over 4\n\n=item An array reference (with at least one element)\n\nA regular L\u003cPSGI\u003e response, except that you may omit either or both the headers\nand body elements. You I\u003cmay not\u003e omit the status.\n\n=item A scalar value that looks like an HTTP status\n\nLike returning a reference to a one-element.\n\nBeware: every subroutine in Perl has a return value, even if you do not return\nanything explicitly. To avoid ambiguities you must return one-element arrays\ninstead of plain values and use an explicit C\u003creturn\u003e at the end of your rules:\n\n return [201] if $_ eq '/favicon.ico';\n s{^/here(?=/|$)}{/there};\n return;\n\n=item A code reference\n\nEquivalent to the L\u003c/C\u003cresponse\u003e\u003e callback in the new interface, with the same\narguments and return values.\n\n=item Any other kind of value\n\nInternal rewrite.\n\n=back\n\n=head2 Porting from the old to the new interface\n\nThere are two major incompatibilities between the interfaces:\n\n=over 4\n\n=item 1.\n\nYou can no longer return status codes as plain scalars, as in C\u003creturn 301\u003e.\nYou B\u003cmust\u003e now C\u003creturn [301]\u003e (which you could before, but didn't have to).\n\n=item 2.\n\nRewriting the response is no longer done by returning a C\u003csub\u003e.\nInstead you must use the C\u003cresponse\u003e attribute.\n\nThis may be inconvient if the function was closing over variables from the\nC\u003crules\u003e callback; in that case you now have to explicitly pass that state\nfrom one callback to the other through the environment hash. However, such\ncode is rare, and in all other cases your code will be more readable under\nthe new interface.\n\n=back\n\n=cut\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fap%2Fplack-middleware-rewrite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fap%2Fplack-middleware-rewrite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fap%2Fplack-middleware-rewrite/lists"}