rack-esi 0.1.1 → 0.1.2

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.
Files changed (4) hide show
  1. data/README.markdown +3 -2
  2. data/VERSION +1 -1
  3. data/lib/rack-esi.rb +55 -33
  4. metadata +2 -2
data/README.markdown CHANGED
@@ -11,7 +11,7 @@ for include, remove and comment.
11
11
  * include limits (:includes => 32)
12
12
  * support for <include> alt and noerror attributes
13
13
 
14
- _It's for development purpose since its still 0.1.x..._
14
+ _It's for development purpose..._
15
15
 
16
16
  ## Installation
17
17
 
@@ -20,7 +20,8 @@ _It's for development purpose since its still 0.1.x..._
20
20
  ## Rails Setup (environment.rb)
21
21
 
22
22
  config.gem 'rack-esi'
23
- config.middleware.use(Rack::ESI, opts = {})
23
+ require 'rack-esi'
24
+ config.middleware.insert_before config.middleware.first, Rack::ESI
24
25
 
25
26
  ## TODO
26
27
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
data/lib/rack-esi.rb CHANGED
@@ -3,7 +3,17 @@ require 'nokogiri'
3
3
 
4
4
  class Rack::ESI
5
5
  NS = { 'esi' => 'http://www.edge-delivery.org/esi/1.0' }
6
- Error = Class.new RuntimeError
6
+ METHODS = { 'include' => :esi_include, 'remove' => nil, 'comment' => nil }
7
+ CSS = METHODS.keys.map { |cmd| "esi|#{ cmd }" } * ','
8
+
9
+ class Error < RuntimeError
10
+ def initialize(status, headers, response)
11
+ @status, @headers, @response = status, headers, response
12
+ end
13
+ def finish
14
+ return [@status, @headers, backtrace]
15
+ end
16
+ end
7
17
 
8
18
  def initialize(app, options = {})
9
19
  @app = app
@@ -17,49 +27,35 @@ class Rack::ESI
17
27
  def call env, counter = { :recursion => 0, :includes => 0 }
18
28
  return @app.call(env) if skip_path? env['PATH_INFO']
19
29
 
20
- status, headers, source = @app.call env
21
- return status, headers, source if skip_type? headers['Content-Type']
30
+ status, headers, input = @app.call env.dup
31
+ return status, headers, input if skip_type? headers['Content-Type']
22
32
 
23
- Rack::Response.new { |target|
24
- source.each { |body| target.write compile(body, env, counter) }
25
- }.finish
33
+ output = []
34
+ input.each { |body| output << compile_body(body, env, counter) }
35
+
36
+ Rack::Response.new(output, status, headers).finish
26
37
  end
27
38
 
28
39
  private
29
40
 
41
+ def with_compiled_path(env, path)
42
+ # TODO: should compile variables.
43
+ env.merge 'PATH_INFO' => path, 'REQUEST_URI' => path
44
+ end
45
+
30
46
  def fetch(path, env, counter)
31
- call env.merge('PATH_INFO' => path), counter if path
47
+ call with_compiled_path(env, path), counter if path
48
+ rescue => e
49
+ return [500, {}, e.backtrace]
32
50
  end
33
51
 
34
52
  # Should I use XML::SAX::Parser?
35
- def compile(body, env, counter)
53
+ def compile_body(body, env, counter)
36
54
  document = Nokogiri.XML body
37
55
 
38
- document.css('esi|include,esi|remove,esi|comment', NS).each do |node|
39
- case node.name
40
- when 'include'
41
- next unless counter[:includes] < @max_includes
42
- counter[:includes] += 1
43
- begin
44
- next unless counter[:recursion] < @max_recursion
45
- counter[:recursion] += 1
46
- status, headers, compiled = fetch node['src'], env, counter
47
- status, headers, compiled = fetch node['alt'], env, counter if status != 200
48
- ensure
49
- counter[:recursion] -= 1
50
- end
51
-
52
- if status != 200
53
- raise Error if node['onerror'] != 'continue'
54
- compiled = []
55
- end
56
-
57
- data = '' and compiled.each { |body| data << body }
58
- node.swap data
59
-
60
- when 'remove', 'comment'
61
- node.unlink
62
- end
56
+ document.css(CSS, NS).each do |node|
57
+ method = METHODS[node.name] and send method, node, env, counter
58
+ node.unlink
63
59
  end
64
60
 
65
61
  document.to_xhtml
@@ -72,4 +68,30 @@ class Rack::ESI
72
68
  @types !~ type
73
69
  end
74
70
 
71
+ def max?(counter)
72
+ not counter[:includes] < @max_includes &&
73
+ counter[:recursion] < @max_recursion
74
+ end
75
+
76
+ def esi_include(node, env, counter)
77
+ return if max? counter
78
+
79
+ counter[:includes] += 1
80
+ counter[:recursion] += 1
81
+
82
+ status, headers, response = fetch node['src'], env, counter
83
+ status, headers, response = fetch node['alt'], env, counter if status != 200
84
+
85
+ if status == 200
86
+ data = ''
87
+ response.each { |inc| data << inc }
88
+ node.before data
89
+ elsif node['onerror'] != 'continue'
90
+ raise Error.new(status, headers, response)
91
+ end
92
+
93
+ ensure
94
+ counter[:recursion] -= 1
95
+ end
96
+
75
97
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-esi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Florian A\xC3\x9Fmann"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-26 00:00:00 +01:00
12
+ date: 2009-11-27 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency