それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

WEBRickの構造を読み解く---Proxy編

性懲りもなく、手を広げているTakuyaです。こんばんは。
WEBRickに手を出してしまいました。


るびまの記事に従いproxyサーバーを作ってみました。そして次に、プロキシにBASIC認証を書けてみました。

WEBRickサーバーは予想に反し、動作早いんだもの。いろんなことに使ってみたくなった。

BASIC認証付のWEBRick Proxyサーバ

認証パスは akiko/wada になる。

proxy-auth.rb
#!/usr/bin/env ruby
KCODE='u'

require 'webrick'
require 'webrick/httpproxy'
require 'stringio'
require 'zlib'


auth_proc = Proc.new(){|req,res|
     WEBrick::HTTPAuth.proxy_basic_auth(req,res,'proxy') do |user,pass|
             user == 'akiko' and pass == 'wada' #この部分で認証。
     end
}

s = WEBrick::HTTPProxyServer.new({
     :Port => 8080,
     :ProxyContentHandler => handler,
     :ProxyAuthProc => auth_proc,
})


#SIGINIを補足する
Signal.trap('INT') do
     #補足したらシャットダウン
     s.shutdown
end

#サーバー起動
s.start

あとは、このプロキシをとおしてWEBを閲覧すればいい。

さて、とても楽ちんなのですが。動作原理がイマイチ分からない。

結論から言えば、認証失敗したら例外を投げる。

  1. :ProxyAuthProcに登録された関数(Proc)はリクエスト処理前に実行される。
  2. WEBrick::HTTPAuth.proxy_basic_authは例外を投げる。
  3. 例外はWEBrick::HTTPStatus::ProxyAuthenticationRequiredである。
  4. Basic認証をブラウザに要求する。

この流れである。

特に例外を使ってレスポンスを書き換えるのが鮮やかな処理でWEBRickの設計に惚れた。が、同時にドキュメントがなく不親切、わかりにくいなと思った。

どうやらこのようなことが言えそうだ

WEBRickの設計思想
HTTPのエラーは例外で処理するってことらしい。

呼び出しの流れをFollowしてみよう。

  1. s.startでサーバーが起動する。
    • WEBrick::HTTPProxyServerは親クラスのStartを継承している。
    • HTTPProxyServerのstartが実行される。
    • スレッド処理を行なう準備をする。
    • 各スレッドがrunを実行する。HTTPProxyServer.serviceはrun内部で処理される。
  2. リクエストがやってくる。
    1. serviceに処理が渡る
    2. proxy_serviceに処理が渡る
    3. proxy_authが呼び出される
    4. 最初の呼び出しだと、認証に失敗するので例外をRaiseする。
    5. HTTPServer.run 68行目 "rescue HTTPStatus::Error => ex"でレスポンスをエラー内容に書き直す
    6. ブラウザにレスポンスを返す。