Mojoliciousで、必ずhttpsの状態でアクセスされるように、こんな感じのコードを書いていたのですが、思ったように動かなくて困りました。
schemeの部分がhttpsにならなくて、無限ループになっていました。

1
2
3
4
5
6
7
8
# NG
if ( $self->req->is_secure ) {
$self->redirect_to('/login');
}
else {
my $url = $self->url_for('/login')->scheme('https');
$self->redirect_to($url->to_abs);
}

schemeは属性(attribute)という風になっていたし、オブジェクトの中身を見ても、schemeは値を持っているように見えたので、何故変更できないんだろう、と思っていました。
色々試しているうちに、to_absが文字列を返すのではないことに気づきました。
なんとなく、文字列を返すメソッドだと思っていたのですが、実際にはオブジェクトを返しています。
文字列を返しているように見えたのは、実際にはto_stringが呼ばれていたからです。
敗因は、to_absが何を返すのかを理解できていなかった事です。
実は、to_absを呼んだ時点で、現在のbaseになるURLがcloneされるので、先に設定した(つもりの)schemeが無視されてしまうようです。
つまり、schemeを設定しようと思えば、まずto_absで絶対URLオブジェクト(?)にしておいてからやれば良い、ということですね。

1
2
3
4
5
6
7
8
# OK
if ( $self->req->is_secure ) {
$self->redirect_to('/login');
}
else {
my $url = $self->url_for('/login')->to_abs->scheme('https');
$self->redirect_to($url);
}

思い込みって怖いですね。