2013-09-18(水) [長年日記]
■ HTTPリクエストの圧縮をサポートする
HTTPクライアントから大きなデータをPOSTするときに圧縮可能ならそうして欲しい場合があって(もちろんブラウザはそんなことしてくれないので専用クライアントを使う前提)、サーバアプリは圧縮・未圧縮の状況にかかわりなく書きたいので、その部分だけRackミドルウェアにしてみた。ちなみにリクエストではなくてレスポンスなら普通の話なので何も考えずにRack::Deflaterを使えば良い。
最初、Rackでリクエストのbodyを操作する方法がわからなくてTwitterでつぶやいたら@moroが教えてくれたので解決。いつもいつも助かります(^^;
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'zlib' | |
module Rack | |
class UnknownCompressMethod < StandardError; end | |
class RequestDecompressor | |
def initialize(app) | |
@app = app | |
end | |
def call(env) | |
req = Rack::Request.new(env) | |
env['rack.input'] = decompress(req.body, env['HTTP_CONTENT_ENCODING']) | |
@app.call(env) | |
end | |
def decompress(body, method) | |
case method | |
when 'gzip' | |
Zlib::GzipReader.wrap(StringIO.new body.read) | |
when 'deflate' | |
StringIO.new(Zlib::Inflate.inflate(body.read)) | |
when nil | |
body | |
else # unknown compressing method | |
raise Rack::UnknownCompressMethod.new("unknown compress method '#{method}'.") | |
end | |
end | |
end | |
end |
こんな感じで使える:
require 'rack/request_decompressor' use Rack::RequestDecompressor
クライアントはContent-Encodingヘッダを追加してPOSTすればよろしい。
spam対策のために、E-mail欄を隠してあります。もしE-mail欄が見えていても、何も入力しないようにしてください。
これは便利そう
「大きなデータ」と言いつつ全部オンメモリで処理してるあたりがまだアレだけど。
gem化した: https://github.com/tdtds/rack-request_decompressor