Mojoliciousのプレースホルダでドットを含むパスをキャプチャしたくない時の話。

全然別のタイトルで記事書いたのですが、内容が間違いまくってたのと愚痴っぽくてひどかったので消しました。30分位で消したから多分誰も見てないんじゃないでしょうか。

Mojoliciousの通常のプレースホルダはドットとスラッシュをキャプチャせず、含んでいた場合はルーティングに失敗します。が、その挙動を期待していたのに、ルーティングに失敗せずに200OKを返してしまうパターンがあってはまりました。
具体的に言うと、/standard/:nameのようなルートを設定していた場合、/standard/hello.htmlとか、hello.jsonのようなパスを設定されると、普通に200OKが返ってしまいます。
タチが悪いことに、param(‘name’)の値はhelloを返すので、paramの値で分岐するようなコードにしてると、意図しないルートをガード出来てないことになかなか気づきません。
具体例は以下。Perlはv5.16.3、Mojoliciousはv7.05です。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use Mojolicious::Lite;

# リラックスプレースホルダ
get '/relax/#name' => sub{
        my $self = shift;
        return $self->render(json =>{param => $self->param('name'), format => $self->stash('format')});
} => 'r';
# /relax/hello.json:
# {"param":"hello.json","format":null}

# 普通のプレースホルダ
get '/standard/:name' => sub{
        my $self = shift;
        return $self->render(json =>{param => $self->param('name'), format => $self->stash('format')});
} => 's';
# /standard/hello.json: 
# {"format":"json","param":"hello"}

# 普通のプレースホルダ+format無効化
get '/standard_disable_format/:name' => [format => 0] => sub{
        my $self = shift;
        return $self->render(json =>{param => $self->param('name'), format => $self->stash('format')});
} => 'sd';
# /standard_disable_format/hello.json:
# status:404

普通のプレースホルダでドットを含んだ値を絶対キャプチャしたくない場合は、[format => 0]を指定しようと思いました。
MojoliciousとかMojolicious::Lite側の仕様は以下。
Mojolicious::Guides::Routing – Routing requests
Mojolicious::Lite – search.cpan.org

splapiはいろいろあってこのルートはガードする必要があるので、v1.12で修正しています。

Bash on Ubuntu on WindowsでMojolicious::LiteとかNet::Twitter::Liteを動かす。

Windows 10 Anniversary Update(Windows 10 バージョン 1607)を適用したので、Bash on Ubuntu on Windowsを使ってみました。念には念を入れて、アップグレードツールを使わずにWindows Updateから適用できる段階でアップデートしたのですが、失敗してOSごと起動しなくなったりしました。相変わらずですね。
私の環境の場合、MacTypeとセキュリティソフトとタッチパッドのドライバが原因だったので、セーフモードで無理やり起動させて原因のアプリを停止させた後、ツールからアップデートしたらうまくいきました。
自分のマシンだとWindows Helloは予想通りサポートされなかったので、使いたかった機能がbashだけになりました。
OSビルドは14393.51です。

Tech TIPS:Windows 10のLinux/Ubuntu互換環境でbashを使う – @IT
ここを見ながらbashを使えるようにしてみました。ちなみに、私の環境だと、bashを使うときにコマンドプロンプトのオプションから「従来のコンソールを使う」のチェックボックスを外さないと動きませんでした。
Bash on ubuntu on Windowsが起動できません。 – マイクロソフト コミュニティ

sudoすると、「名前解決が出来ません」と言われてしまうので、/etc/hostsに「127.0.0.1 ホスト名」を追加しておきました。
ちなみにPerlはv5.18.2でした。メイン環境のさくらVPS/CentOS 7環境がv5.16.3なので、ubuntuのほうがバージョン上ですね。
ubuntuのバージョンは以下のとおり。

➜  ~ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"

ちなみにoh-my-zsh使ってみたのですが、(やっぱり)文字化けしちゃいました、

ホームディレクトリの実体は以下にありました。

C:\Users\ユーザ名\AppData\Local\lxss\home\ubuntuのユーザ名

