Importing C::P::RequireSSL 0.01 v0.01
Andy Grundman [Thu, 23 Jun 2005 21:31:52 +0000 (21:31 +0000)]
Build.PL [new file with mode: 0644]
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
META.yml [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/Catalyst/Plugin/RequireSSL.pm [new file with mode: 0644]
t/01use.t [new file with mode: 0644]
t/02pod.t [new file with mode: 0644]
t/03podcoverage.t [new file with mode: 0644]

diff --git a/Build.PL b/Build.PL
new file mode 100644 (file)
index 0000000..58148c9
--- /dev/null
+++ b/Build.PL
@@ -0,0 +1,14 @@
+use strict;
+use Module::Build;
+
+my $build = Module::Build->new(
+    create_makefile_pl => 'passthrough',
+    license            => 'perl',
+    module_name        => 'Catalyst::Plugin::RequireSSL',
+    requires           => { 'Catalyst' => '5.23' },
+    create_makefile_pl => 'passthrough',
+    test_files   => [
+        glob('t/*.t') 
+    ]
+);
+$build->create_build_script;
diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..a76039c
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension Catalyst::Plugin::RequireSSL
+
+0.01    2005-06-08 23:45:00
+        - initial release
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..731a9a7
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,10 @@
+Build.PL
+Changes
+lib/Catalyst/Plugin/RequireSSL.pm
+Makefile.PL
+MANIFEST                       This list of files
+META.yml
+README
+t/01use.t
+t/02pod.t
+t/03podcoverage.t
diff --git a/META.yml b/META.yml
new file mode 100644 (file)
index 0000000..b7a20d3
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,8 @@
+--- #YAML:1.0
+name: Catalyst-Plugin-RequireSSL
+version: 0.01
+author:
+  - Andy Grundman, C<andy@hybridized.org>
+abstract: Force SSL mode on select pages
+license: perl
+generated_by: Module::Build version 0.2604, without YAML.pm
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..51d31fd
--- /dev/null
@@ -0,0 +1,31 @@
+# Note: this file was auto-generated by Module::Build::Compat version 0.03
+    
+    unless (eval "use Module::Build::Compat 0.02; 1" ) {
+      print "This module requires Module::Build to install itself.\n";
+      
+      require ExtUtils::MakeMaker;
+      my $yn = ExtUtils::MakeMaker::prompt
+       ('  Install Module::Build now from CPAN?', 'y');
+      
+      unless ($yn =~ /^y/i) {
+       die " *** Cannot install without Module::Build.  Exiting ...\n";
+      }
+      
+      require Cwd;
+      require File::Spec;
+      require CPAN;
+      
+      # Save this 'cause CPAN will chdir all over the place.
+      my $cwd = Cwd::cwd();
+      my $makefile = File::Spec->rel2abs($0);
+      
+      CPAN::Shell->install('Module::Build::Compat')
+       or die " *** Cannot install without Module::Build.  Exiting ...\n";
+      
+      chdir $cwd or die "Cannot chdir() back to $cwd: $!";
+    }
+    eval "use Module::Build::Compat 0.02; 1" or die $@;
+    use lib '_build/lib';
+    Module::Build::Compat->run_build_pl(args => \@ARGV);
+    require Module::Build;
+    Module::Build::Compat->write_makefile(build_class => 'Module::Build');
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..c9bc78b
--- /dev/null
+++ b/README
@@ -0,0 +1,137 @@
+NAME
+    Catalyst::Plugin::PageCache - Cache the output of entire pages
+
+SYNOPSIS
+        use Catalyst 'PageCache';
+    
+        MyApp->config->{page_cache} = {
+            expires => 300,
+            set_http_headers => 1,
+            auto_cache => [
+                '/view/.*',
+                '/list',
+            ],
+            debug => 1,
+        };
+
+        $c->cache_page( '3600' );
+    
+        $c->clear_cached_page( '/list' );
+
+DESCRIPTION
+    Many dynamic websites perform heavy processing on most pages, yet this
+    information may rarely change from request to request. Using the
+    PageCache plugin, you can cache the full output of different pages so
+    they are served to your visitors as fast as possible. This method of
+    caching is very useful for withstanding a Slashdotting, for example.
+
+    This plugin requires that you also load a Cache plugin. Please see the
+    Known Issues when choosing a cache backend.
+
+WARNINGS
+    PageCache should be placed at the end of your plugin list.
+
+    You should only use the page cache on pages which have NO user-specific
+    or customized content. Also, be careful if caching a page which may
+    forward to another controller. For example, if you cache a page behind a
+    login screen, the logged-in version may be cached and served to
+    unauthenticated users.
+
+    Note that pages that result from POST requests will never be cached.
+
+PERFORMANCE
+    On my Athlon XP 1800+ Linux server, a cached page is served in 0.008
+    seconds when using the HTTP::Daemon server and any of the Cache plugins.
+
+CONFIGURATION
+    Configuration is optional. You may define the following configuration
+    values:
+
+        expires => $seconds
+    
+    This will set the default expiration time for all page caches. If you do
+    not specify this, expiration defaults to 300 seconds (5 minutes).
+
+        set_http_headers => 1
+    
+    Enabling this value will cause Catalyst to set the correct HTTP headers
+    to allow browsers and proxy servers to cache your page. This will
+    further reduce the load on your server. The headers are set in such a
+    way that the browser/proxy cache will expire at the same time as your
+    cache. The Last-Modified header will be preserved if you have already
+    specified it.
+
+        auto_cache => [
+            $uri,
+        ]
+    
+    To automatically cache certain pages, or all pages, you can specify
+    auto-cache URIs as an array reference. Any controller within your
+    application that matches one of the auto_cache URIs will be cached using
+    the default expiration time. URIs may be specified as absolute: '/list'
+    or as a regex: '/view/.*'
+
+        debug => 1
+    
+    This will print additional debugging information to the Catalyst log.
+    You will need to have -Debug enabled to see these messages.
+
+  METHODS
+    cache_page
+        Call cache_page in any controller method you wish to be cached.
+
+            $c->cache_page( $expire );
+
+        The page will be cached for $expire seconds. Every user who visits
+        the URI(s) referenced by that controller will receive the page
+        directly from cache. Your controller will not be processed again
+        until the cache expires. You can set this value to as low as 60
+        seconds if you have heavy traffic to greatly improve site
+        performance.
+
+    clear_cached_page
+        To clear the cached value for a URI, you may call clear_cached_page.
+
+            $c->clear_cached_page( '/view/userlist' );
+            $c->clear_cached_page( '/view/.*' );
+    
+        This method takes an absolute path or regular expression. For
+        obvious reasons, this must be called from a different controller
+        than the cached controller. You may for example wish to build an
+        admin page that lets you clear page caches.
+
+    dispatch (extended)
+        Bypass the dispatch phase and send cached content if available
+
+    finalize (extended)
+        Cache the page output if requested.
+
+    setup
+        Setup default values.
+
+    _page_cache_key
+        Returns a cache key for the current page.
+
+KNOWN ISSUES
+    It is not currently possible to cache pages served from the Static
+    plugin. If you're concerned enough about performance to use this plugin,
+    you should be serving static files directly from your web server anyway.
+
+    Cache::FastMmap does not have the ability to specify different
+    expiration times for cached data. Therefore, if your
+    MyApp->config->{cache}->{expires} value is set to anything other than 0,
+    you may experience problems with the clear_cached_page method, because
+    the cache index may be removed. For best results, you may wish to use
+    Cache::FileCache or Cache::Memcached as your cache backend.
+
+SEE ALSO
+    Catalyst, Catalyst::Plugin::Cache::FastMmap,
+    Catalyst::Plugin::Cache::FileCache, Catalyst::Plugin::Cache::Memcached
+
+AUTHOR
+    Andy Grundman, "andy@hybridized.org"
+
+COPYRIGHT
+    This program is free software, you can redistribute it and/or modify it
+    under the same terms as Perl itself.
+
diff --git a/lib/Catalyst/Plugin/RequireSSL.pm b/lib/Catalyst/Plugin/RequireSSL.pm
new file mode 100644 (file)
index 0000000..590fd31
--- /dev/null
@@ -0,0 +1,195 @@
+package Catalyst::Plugin::RequireSSL;
+
+use strict;
+use base qw/Class::Accessor::Fast/;
+use NEXT;
+
+our $VERSION = '0.01';
+
+__PACKAGE__->mk_accessors( '_require_ssl' );
+
+=head1 NAME
+
+Catalyst::Plugin::RequireSSL - Force SSL mode on select pages
+
+=head1 SYNOPSIS
+
+    use Catalyst 'RequireSSL';
+    
+    MyApp->config->{require_ssl} = {
+        https => 'secure.mydomain.com',
+        http => 'www.mydomain.com',
+        remain_in_ssl => 0,
+    };
+
+    $c->require_ssl;
+
+=head1 DESCRIPTION
+
+Use this plugin if you wish to selectively force SSL mode on some of your web pages, 
+for example a user login form or shopping cart.
+
+Simply place $c->require_ssl calls in any controller method you wish to be secured. 
+
+This plugin will automatically disable itself if you are running under the standalone
+HTTP::Daemon Catalyst server.  A warning message will be printed to the log file whenever
+an SSL redirect would have occurred.
+
+=head1 WARNINGS
+
+If you utilize different servers or hostnames for non-SSL and SSL requests, and you rely
+on a session cookie to determine redirection (i.e for a login page), your cookie must
+be visible to both servers.  For more information, see the documentation for the Session plugin
+you are using.
+
+=head1 CONFIGURATION
+
+Configuration is optional.  You may define the following configuration values:
+
+    https => $ssl_host
+    
+If your SSL domain name is different from your non-SSL domain, set this value.
+
+    http => $non_ssl_host
+    
+If you have set the https value above, you must also set the hostname of your non-SSL
+server.
+
+    remain_in_ssl
+    
+If you'd like your users to remain in SSL mode after visiting an SSL-required page, you can
+set this option to 1.  By default, users will be redirected back to non-SSL mode as soon as
+possible.
+
+=head2 METHODS
+
+=over 4
+
+=item require_ssl
+
+Call require_ssl in any controller method you wish to be secured.
+
+    $c->require_ssl;
+
+The browser will be redirected to the same path on your SSL server.  POST requests
+are never redirected.
+
+=cut
+
+sub require_ssl {
+    my $c = shift;
+    
+    $c->_require_ssl( 1 );
+      
+    unless ( $c->req->secure || $c->req->method eq "POST" ) {
+        if ( $c->config->{require_ssl}->{disabled} ) {
+            $c->log->warn( "RequireSSL: Would have redirected to " . $c->_redirect_uri( 'https' ) );
+        } else {
+            $c->res->redirect( $c->_redirect_uri( 'https' ) );
+        }
+    }
+}
+
+=item finalize (extended)
+
+Redirect back to non-SSL mode if necessary.
+
+=cut
+
+sub finalize {
+    my $c = shift;
+    
+    # redirect unless:
+    # we're not in SSL mode,
+    # it's a POST request,
+    # we're already required to be in SSL for this request,
+    # or the user doesn't want us to redirect
+    unless ( !$c->req->secure
+      || $c->req->method eq "POST"
+      || $c->_require_ssl
+      || $c->config->{require_ssl}->{remain_in_ssl} ) {
+          $c->res->redirect( $c->_redirect_uri( 'http' ) );
+    }
+    
+    return $c->NEXT::finalize(@_);    
+}
+
+=item setup
+
+Setup default values.
+
+=cut
+
+sub setup {
+    my $c = shift;
+    
+    $c->NEXT::setup(@_);
+    
+    # disable the plugin when running under certain engines which don't support SSL
+    # XXX: I didn't include Catalyst::Engine::Server here as it may be used as a backend
+    # in a proxy setup.
+    if ( $c->engine eq "Catalyst::Engine::HTTP" ) {
+        $c->config->{require_ssl}->{disabled} = 1;
+        $c->log->warn( "RequireSSL: Disabling SSL redirection while running under " . $c->engine );
+    }
+}
+
+=item _redirect_uri
+
+Generate the redirection URI.
+
+=cut
+
+sub _redirect_uri {
+    my ( $c, $type ) = @_;
+    
+    # XXX: Cat needs a $c->req->host method...
+    # until then, strip off the leading protocol from base
+    unless ( $c->config->{require_ssl}->{$type} ) {
+        my $host = $c->req->base;
+        $host =~ s/^http(s?):\/\///;
+        $c->config->{require_ssl}->{$type} = $host;
+    }
+    
+    $c->config->{require_ssl}->{$type} .= '/'
+        unless ( $c->config->{require_ssl}->{$type} =~ /\/$/ );
+    
+    my $redir = $type . '://' . $c->config->{require_ssl}->{$type} . $c->req->path;
+    if ( scalar keys %{ $c->req->params } ) {
+        my @params = ();
+        foreach my $k ( sort keys %{ $c->req->params } ) {
+            push @params, $k . "=" . $c->req->params->{$k};
+        }
+        $redir .= "?" . join "&", @params;
+    }
+    
+    return $redir;
+}
+
+=back
+
+=head1 KNOWN ISSUES
+
+When viewing an SSL-required page that uses static files served from the Static plugin, the static
+files are redirected to the non-SSL path.  It may be possible to work around this by checking the
+referer protocol, but currently there is no way to determine if a file being served is static content.
+
+For best results, always serve static files directly from your web server without using the Static
+plugin.
+
+=head1 SEE ALSO
+
+L<Catalyst>
+
+=head1 AUTHOR
+
+Andy Grundman, C<andy@hybridized.org>
+
+=head1 COPYRIGHT
+
+This program is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
+
+1;
diff --git a/t/01use.t b/t/01use.t
new file mode 100644 (file)
index 0000000..b47fbda
--- /dev/null
+++ b/t/01use.t
@@ -0,0 +1,3 @@
+use Test::More tests => 1;
+
+use_ok('Catalyst::Plugin::RequireSSL');
diff --git a/t/02pod.t b/t/02pod.t
new file mode 100644 (file)
index 0000000..1647794
--- /dev/null
+++ b/t/02pod.t
@@ -0,0 +1,7 @@
+use Test::More;
+
+eval "use Test::Pod 1.14";
+plan skip_all => 'Test::Pod 1.14 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_files_ok();
diff --git a/t/03podcoverage.t b/t/03podcoverage.t
new file mode 100644 (file)
index 0000000..d91be5e
--- /dev/null
@@ -0,0 +1,7 @@
+use Test::More;
+
+eval "use Test::Pod::Coverage 1.04";
+plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_coverage_ok();