HTTPS tricks
Using HTTPS with the catalyst built in server
The built in server is extreemly useful during development, but it does not support HTTPS. These are some tricks that let you develop using https more easily.
Using pound to handle the https connections
pound is a very lightweight load balancer which can be used to decrypt https traffic and then forward it to a http server for processing. The following bash script will check for prerequisites and then start pound.
More details on pound can be found at http://www.apsis.ch/pound/
It should be run like this:
bash> path/to/script/run_pound_for_dev.bash 3000 3001
The first argument is the http port to forward to, the second the https port to listen on. We usually can't use '80' and '443' (the defaults) as we are not running as root.
The script contents:
#!/bin/bash
# Change to the directory that this script is in
cd `dirname $0`
# capture the port numbers to use
HTTP_PORT=$1
HTTPS_PORT=$2
echo "HTTP_PORT: $HTTP_PORT, HTTPS_PORT: $HTTPS_PORT";
# echo out the config to the config file - put in the correct port numbers
echo "
Daemon 0
LogLevel 2
ListenHTTPS
Address 0.0.0.0
Port ${HTTPS_PORT}
Cert \"server_dev.pem\"
AddHeader \"X-Secure-Connection: true\"
Service
BackEnd
Address 127.0.0.1
Port $HTTP_PORT
End
End
End
" > pound_dev.cfg
# create the certificate if needed
if test ! -e server_dev.pem; then
echo " ---- creating the required certificate: server_dev.pem ---- ";
openssl \
req \
-new \
-x509 \
-days 365 \
-nodes \
-out server_dev.pem \
-keyout server_dev.pem
echo;
echo "---- certificate created ----- ";
echo;
fi;
# start pound
/usr/sbin/pound -v -f pound_dev.cfg -p pound_dev.pid
Starting pound when you start the server
To start pound whenever you start the test server put the following in your myapp_server.pl script:
# we want to start a pound process to handle the
if ( my $child_pid = fork() ) {
warn "Pound has been started on pid $child_pid.\n";
} else {
my $http_port = $port;
my $https_port = $port + 1;
exec "misc/pound/run_pound_for_dev.bash $http_port $https_port";
}
This should come just after the pod2usage(1) if $help line.
Working out if the request was secure
As all traffic now reaches the catalyst server over http we need some other way of determining if the traffic was originally https. In the pound config you'll note the AddHeader line which will add the following header to all requests that pound forwards for us:
X-Secure-Connection: true
We can now check for this header in our app and use it to toggle the secure flag on the request.
This should go in your MyApp.pm file:
=head2 prepare_headers
$c->prepare_headers;
We want to pretend that the connection was secure if the header
C<X-Secure-Connection> is set to a true value. This allows the tedious HTTPS
encryption/decryption/negotiating to be dealt with by the load balancers.
=cut
sub prepare_headers {
my $c = shift;
# run the other bits first
$c->maybe::next::method();
# check for the X-Secure-Connection header
$c->req->secure(1)
if $c->req->header('X-Secure-Connection');
return 1;
}
Creating secure links
This will vary depending on your app, but the following code might be a useful starter:
Again, in your MyApp.pm file:
my $USE_TESTING_HTTPS_PORT = undef; # Should we use the testing port?
# make changes to config for the development environment
my $engine = $ENV{CATALYST_ENGINE} || '';
if ( $engine =~ m{ ^ HTTP (\:\:Restarter)? }x ) {
# we should be running pound for the tests to work
$USE_TESTING_HTTPS_PORT = 1;
}
=head2 redirect_to_secure
$c->redirect_to_secure();
Redirect the current request to the secure url. On live this is just
replacing the 'http' with 'https'. On the catalyst test server it is also
changing the port to C<$http_port + 1> which is where pound is expected to
be running.
=cut
sub redirect_to_secure {
my $c = shift;
# get a copy of the url
my $uri = $c->req->uri->clone;
# change the protocol
$uri->scheme('https');
# change the port if needed
if ($USE_TESTING_HTTPS_PORT) {
$uri->port( $uri->port + 1 );
}
# debug output
$c->log->debug(
sprintf(
"redirecting from %s to %s",
$c->req->uri->as_string, $uri->as_string
)
) if $c->debug;
# redirect to this new url
$c->res->redirect($uri);
return;
}
Showing changes from previous revision. Removed | Added

