0
Help us understand the problem. What are the problem?

posted at

webrickでproxyを作ったときレスポンスのbodyが文字列として取り出せない

ちょっと悩んだのでメモ。

あるWebアプリがどんなパラメータの受け渡しをしてるのか覗いてやろうと思って WEBrick::HTTPProxyServer でプロキシサーバを作りました。その時レスポンスのボディ (WEBrick::HTTPResponse オブジェクト) がなんか Proc オブジェクトになってたので中身が覗けません…。で、こういうふうにやれば覗けましたというメモです。

だめな例

s = WEBrick::HTTPProxyServer.new(
      Port: 8080,
      ProxyContentHandler: ->(_req, res) {
        puts res.body # ここが問題。これじゃ覗けない
      })
Signal.trap('INT') do
  s.shutdown
end
s.start

だめな例では #<Proc:0x00007f8a06977628 (省略)/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/webrick-1.7.0/lib/webrick/httpproxy.rb:344 (lambda)> とか言う文字列が出力されます。

res.body の中身を見るとなんかパラメータを一個取り (xとします) bodyを保持しているバッファ (body_tmp: 実体は Array) からから読み出して x に write で書いていたので StringIO オブジェクトを渡してやればいいかなと思ってこうしました。

良い例

s = WEBrick::HTTPProxyServer.new(
      Port: 8080,
      ProxyContentHandler: ->(_req, res) {
        sio = StringIO.new(String.new, 'r+')
        res.body.(sio)
        sio.rewind
        res.body = sio.read
        puts res.body
      })
Signal.trap('INT') do
  s.shutdown
end
s.start

これで body が見えました。res.body に読んだ結果を改めて代入しているのは、こうしないと UA 側に body が渡らないからです (body_tmp.shift で破壊的に読み出してるので残らない)。

あともう一つ、StringIO オブジェクトを作るときに '' などリテラルではなく String.new を渡している理由を説明します。今どき

# frozen_string_literal: true

を普通にやってると思うんですが、これだとリテラルで作った String が freeze されてるので書けないんですよ。ということで 'r+' モードで作ろうとしても permission denied になっちゃいます (よくできてる)。ということで freeze されてない String オブジェクトを得るのに手っ取り早い方法が String.new なのでした。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?