rack-pagespeed-fork 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 583d2f74f36b8f3f550ee2abeaf37459d51509cf
4
- data.tar.gz: 093d507aede980e1871c6883fcda57a8ce46c5ab
3
+ metadata.gz: ec363d5fedd80da9e96fa635b10808d5b02a0f8d
4
+ data.tar.gz: 1654be013612d6d260554321ea6f08d095697a7c
5
5
  SHA512:
6
- metadata.gz: 1aa719697358b8fe33516a2d6565b8099c9b28994a9bba69c8337fd03ee8ea4ab2d76c76717826f7cd55e62dc73919b45006a757f11464e59d3b12fe017c049a
7
- data.tar.gz: 8d5a2a15f7523c740b3020d2172b8bad881d8edecb308bf3b7f9c1caf6f43358ccdf68c04d39ef81a155322c665c989769884cc2c2faa2f560626515d2ea330a
6
+ metadata.gz: 3d58e5223f6e7df77d93dfa77047f182ab86d72fb002101b1b95368ee4e3640c1b222997d04092e7a5ed9a61a9f92046966d7a7daa52f280ba15eb8006c1c8b9
7
+ data.tar.gz: a898d685a180fe5786d668d745c8e63b8205b32f5a6e0361a02ecdd554cf44aea92db3015e4e4e522f9832bd8e4da87162b2c04952af87715886a764190fbd1b
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -9,7 +9,7 @@ module Rack
9
9
 
10
10
  def initialize app, options, &block
11
11
  @app = app
12
- @config = Config.new options, &block
12
+ @config = Config.new options.merge(app: app), &block
13
13
  end
14
14
 
15
15
  def call env
@@ -21,11 +21,12 @@ module Rack
21
21
  body = ""; @response.each do |part| body << part end
22
22
  @document = Nokogiri::HTML(body)
23
23
  @config.filters.each do |filter|
24
+ filter.options[:env] = env
24
25
  filter.execute! @document
25
26
  end
26
27
  body = @document.to_html
27
28
  headers['Content-Length'] = body.length.to_s if headers['Content-Length'] # still UTF-8 unsafe
28
- [status, headers, [body]]
29
+ [status, headers, [body]]
29
30
  end
30
31
  end
31
32
 
@@ -35,6 +36,7 @@ module Rack
35
36
  [
36
37
  200,
37
38
  {
39
+ 'Last-Modified' => store.mtime(asset_id).httpdate,
38
40
  'Content-Length' => asset.length,
39
41
  'Content-Type' => (Rack::Mime.mime_type(::File.extname(asset_id))),
40
42
  'Cache-Control' => "public, max-age=#{(60*60*24*365.25*10).to_i}",
@@ -3,11 +3,10 @@ class Rack::PageSpeed::Config
3
3
  class NoSuchStorageMechanism < StandardError; end
4
4
  load "#{::File.dirname(__FILE__)}/store/disk.rb"
5
5
 
6
- attr_reader :filters, :public
6
+ attr_reader :filters, :app
7
7
 
8
8
  def initialize options = {}, &block
9
- @filters, @options, @public = [], options, options[:public]
10
- raise ArgumentError, ":public needs to be a directory" unless File.directory? @public.to_s
9
+ @filters, @options, @app = [], options, options[:app]
11
10
  filters_to_methods
12
11
  enable_filters_from_options
13
12
  enable_store_from_options
@@ -61,7 +60,7 @@ class Rack::PageSpeed::Config
61
60
  def filters_to_methods
62
61
  Rack::PageSpeed::Filter.available_filters.each do |klass|
63
62
  (class << self; self; end).send :define_method, klass.name do |*options|
64
- default_options = {:public => @options[:public], :store => @store}
63
+ default_options = {:app => @options[:app], :store => @store}
65
64
  instance = klass.new(options.any? ? default_options.merge(*options) : default_options)
66
65
  @filters << instance if instance and !@filters.select { |k| k.is_a? instance.class }.any?
67
66
  end
@@ -6,3 +6,4 @@ require "#{lib}/filters/combine_javascripts.rb"
6
6
  require "#{lib}/filters/combine_css.rb"
7
7
  require "#{lib}/filters/minify_javascripts.rb"
8
8
  require "#{lib}/filters/inline_images.rb"
9
+ require "#{lib}/filters/minify_css.rb"
@@ -45,18 +45,46 @@ module Rack::PageSpeed::Filters
45
45
  end
46
46
 
47
47
  private
48
- def file_for node
49
- path = case node.name
50
- when 'script'
51
- node['src']
52
- when 'img'
53
- node['src']
54
- when 'link'
55
- node['href']
48
+ # Asset is not local if it has either a scheme (e.g. 'http:') or a host (e.g. '//google.com/')
49
+ def is_local? path
50
+ uri = URI.parse(path)
51
+ uri.scheme.nil? && uri.host.nil?
52
+ rescue URI::BadURIError
53
+ false
54
+ rescue URI::InvalidURIError
55
+ false
56
+ end
57
+
58
+ def content? node
59
+ content_for(node)[0] == 200
60
+ end
61
+
62
+ def content_only node
63
+ status, headers, body = content_for(node)
64
+ return nil if status != 200
65
+ full_body = ""; body.each do |part| full_body << part end
66
+ full_body
67
+ end
68
+
69
+ def path_for node
70
+ case node.name
71
+ when 'script'
72
+ node['src']
73
+ when 'img'
74
+ node['src']
75
+ when 'link'
76
+ node['href']
56
77
  end
57
- return false unless path
58
- path = ::File.join(options[:public], URI.parse(path).path)
59
- ::File.open path if ::File.exists? path
78
+ end
79
+
80
+ # Retrieve the referenced asset through the Rack application
81
+ def content_for node
82
+ path = path_for node
83
+ return [404, {}, ""] unless path && is_local?(path)
84
+ app = options[:app]
85
+ env = options[:env].dup
86
+ env['PATH_INFO'] = path
87
+ app.call(env)
60
88
  end
61
89
  end
62
90
  # shortcut
@@ -22,7 +22,7 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
22
22
 
23
23
  private
24
24
  def merge_contents nodes, separator = ';'
25
- nodes.map { |node| file_for(node).read rescue "" }.join("\n")
25
+ nodes.map { |node| content_only(node) rescue "" }.join("\n")
26
26
  end
27
27
 
28
28
  def save nodes
@@ -32,7 +32,7 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
32
32
  end
33
33
 
34
34
  def local_css? node
35
- node.name == 'link' and file_for(node)
35
+ node.name == 'link' and content_for(node)[0] == 200
36
36
  end
37
37
 
38
38
  def topmost_of_sequence nodes
@@ -57,9 +57,10 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
57
57
 
58
58
  def unique_id nodes
59
59
  return Digest::MD5.hexdigest nodes.map { |node|
60
- file = file_for node
61
- next unless file
62
- file.mtime.to_i.to_s + file.read
60
+ status, headers, body = content_for node
61
+ next unless status == 200
62
+ full_body = ""; body.each do |part| full_body << part end
63
+ headers['Last-Modified'] + full_body
63
64
  }.join unless @options[:hash]
64
65
  @options[:hash].each do |urls, hash|
65
66
  next unless (nodes.map { |node| node['href'] } & urls).length == urls.length
@@ -7,7 +7,7 @@ end
7
7
  class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
8
8
  requires_store
9
9
  name 'combine_javascripts'
10
- priority 8
10
+ priority 10
11
11
 
12
12
  def execute! document
13
13
  nodes = document.css('script[src]')
@@ -23,7 +23,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
23
23
 
24
24
  private
25
25
  def save nodes
26
- contents = nodes.map { |node| file_for(node).read rescue "" }.join(';')
26
+ contents = nodes.map { |node| content_only(node) rescue "" }.join(';')
27
27
  nodes_id = unique_id nodes
28
28
  @options[:store]["#{nodes_id}.js"] = contents
29
29
  end
@@ -36,7 +36,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
36
36
  end
37
37
 
38
38
  def local_script? node
39
- node.name == 'script' and file_for(node)
39
+ node.name == 'script' and content?(node)
40
40
  end
41
41
 
42
42
  def topmost_of_sequence nodes
@@ -44,7 +44,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
44
44
  nodes.each do |node|
45
45
  _previous, _next = node.previous_sibling, node.next_sibling
46
46
  if _previous && local_script?(_previous) &&
47
- (!_next || !file_for(_next))
47
+ (!_next || !local_script?(_next))
48
48
  result << node
49
49
  end
50
50
  end
@@ -52,10 +52,11 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
52
52
  end
53
53
 
54
54
  def unique_id nodes
55
- return Digest::MD5.hexdigest nodes.map { |node|
56
- file = file_for node
57
- next unless file
58
- file.mtime.to_i.to_s + file.read
55
+ return Digest::MD5.hexdigest nodes.map { |node|
56
+ status, headers, body = content_for node
57
+ next unless status == 200
58
+ full_body = ""; body.each do |part| full_body << part end
59
+ headers['Last-Modified'] + full_body
59
60
  }.join unless @options[:hash]
60
61
  @options[:hash].each do |urls, hash|
61
62
  next unless (nodes.map { |node| node['src'] } & urls).length == urls.length
@@ -1,3 +1,4 @@
1
+ require 'csso'
1
2
  class Rack::PageSpeed::Filters::InlineCSS < Rack::PageSpeed::Filter
2
3
  priority 10
3
4
 
@@ -5,10 +6,11 @@ class Rack::PageSpeed::Filters::InlineCSS < Rack::PageSpeed::Filter
5
6
  nodes = document.css('link[rel="stylesheet"][href]')
6
7
  return false unless nodes.count > 0
7
8
  nodes.each do |node|
8
- file = file_for node
9
- next if !file or file.stat.size > (@options[:max_size] or 2048)
9
+ status, headers, body = content_for node
10
+ next if !status == 200 or headers['Content-Length'].to_i > (@options[:max_size] or 2048)
10
11
  inline = Nokogiri::XML::Node.new 'style', document
11
- inline.content = file.read
12
+ full_body = ""; body.each do |part| full_body << part end
13
+ inline.content = Csso.optimize(full_body)
12
14
  node.before inline
13
15
  node.remove
14
16
  end
@@ -5,10 +5,12 @@ class Rack::PageSpeed::Filters::InlineImages < Rack::PageSpeed::Filter
5
5
  nodes = document.css('img')
6
6
  return false unless nodes.count > 0
7
7
  nodes.each do |node|
8
- file = file_for node
9
- next if !file or file.stat.size > (@options[:max_size] or 1024)
8
+ status, headers, body = content_for node
9
+ next if status != 200 or headers['Content-Length'].to_i > (@options[:max_size] or 1024)
10
+ url = node['src']
10
11
  img = node.clone
11
- img['src'] = "data:#{Rack::Mime.mime_type(File.extname(file.path))};base64,#{[file.read].pack('m')}"
12
+ full_body = ""; body.each do |part| full_body << part end
13
+ img['src'] = "data:#{Rack::Mime.mime_type(File.extname(path_for(node)))};base64,#{[full_body].pack('m')}"
12
14
  img['alt'] = node['alt'] if node['alt']
13
15
  node.before img
14
16
  node.remove
@@ -1,15 +1,16 @@
1
1
  class Rack::PageSpeed::Filters::InlineJavaScripts < Rack::PageSpeed::Filter
2
2
  name 'inline_javascripts'
3
- priority 10
3
+ priority 8
4
4
 
5
5
  def execute! document
6
6
  nodes = document.css('script[src]')
7
7
  return false unless nodes.count > 0
8
8
  nodes.each do |node|
9
- file = file_for node
10
- next if !file or file.stat.size > (@options[:max_size] or 2048)
9
+ status, headers, body = content_for node
10
+ next if status != 200 or headers['Content-Length'].to_i > (@options[:max_size] or 2048)
11
11
  inline = Nokogiri::XML::Node.new 'script', document
12
- inline.content = file.read
12
+ full_body = ""; body.each do |part| full_body << part end
13
+ inline.content = JSMin.minify(full_body)
13
14
  node.before inline
14
15
  node.remove
15
16
  end
@@ -0,0 +1,31 @@
1
+ require 'csso'
2
+
3
+ begin
4
+ require 'md5'
5
+ rescue LoadError
6
+ require 'digest/md5'
7
+ end
8
+
9
+ class Rack::PageSpeed::Filters::MinifyCSS < Rack::PageSpeed::Filters::Base
10
+ requires_store
11
+ name 'minify_css'
12
+ priority 2
13
+
14
+ def execute! document
15
+ nodes = document.css('link[rel="stylesheet"][href]')
16
+ return false unless nodes.count > 0
17
+ nodes.each do |node|
18
+ if match = %r(^/rack-pagespeed-(.*)).match(node['href'])
19
+ store = @options[:store]
20
+ store[match[1]] = Csso.optimize(store[match[1]])
21
+ else
22
+ status, headers, body = content_for node
23
+ next unless node.name == 'link' && status == 200
24
+ css = ""; body.each do |part| css << part end
25
+ hash = Digest::MD5.hexdigest headers['Last-Modified'] + css
26
+ @options[:store]["#{hash}.css"] = Csso.optimize(css)
27
+ node['href'] = "/rack-pagespeed-#{hash}.css"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -21,10 +21,10 @@ class Rack::PageSpeed::Filters::MinifyJavaScripts < Rack::PageSpeed::Filters::Ba
21
21
  store = @options[:store]
22
22
  store[match[1]] = JSMin.minify store[match[1]]
23
23
  else
24
- next unless local_script? node
25
- file = file_for node
26
- javascript = file.read
27
- hash = Digest::MD5.hexdigest file.mtime.to_i.to_s + javascript
24
+ status, headers, body = content_for node
25
+ next unless node.name == 'script' && status == 200
26
+ javascript = ""; body.each do |part| javascript << part end
27
+ hash = Digest::MD5.hexdigest headers['Last-Modified'] + javascript
28
28
  compressed = Nokogiri::XML::Node.new 'script', document
29
29
  compressed['src'] = "/rack-pagespeed-#{hash}.js"
30
30
  @options[:store]["#{hash}.js"] = JSMin.minify javascript
@@ -34,8 +34,4 @@ class Rack::PageSpeed::Filters::MinifyJavaScripts < Rack::PageSpeed::Filters::Ba
34
34
  end
35
35
  end
36
36
  end
37
-
38
- def local_script? node
39
- node.name == 'script' and file_for(node)
40
- end
41
37
  end
@@ -8,6 +8,12 @@ class Rack::PageSpeed::Store::Disk
8
8
  @path = path
9
9
  end
10
10
 
11
+ # Retrieve last modified time from Disk asset
12
+ def mtime key
13
+ path = "#{@path}/rack-pagespeed-#{key}"
14
+ File.mtime path if File.exists? path
15
+ end
16
+
11
17
  def [] key
12
18
  path = "#{@path}/rack-pagespeed-#{key}"
13
19
  File.read path if File.exists? path
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: rack-pagespeed-fork 0.1.0 ruby lib
5
+ # stub: rack-pagespeed-fork 0.1.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "rack-pagespeed-fork"
9
- s.version = "0.1.0"
9
+ s.version = "0.1.1"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Will Jordan", "Julio Cesar Ody"]
14
- s.date = "2014-10-08"
14
+ s.date = "2014-10-09"
15
15
  s.description = "Web page speed optimizations at the Rack level - fork"
16
16
  s.email = "will@code.org"
17
17
  s.extra_rdoc_files = [
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  "lib/rack/pagespeed/filters/inline_css.rb",
33
33
  "lib/rack/pagespeed/filters/inline_images.rb",
34
34
  "lib/rack/pagespeed/filters/inline_javascripts.rb",
35
+ "lib/rack/pagespeed/filters/minify_css.rb",
35
36
  "lib/rack/pagespeed/filters/minify_javascripts.rb",
36
37
  "lib/rack/pagespeed/store/disk.rb",
37
38
  "lib/rack/pagespeed/store/memcached.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-pagespeed-fork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Will Jordan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-08 00:00:00.000000000 Z
12
+ date: 2014-10-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -116,6 +116,7 @@ files:
116
116
  - lib/rack/pagespeed/filters/inline_css.rb
117
117
  - lib/rack/pagespeed/filters/inline_images.rb
118
118
  - lib/rack/pagespeed/filters/inline_javascripts.rb
119
+ - lib/rack/pagespeed/filters/minify_css.rb
119
120
  - lib/rack/pagespeed/filters/minify_javascripts.rb
120
121
  - lib/rack/pagespeed/store/disk.rb
121
122
  - lib/rack/pagespeed/store/memcached.rb