rack-pagespeed-fork 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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