LoginSignup
126
120

More than 5 years have passed since last update.

クライアントからやってくる本物のHTTPリクエストをダンプする

Last updated at Posted at 2014-03-06

Rack限定ならむかし rack-spyup というものを書いた。自分で使ってみたけどJSON APIのデバッグとかだと革命的に便利だと思う。

ただ、Rackに到達する前にリクエストがお亡くなりになったりとか、そもそもサーバルビーじゃないしとかあると思うので、もっと汎用的な感じでダンプする手順をメモしてみる。

リクエストが来たら内容を全部ダンプするHTTPサーバを作る

Rubyに標準添付されている、WEBrickの基本的な機能で割と簡単に作れる。

http-dumper.rb
# -*- coding: utf-8 -*-
require 'optparse'
require 'webrick'
require 'json'
options = ARGV.getopts("p:", "port:")

# The :monkey: raises
# cf. http://d.hatena.ne.jp/vividcode/20110505/1304618393
class WEBrick::HTTPServlet::ProcHandler
  alias do_PUT    do_POST
  alias do_DELETE do_POST
end

HORIZON = "\e[31m" + ("#" * 72) + "\e[0m"

def dump_http_request(req)
  puts HORIZON
  puts req.request_line
  puts req.raw_header
  puts
  if body = req.body
    puts body.lines.map{|line| line.gsub /[[:cntrl:]]/, '' }
  else
    puts "\e[35m*** Empty request body (maybe it is GET) ***\e[0m"
  end
  puts HORIZON
  puts
end

srv = WEBrick::HTTPServer.new(
  :BindAddress => "0.0.0.0",
  :Port => (options["p"] || options["port"] || raise("Need option -p=PORT")).to_i,
)

srv.mount_proc "/" do |req, res|
  dump_http_request(req)

  res.content_type = "application/json"
  res.body = {return: "OK"}.to_json
end

Signal.trap('INT') { srv.shutdown }
srv.start

dump_http_request が冗長だが(しょうがない)、WEBrick自体は簡単に扱えることが分かると思う。

これをターミナル(1)で起動しとく:

$ ruby http-dumper.rb  -p 3002

リクエストをクローンして二つのサーバに送りつけるひとを作る

かっこ良くGoの gor を使おうとしたが、Macだとちゃんと動かない感じがする。

今回は手軽さ重視で kage を使い、gorコマンドと同じようなことをさせてみる。 gem install kage した後:

kage-front.rb
require 'optparse'
require 'kage'

options = ARGV.getopts("p:", "port:", "backend-port:", "dumper-port:")

Kage::ProxyServer.start do |server|
  server.port = (options["p"] || options["port"] || raise("Need option -p=PORT")).to_i
  server.host = '0.0.0.0'
  server.debug = false

  server.add_master_backend(:dev, 'localhost', options["backend-port"])
  server.add_backend(:dump, 'localhost', options["dumper-port"])

  server.on_select_backends do |request, headers|
    # アセットまでdump serverに送るのはうざったいので適当に振り分ける
    is_asset = request[:path] =~ /\.(ico|js|css|gif|png|jpe?g)$/
    is_asset ? [:dev] : [:dev, :dump]
  end

  puts "Server is listening 0.0.0.0:#{server.port}"
end

これもターミナル(2)で立ち上げ。

$ ruby kage-front.rb -p 3000 --backend-port=3001 --dumper-port=3002

あとは分かるな

検査したいアプリを 3001 番ポートでターミナル(3)に立ち上げること。Railsなら rails s -p 3001

アクセスする

http://localhost:3000 にいつも通りアクセスする。そうすると、いつも通りのウェブサービスが見える...

一方で、ターミナル(1)ではリクエストの内容がダンプされているのであった!

httpdump.png

Usage

普通HTTPリクエストがそもそも壊れてるって少ないと思うけど、今回はジャバを触っていたらどうも壊れてしまっていたのでこういう感じでチェックしていた。参考にしてください。

ブラウザならデベロッパツールでいいけど、HTTPってやっぱいろんなクライアントから叩くと思うんで...。

FAQ

ngrep でいいじゃん

そうですね。tcpflowも便利でいいですね。

ただまあ、一応、そもそも「HTTPリクエストをクローンする」というのが便利かなと思ったのでメモがてら書いてみた感じでござる。あと、APIならともかくWebサービスだとアセットへのアクセスも全部出てしまってノイズっぽいし、このやりかただと正規表現などで適当に絞れると思う。

追記

gemの形でインストールできるようにした ので、bundlerなど使って入れてみて利用できるようになりました(rubygems.org には置かない予定です)。

126
120
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
126
120