Help us understand the problem. What is going on with this article?

rack middlewareをざっくり触ってみた

More than 5 years have passed since last update.

概要

webアプリでとあるパスへのリクエストをフックしてゴニョゴニョする。
そんな方法ないかなぁと思っていたらタイムリーな記事を見つけた。

開発環境でのみ、リクエスト毎になんか処理をフックしたい in Ruby

しかしrack middlewareってどんなもの?状態なので勉強からスタート。

rack middlewareの簡単なお勉強

Rackミドルウェアの作り方を勉強した
ここみたら何となく分かった。

簡単なmiddlewareを書いてみる

/hogeにアクセスが来たら、"hogehoge"を返すmiddleware。
元のアプリに/hogeの処理が定義してあっても、その処理を通さずにクライアントへ結果を返す。
そんなmiddlewareを書いてみた。

my_rack_middleware.rb
class MyRackMiddelware
  def initialize(app)
    @app = app 
  end 

  def call(env)
    if env["PATH_INFO"] == '/hoge'
      res = []
      res[0] = 200 
      res[2] = [ "hogehoge" ]
      content_length = res[2].inject(0) do |sum, content|
        sum + content.bytesize
      end 
      res[1] = { "Content-Type"           => "text/html;charset=utf-8",
                 "Content-Length"         => content_length.to_s,
                 "X-XSS-Protection"       => "1; mode=block",
                 "X-Content-Type-Options" => "nosniff",
                 "X-Frame-Options"        => "SAMEORIGIN"}
    else
      res = @app.call(env)
    end 
    res 
  end 
end

何のことはないinitializeとcallメソッドがあるだけの普通のクラス。

rack middlewareの形式は、

  • リクエストの情報はenvに格納されている (詳細は後述)
  • レスポンスの形式は配列で、[ステータスコード、ヘッダ、ボディ]の順に格納される

ここで使っているenv["PATH_INFO"]にはリクエストパスが格納されているので、これを使って特定のパスへのリクエストをフックしている。
@app.call(env)とすることで、本来呼び出されるWebアプリ(RailsやSinatra)の処理が呼ばれる。
レスポンスの中身を直接指定することで、全く違うページを返したり、リダイレクトさせたり、何かを作成したように見せかけたりできる。

つまり、何でもできてしまう。

(ちなみに、適当なボディだけでレスポンスを返したらContent-Lengthの不一致で怒られた。何でもできるけど、値はきちんと設定すべし。)

envの中身

既に記事を書かれている方がいたのでそちらのリンクを。
HTTP Request Headerがどういう感じでRackのenvに変換されるか

ざっくり言えば、

  • 特定のヘッダはRackが埋めてくれる
  • Rackで定義してないヘッダは、upcaseして、頭に"HTTP_"をつけたものがセットされる

実際にはこんな感じになってる。

env
{"rack.version"=>[1, 2],
 "rack.input"=>#<StringIO:0x00000003a66be0>,
 "rack.errors"=>#<StringIO:0x00000003a66e88>,
 "rack.multithread"=>true,
 "rack.multiprocess"=>true,
 "rack.run_once"=>false,
 "REQUEST_METHOD"=>"POST",
 "SERVER_NAME"=>"example.org",
 "SERVER_PORT"=>"80",
 "QUERY_STRING"=>"",
 "PATH_INFO"=>"/",
 "rack.url_scheme"=>"http",
 "HTTPS"=>"off",
 "SCRIPT_NAME"=>"",
 "CONTENT_LENGTH"=>"40",
 "rack.test"=>true,
 "REMOTE_ADDR"=>"127.0.0.1",
 "CONTENT_TYPE"=>"application/x-www-form-urlencoded",
 "HTTP_HOST"=>"example.org",
 "HTTP_COOKIE"=>""}

postのbody

試している際にpostで送ったbodyが見つからず、???となった。
よく見れば...だったけど、同じハマり方してた人もいたので、一応記載。

http://stackoverflow.com/questions/15458334/how-to-read-post-data-in-rack-request

env['rack.input']に入ってる。
StringIOオブジェクトで入っているので、getsで取り出す。

# 先ほどのenv
env["rack.input"]       #=> #<StringIO:0x00000003a66be0>
env["rack.input"].gets  #=> "email=test%40example.org%26pass=password"

使い方

  • sinatraの場合 => config.ru に書く
config.ru
# ...
require File.expand_path 'lib/my_rack_middleware', File.dirname(__FILE__)
use MyRackMiddleware
  • railsの場合 => config/environments/xxx.rbやconfig/application.rb に書く
config/environments/development.rb
MyApp::Application.configure do
  # ...
  config.middleware.use MyRackMiddelware
end

テスト

別記事をupしたのでそちらを参照。

jrits
信頼と魅力のある先進のITをもとに、お客様のワークスタイル・イノベーションの実現を目指します。
http://www.jrits.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした