Skip to content

Instantly share code, notes, and snippets.

@chriskottom
Created October 29, 2009 08:38
Show Gist options
  • Save chriskottom/221275 to your computer and use it in GitHub Desktop.
Save chriskottom/221275 to your computer and use it in GitHub Desktop.
require 'nokogiri'
require 'pstore'
#
# Rack::DomainSprinkler
#
# Modifies outgoing HTML markup so that common static assets like script source
# files, images, and stylesheets will be served from one of a number of domains
# rather than just a single one in order to improve parallelization of resource
# downloads during page loads.
#
module Rack
class DomainSprinkler
#
# Options:
# A list of domains across which to spread requests
# The name of the file to be used for caching URL/path mappings
#
def initialize(app, domains=[], cache_loc="tmp/sprinklins.pstore")
@app = app
@@domains = domains
@@url_cache = PStore.new(cache_loc)
end
def call(env)
dup._call(env)
end
#
# Currently only looks for <link>, <script>, and <img> tags.
# Should be refactored to provide more generic mapping.
#
def _call(env)
status, headers, response = @app.call(env)
if headers["Content-Type"] =~ /^text\/html/
document = Nokogiri::HTML(response.body)
sprinkle(env, document, 'link', 'href')
sprinkle(env, document, 'script', 'src')
sprinkle(env, document, 'img', 'src')
response.body = document.to_html
end
[status, headers, response]
end
def sprinkle(env, document, selector, property)
document.search(selector).each do |node|
url = node[property]
if !url.empty? and url !~ /^\#/ and url !~ /^http\:\/\//
node[property] = domainify(url, env)
end
end
end
def domainify(path, env)
if path !~ /\//
path = absolutify(path)
end
full_url = nil
@@url_cache.transaction do
unless @@url_cache[path]
domain = @@domains.shift and @@domains.push(domain)
@@url_cache[path] = "http://#{ domain }#{ path }"
end
full_url = @@url_cache[path]
end
full_url
end
def absolutify(path, env)
path_prefix = env['REQUEST_PATH']
unless path_prefix =~ /\/$/
path_prefix.sub!(/\/[^\/]+$/, '')
end
"#{ tmp_path }/#{ path }"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment