Skip to content

Instantly share code, notes, and snippets.

@chriskottom
Created October 29, 2009 08:38

Revisions

  1. chriskottom created this gist Oct 29, 2009.
    91 changes: 91 additions & 0 deletions Rack::DomainSprinkler
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    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