Is there a way to force $c->uri_for in Catalyst to generate a URI that begins with https?
I've written a web application using Catalyst that has a lot of forms and needs to run over https. There are no hard-coded URLs, everything uses $c->uri_for
or $c->req->uri
. Everything worked great in the development environment using the dev server running over http.
Today, when I went开发者_如何学C ahead and deployed the application, I noticed a problem. The way our production environment is currently setup, client browsers talk to a F5 load-balancer over HTTPS and the F5 talks to the web server on the internal network over HTTP.
[ Browser ] ---HTTPS---> [ F5 ] ---HTTP---> [ Web Server ]
Now, because the web server only gets HTTP
requests, all URIs are generated starting with HTTP. This means:
<form action='[% c.uri_for('/secure/form') %]' method='post'>
becomes:
<form action='http://websitename.org/secure/form' method='post'>
and now all browsers complain you are submitting data over an insecure connection. I need that c.uri_for
to begin with https.
The app needed to go live today, so I did a mass search/replace for all form actions to this:
<form action='[% c.uri_for('/secure/form') | replace('http:', 'https:'%]' method='post'>
Well, now that breaks development, so I conditionalized the form actions based on a config key:
[% IF c.config.production %]
<form action='[% c.uri_for('/secure/form') | replace ('http:', 'https:') %]' method='post'>
[% ELSE %]
<form action='[% c.uri_for('/secure/form') %]' method='post'>
[% END %]
Needless to say, this all just seems wrong on multiple levels. Anyone have a better idea? And is there a way to force $c->uri_for
to generate a URI that begins with https?
Solution
If you're using Catalyst 5.80008 or later, set MyApp->config(using_frontend_proxy => 1);
and simply have your proxy set the X-Forwarded-Port
header. For Catalyst versions prior to 5.80008, still set using_frontend_proxy
so you get the actual client_ip, but to generate the correct URIs have your web server set the environment variable HTTPS
to ON
You might try this configuration option:
MyApp->config(using_frontend_proxy => 1);
It's described in Catalyst's documentation
The following works (tested):
In MyApp.pm, add the following sub:
sub secure_uri_for {
my ($self, @args) = @_;
my $u = $self->uri_for(@args);
$u->scheme('https');
return $u;
}
Now any time you want a guaranteed https, you can call $c->secure_uri_for('whatever')
I don't use Catalyst, but the docs for uri_for
point to the request object's base
method.
I read the source, and found that base
is a read/write method. So, you should be able to squeeze $req->base('https://foo.bar.com/')
into your code somewhere to get your https uris.
Update:
singingfish says that the above advice is incorrect--which wouldn't surprise me at all, it was based on a quick look at TFM. S/He also says that the scheme
method should be set instead. I assume s/he is referring the the uri object's scheme
method.
Further searching turned up HTTPS Tricks on the Catalyst Wiki. It shows an example of setting the scheme on the uri objects returned by the uri_for_action
method. It looks like you would need to set the scheme on every uri you request, all over your code. So, I can't help but feel that the scheme method may not be the best choice.
I also found this thread on the mailing list. Setting base
or setting an environment variable are both recommended methods.
This gives you several avenues of investigation. Good luck.
精彩评论