Tech Notes

H2OでHTTPからHTTPSにリダイレクトするconfig

H2O公式が提供してる設定サンプルが目論見どうりの動作をしなかったので自力でなんとかした。1/13 追記

プロジェクト公式リポジトリのWikiでは「redirect: localhost:443」とか書けばうまいことやってくれるっぽく書いてあるのでそのようにやってみたところ、上手く動かない。

レスポンスヘッダを確認したところ、「Location: localhost:443」ってなんにもなってないよ!となったため、mrubyでなんとかしました。いざというとき設定ファイルにプログラム直書きでごりごり書けるのはとても便利ですね。

hosts:
  "foolslab.net:80":
    listen:
      port: 80
    paths:
      "/":
        mruby.handler: |
          proc {|env|
            [302, {"Location" => ('https://' << (env['HTTP_HOST'].split(':')[0]) << env['PATH_INFO'])}, [""]]
          }

Rubyはまともに触ったことほとんどなかったので、入門サイト読みながらなんとか縫い合わせました。まともに学ぶのが億劫だったことをここに告白します。一応後人のために得た知識を雑に紹介しておきます。

なんかRackとかいう概念があるらしい

よく分かんないけどWebサーバとRubyプログラムを繋ぐ為のAPI規約みたいなものっぽいです。H2Oもこれに準拠したものを実装しているらしく、設定ファイルとかに書いたmrubyのプログラムはこれに従って読み込んでやってくれるっぽいです。

具体的には、プログラミング経験あれば上のブツの最後3行読めば何となく分かると思いますが、「環境変数を引数にとってHTTPステータスコード・リクエストヘッダ・本文の三つ組みデータを返す関数オブジェクト」を作ってワーワーやるっぽいです。

あ、Ruby未経験の方には気持ち悪いと思うんですが、Rubyの関数というものはreturnとか書かなくても、関数の最後に書いた式が返り値になるそうです。9行目はreturn [302, {"Location" => ('https://' << (env['HTTP_HOST'].split(':')[0]) << env['PATH_INFO'])}, [""]]; みたいに解釈してもらえれば結構です。きもーい!(C++er並感)

ソースコードこまごま解説

という名の私用Ruby知識備忘録です。

  • proc{}

関数オブジェクト(Procクラスのインスタンス)を作る構文らしいです。他にProc.new{}とかlambda{}とか別の書き方もあるらしく、lambdaは微妙に挙動が違うらしいです。なお、{の直後に|変数名, 変数名, ...|みたいのを書くと引数ということになるっぽいです。上の例ではenvですね。個人的に引数リストは{の前にあって欲しい…

  • [hoge1, hoge2, ...]

ただの配列リテラルです。Rackオブジェクトが返す配列データは、0番目:HTTPステータスコード、1番目:HTTPレスポンスヘッダ、2番目:HTTP本文データ、みたいな感じで決められてるぽいです。

  • {"hoge1" => "foo1", "hoge2" => "foo2", ...}

連想配列リテラルです。Rubyでは連想配列のことをハッシュと呼ぶらしいです。ぱいてょんではディクショナリだったりC++のSTLではmapだったりして連想配列の呼び名はネーミングセンスのサラダボウルじゃないかと思います。きっとバベルの塔の建材は連想配列です。

  • env['HTTP_HOST']、env['PATH_INFO']

ただの環境変数。ググれば画面に湧く

  • .split(':')[0]

env['HTTP_HOST']"foolslab.net"が入っていれば"Location: https://foolslab.net/xxxx/"とかみたいにいけるのですが、"foolslab.net:80"とか入ってると"Location: https://foolslab.net:80/xxxx/"とかになってしまい、80番ポートをHTTPSで叩かれても困るのでこのようにしました。

splitは文字列を特定の文字で区切ってくれる関数で、'abc:def:ghi'.split(':')とかってやれば['abc', 'def, 'ghi']とか返ってきます。':'で区切って最初の要素だけ取り出すことでポート番号部分を切りました。

  • [""]

本文。からっぽ。高校の課題やテストで吐くほど文字書いてるのになんでこんなところでまで作文しないといけないんですか?

最後に

この中にまともなRuby技術者やWebデベロパがいて記事内容に苦言があったらコメントぶん投げてください。丁寧にぶち直します。

追記

もっとまともな書き方があったみたいです。

https://qiita.com/VTRyo/items/604e9bc793a3f91f3cfd

redirect: https://xxxxx.jp みたいにやるだけで良かった模様。しかしあの設定サンプルが想定通りに動かないことには変わりがない。何なのだ。