-
-
Save delagoya/33468 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
A collection of Rack middleware, found all over the internet and part of Merb's core. |
This file contains hidden or 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
module Merb | |
module Rack | |
class Application | |
def call(env) | |
begin | |
rack_response = ::Merb::Dispatcher.handle(Merb::Request.new(env)) | |
rescue Object => e | |
return [500, {Merb::Const::CONTENT_TYPE => "text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")] | |
end | |
Merb.logger.info "\n\n" | |
Merb.logger.flush | |
# unless controller.headers[Merb::Const::DATE] | |
# require "time" | |
# controller.headers[Merb::Const::DATE] = Time.now.rfc2822.to_s | |
# end | |
rack_response | |
end | |
def deferred?(env) | |
path = env[Merb::Const::PATH_INFO] ? env[Merb::Const::PATH_INFO].chomp('/') : "" | |
if path =~ Merb.deferred_actions | |
Merb.logger.info! "Deferring Request: #{path}" | |
true | |
else | |
false | |
end | |
end # deferred?(env) | |
end # Application | |
end # Rack | |
end # Merb |
This file contains hidden or 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
# use with:: | |
# | |
# use CacheSettings, { | |
# /\/static\// => | |
# { :cache_control => "max-age=86400, public", | |
# :expires => 86400 | |
# } | |
# } | |
# use Rack::Static, :urls => ["/static"] # for example | |
class CacheSettings | |
def initialize app, pat | |
@app = app | |
@pat = pat | |
end | |
def call env | |
res = @app.call(env) | |
path = env["REQUEST_PATH"] | |
@pat.each do |pattern,data| | |
if path =~ pattern | |
res[1]["Cache-Control"] = data[:cache_control] if data.has_key?(:cache_control) | |
res[1]["Expires"] = (Time.now + data[:expires]).utc.rfc2822 if data.has_key?(:expires) | |
return res | |
end | |
end | |
res | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class ConditionalGet < Merb::Rack::Middleware | |
def call(env) | |
status, headers, body = @app.call(env) | |
if document_not_modified?(env, headers) | |
status = 304 | |
body = "" | |
# set Date header using RFC1123 date format as specified by HTTP | |
# RFC2616 section 3.3.1. | |
end | |
[status, headers, body] | |
end | |
private | |
def document_not_modified?(env, headers) | |
if etag = headers[Merb::Const::ETAG] | |
etag == env[Merb::Const::HTTP_IF_NONE_MATCH] | |
elsif last_modified = headers[Merb::Const::LAST_MODIFIED] | |
last_modified == env[Merb::Const::HTTP_IF_MODIFIED_SINCE] | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class ContentLength < Merb::Rack::Middleware | |
def call(env) | |
status, headers, body = @app.call(env) | |
# to_s is because Rack spec expects header | |
# values to be iterable and yield strings | |
header = 'Content-Length'.freeze | |
headers[header] = body.size.to_s unless headers.has_key?(header) | |
[status, headers, body] | |
end | |
end | |
end | |
end |
This file contains hidden or 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 'digest/md5' | |
module Merb | |
module Rack | |
class Csrf < Merb::Rack::Middleware | |
HTML_TYPES = %w(text/html application/xhtml+xml) | |
POST_FORM_RE = Regexp.compile('(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', Regexp::IGNORECASE) | |
ERROR_MSG = '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>'.freeze | |
def call(env) | |
status, header, body = @app.call(env) | |
body = body.to_s | |
if env[Merb::Const::REQUEST_METHOD] == Merb::Const::GET | |
body = process_response(body) if valid_content_type?(header[Merb::Const::CONTENT_TYPE]) | |
elsif env[Merb::Const::REQUEST_METHOD] == Merb::Const::POST | |
status, body = process_request(env, status, body) | |
end | |
[status, header, body] | |
end | |
private | |
def process_request(env, status, body) | |
session_id = Merb::Config[:session_id_key] | |
csrf_token = _make_token(session_id) | |
request_csrf_token = env['csrf_authentication_token'] | |
unless csrf_token == request_csrf_token | |
exception = Merb::ControllerExceptions::Forbidden.new(ERROR_MSG) | |
status = exception.status | |
body = exception.message | |
return [status, body] | |
end | |
return [status, body] | |
end | |
def process_response(body) | |
session_id = Merb::Config[:session_id_key] | |
csrf_token = _make_token(session_id) | |
if csrf_token | |
modified_body = '' | |
body.scan(POST_FORM_RE) do |match| | |
modified_body << add_csrf_field($~, csrf_token) | |
end | |
body = modified_body | |
end | |
body | |
end | |
def add_csrf_field(match, csrf_token) | |
modified_body = match.pre_match | |
modified_body << match.to_s | |
modified_body << "<div style='display: none;'><input type='hidden' id='csrf_authentication_token' name='csrf_authentication_token' value='#{csrf_token}' /></div>" | |
modified_body << match.post_match | |
end | |
def valid_content_type?(content_type) | |
HTML_TYPES.include?(content_type.split(';').first) | |
end | |
def _make_token(session_id) | |
Digest::MD5.hexdigest(Merb::Config[:session_secret_key] + session_id) | |
end | |
end | |
end | |
end |
This file contains hidden or 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
module Rack | |
# A Rack middleware for providing JSON-P support. | |
# | |
# Full credit to Flinn Mueller (http://actsasflinn.com/) for this contribution. | |
# | |
class JSONP | |
def initialize(app) | |
@app = app | |
end | |
# Proxies the request to the application, stripping out the JSON-P callback | |
# method and padding the response with the appropriate callback format. | |
# | |
# Changes nothing if no <tt>callback</tt> param is specified. | |
# | |
def call(env) | |
status, headers, response = @app.call(env) | |
request = Rack::Request.new(env) | |
response = pad(request.params.delete('callback'), response) if request.params.include?('callback') | |
[status, headers, response] | |
end | |
# Pads the response with the appropriate callback format according to the | |
# JSON-P spec/requirements. | |
# | |
# The Rack response spec indicates that it should be enumerable. The method | |
# of combining all of the data into a sinle string makes sense since JSON | |
# is returned as a full string. | |
# | |
def pad(callback, response, body = "") | |
response.each{ |s| body << s } | |
"#{callback}(#{body})" | |
end | |
end | |
end |
This file contains hidden or 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
class LimitPostBodySize | |
TYPES = /(errors|reports|alerts)/ | |
CLIENT_ID = /([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12})/ | |
PLUGIN_ID = /(\d+)/ | |
PATH = %r{/clients/#{CLIENT_ID}/plugins/#{PLUGIN_ID}/#{TYPES}\.scout} | |
VERSION = /version=(\d+\.\d+\.\d+)/ | |
attr_accessor :app, :max_size | |
def initialize(app, limit, logger = nil) | |
@app, @limit, @logger = app, limit, logger | |
@logger = Logger.new(@logger) unless @logger.is_a?(Logger) | |
end | |
def call(env) | |
post_body_size = case env['rack.input'] | |
when StringIO | |
env['rack.input'].size | |
when IO | |
env['rack.input'].stat.size | |
else | |
puts env['rack.input'].class.to_s | |
0 | |
end | |
if post_body_size > @limit | |
puts env['PATH_INFO'] | |
puts env['PATH_INFO'] =~ PATH | |
client_id, plugin_id, type = $1, $2, $3 if env['PATH_INFO'] =~ PATH | |
version = $1 if env['QUERY_STRING'] =~ VERSION | |
logger.info("[#{Time.now.strftime("%Y-%m-%d %H:%I:%S")}] #{type.upcase} ClientID:#{client_id} PluginID:#{plugin_id.to_s} PostBodySize:#{post_body_size.to_s} (Version:#{version})") | |
end | |
@app.call(env) | |
end | |
def logger | |
@logger ||= Logger.new(File.join(File.dirname(__FILE__), '..', 'log', 'excessive_post_body.log')) | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class Middleware | |
def initialize(app) | |
@app = app | |
end | |
def deferred?(env) | |
@app.deferred?(env) | |
end | |
def call(env) | |
@app.call(env) | |
end | |
end | |
end | |
end | |
This file contains hidden or 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
module Merb | |
module Rack | |
class PathPrefix < Merb::Rack::Middleware | |
def initialize(app, path_prefix = nil) | |
super(app) | |
@path_prefix = /^#{Regexp.escape(path_prefix)}/ | |
end | |
def deferred?(env) | |
strip_path_prefix(env) | |
@app.deferred?(env) | |
end | |
def call(env) | |
strip_path_prefix(env) | |
@app.call(env) | |
end | |
def strip_path_prefix(env) | |
['PATH_INFO', 'REQUEST_URI'].each do |path_key| | |
if env[path_key] =~ @path_prefix | |
env[path_key].sub!(@path_prefix, '') | |
env[path_key] = '/' if env[path_key].empty? | |
end | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or 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
begin | |
require 'json' | |
rescue LoadError => e | |
require 'json/pure' | |
end | |
module Rack | |
# A Rack middleware for parsing POST/PUT body data when Content-Type is | |
# not one of the standard supported types, like <tt>application/json</tt>. | |
# | |
class PostBodyContentTypeParsers | |
# Constants | |
# | |
CONTENT_TYPE = 'CONTENT_TYPE'.freeze | |
POST_BODY = 'rack.input'.freeze | |
FORM_INPUT = 'rack.request.form_input'.freeze | |
FORM_HASH = 'rack.request.form_hash'.freeze | |
# Supported Content-Types | |
# | |
APPLICATION_JSON = 'application/json'.freeze | |
def initialize(app) | |
@app = app | |
end | |
def call(env) | |
case env[CONTENT_TYPE] | |
when APPLICATION_JSON | |
env.update(FORM_HASH => JSON.parse(env[POST_BODY].read), FORM_INPUT => env[POST_BODY]) | |
end | |
@app.call(env) | |
end | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class Profiler < Merb::Rack::Middleware | |
def initialize(app, min=1, iter=1) | |
super(app) | |
@min, @iter = min, iter | |
end | |
def call(env) | |
__profile__("profile_output", @min, @iter) do | |
@app.call(env) | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class Static < Merb::Rack::Middleware | |
def initialize(app,directory) | |
super(app) | |
@static_server = ::Rack::File.new(directory) | |
end | |
def call(env) | |
path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : "" | |
cached_path = (path.empty? ? 'index' : path) + '.html' | |
if file_exist?(path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD | |
serve_static(env) | |
elsif file_exist?(cached_path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD | |
env['PATH_INFO'] = cached_path | |
serve_static(env) | |
elsif path =~ /favicon\.ico/ | |
return [404, {"Content-Type"=>"text/html"}, "404 Not Found."] | |
else | |
@app.call(env) | |
end | |
end | |
# ==== Parameters | |
# path<String>:: The path to the file relative to the server root. | |
# | |
# ==== Returns | |
# Boolean:: True if file exists under the server root and is readable. | |
def file_exist?(path) | |
full_path = ::File.join(@static_server.root, ::Merb::Request.unescape(path)) | |
::File.file?(full_path) && ::File.readable?(full_path) | |
end | |
# ==== Parameters | |
# env<Hash>:: Environment variables to pass on to the server. | |
def serve_static(env) | |
env["PATH_INFO"] = ::Merb::Request.unescape(env["PATH_INFO"]) | |
@static_server.call(env) | |
end | |
end | |
end | |
end |
This file contains hidden or 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
class SubdomainToPathInfo # man I'm bad with names | |
def initialize(app) | |
@app = app | |
end | |
def call(env) | |
@app.call(filter(env)) | |
end | |
def filter(env) | |
if env['SERVER_NAME'] =~ /(.*)\.domain\.com/ | |
env['PATH_INFO'] = "#{$1}#{env['PATH_INFO']}" | |
end | |
env | |
end | |
end |
This file contains hidden or 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
module Merb | |
module Rack | |
class Tracer < Merb::Rack::Middleware | |
def call(env) | |
Merb.logger.debug!("Rack environment:\n" + env.inspect + "\n\n") | |
status, headers, body = @app.call(env) | |
Merb.logger.debug!("Status: #{status.inspect}") | |
Merb.logger.debug!("Headers: #{headers.inspect}") | |
Merb.logger.debug!("Body: #{body.inspect}") | |
[status, headers, body] | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment