kivanio (owner)

Revisions

gist: 227904 Download_button fork
public
Public Clone URL: git://gist.github.com/227904.git
Embed All Files: show embed
Rack::DomainSprinkler #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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