cpanでモジュールを導入しようとした

最初はcpanでMojoliciousを入れようとしたのですが、「Warning: the following files are missing in your kit」みたいな感じで全然makeできないので、cpanは使えませんでした。cpanmならいけるかもしれないけどめんどくさいので試してません。

apt-getで導入する

ubuntuだとapt-getでperlのモジュールを導入できるので、sudo apt-getで導入してしまいました。

➜  ~ sudo apt-get install libmojolicious-perl
➜  ~ sudo apt-get install libnet-twitter-lite-perl

無事導入できました。

Mojolicious:Liteを動かしてみる

以下のスクリプトをhypnotoadで実行して、http://localhost:8181にアクセスしてみました。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use Mojolicious::Lite;
app->config(
  hypnotoad => {
    listen => ['http://*:8181'],
    },
);

get '/' => sub {
  my $self = shift;
  return $self->render(json =>{test => "hello world"});
} => 'index';
app->start;

bashから動かすMojoLite

bashから動かすMojoLite


わーい動いた。

Net::Twitter::Liteを動かしてみる

以下のスクリプトを動かしてみました。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use Net::Twitter::Lite::WithAPIv1_1;
use Encode;

my $nt = Net::Twitter::Lite::WithAPIv1_1->new(
consumer_key => $consumer_key,
consumer_secret => $consumer_key_secret,
access_token => $access_token,
access_token_secret => $access_token_secret,
ssl => 1
);

my $tl = $nt->user_timeline();

for my $status(@$tl){
    print encode_utf8($status->{text} ."\n");
}

コンソールから実行してみる

コンソールから実行してみる


わーい動いた。

試したけどできなかったこと

mongodb3は導入できませんでした。以下のStackOverflowの記事と同じ症状です。
Windows 10 Linux Subsystem. How to install MongoDB – Stack Overflow

感想

VirtualBoxでやれ。
ちなみにrm -rfしたらどうなるのかなーと思ったら、やっぱり試してる人がいて「あっ…」てなりました。
`rm -rf /` on Bash on Ubuntu on Windows – Qiita

グローバルIPの8080ポートにアクセスするとルータの設定画面が見える。

私の使っているルータは、192.168.0.1(=ルータのアドレス)の80ポートにアクセスすると、ルータの設定画面が見えるタイプです。
IPマスカレードで、80と443ポートはRaspberry Piにアクセスされるようにしています。が、操作を間違って自分のグローバルIPの8080ポートにアクセスしてみたら、なぜかルータの設定画面が出てきて死ぬほどビビりました。8080ポートなんて設定のどこにも出てないんですがこれは。ためしにルータの8080ポートにアクセスしましたがrefuseされるし謎です。

調べてみたら以下のケースがぴったり当てはまりました。
グローバルIPでルータの設定画面が開いてしまう – .自宅サーバを公開している… – Yahoo!知恵袋
グローバルIPアドレスについて – その他(インターネット接続) 締切済 | 教えて!goo

WAN側のIPアドレス(グローバル)にLAN内からアクセスすると
ルータがちゃんとIPマスカレードを行わないで自分自身のそのポートを
返してしまう場合があります。

使っているルータの仕様のページに詳しいことが書いてなかったのでなんともですが、少なくとも発生している事象に関してはこの挙動に当てはまります。

LAN内からWAN側のIPアドレスの8080ポートにアクセスすると、ルータ自身の8080ポートにアクセスすることになるんですね。試しにLAN外の環境からIPアドレス:8080にアクセスすると、想定通りrefuseされました。

ルータの設定アプリはルータ自身の8080ポート(外からアクセス不可)で動いていて、80ポート(外からアクセス可)にアクセスすると設定アプリが見えるということですね。リバースプロキシ処理は自前でやってるんでしょうか。
ためしに22とかそれっぽそうなポートにアクセスしてみましたが、全部動いてないみたいでした。残念です。(何が)

将来8080ポート開けたときはLAN外から動作確認しないといけないですね。困った困った。