mongrel_esi 0.4.0

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 (73) hide show
  1. data/COPYING +53 -0
  2. data/LICENSE +471 -0
  3. data/README +186 -0
  4. data/Rakefile +141 -0
  5. data/bin/mongrel_esi +271 -0
  6. data/ext/esi/common.rl +41 -0
  7. data/ext/esi/esi_parser.c +387 -0
  8. data/ext/esi/extconf.rb +6 -0
  9. data/ext/esi/machine.rb +499 -0
  10. data/ext/esi/parser.c +1675 -0
  11. data/ext/esi/parser.h +113 -0
  12. data/ext/esi/parser.rb +49 -0
  13. data/ext/esi/parser.rl +398 -0
  14. data/ext/esi/ruby_esi.rl +135 -0
  15. data/ext/esi/run-test.rb +3 -0
  16. data/ext/esi/test/common.rl +41 -0
  17. data/ext/esi/test/parser.c +1676 -0
  18. data/ext/esi/test/parser.h +113 -0
  19. data/ext/esi/test/parser.rl +398 -0
  20. data/ext/esi/test/test.c +373 -0
  21. data/ext/esi/test1.rb +56 -0
  22. data/ext/esi/test2.rb +45 -0
  23. data/lib/esi/cache.rb +207 -0
  24. data/lib/esi/config.rb +154 -0
  25. data/lib/esi/dispatcher.rb +27 -0
  26. data/lib/esi/handler.rb +236 -0
  27. data/lib/esi/invalidator.rb +40 -0
  28. data/lib/esi/logger.rb +46 -0
  29. data/lib/esi/router.rb +84 -0
  30. data/lib/esi/tag/attempt.rb +6 -0
  31. data/lib/esi/tag/base.rb +85 -0
  32. data/lib/esi/tag/except.rb +24 -0
  33. data/lib/esi/tag/include.rb +190 -0
  34. data/lib/esi/tag/invalidate.rb +54 -0
  35. data/lib/esi/tag/try.rb +40 -0
  36. data/lib/multi_dirhandler.rb +70 -0
  37. data/setup.rb +1585 -0
  38. data/test/integration/basic_test.rb +39 -0
  39. data/test/integration/cache_test.rb +37 -0
  40. data/test/integration/docs/content/500.html +16 -0
  41. data/test/integration/docs/content/500_with_failover.html +16 -0
  42. data/test/integration/docs/content/500_with_failover_to_alt.html +8 -0
  43. data/test/integration/docs/content/ajax_test_page.html +15 -0
  44. data/test/integration/docs/content/cookie_variable.html +3 -0
  45. data/test/integration/docs/content/foo.html +15 -0
  46. data/test/integration/docs/content/include_in_include.html +15 -0
  47. data/test/integration/docs/content/malformed_transforms.html +16 -0
  48. data/test/integration/docs/content/malformed_transforms.html-correct +11 -0
  49. data/test/integration/docs/content/static-failover.html +20 -0
  50. data/test/integration/docs/content/test2.html +1 -0
  51. data/test/integration/docs/content/test3.html +17 -0
  52. data/test/integration/docs/esi_invalidate.html +6 -0
  53. data/test/integration/docs/esi_mixed_content.html +15 -0
  54. data/test/integration/docs/esi_test_content.html +27 -0
  55. data/test/integration/docs/index.html +688 -0
  56. data/test/integration/docs/test1.html +1 -0
  57. data/test/integration/docs/test3.html +9 -0
  58. data/test/integration/docs/test_failover.html +1 -0
  59. data/test/integration/handler_test.rb +270 -0
  60. data/test/integration/help.rb +234 -0
  61. data/test/net/get_test.rb +197 -0
  62. data/test/net/net_helper.rb +16 -0
  63. data/test/net/server_test.rb +249 -0
  64. data/test/unit/base_tag_test.rb +44 -0
  65. data/test/unit/esi-sample.html +56 -0
  66. data/test/unit/help.rb +77 -0
  67. data/test/unit/include_request_test.rb +69 -0
  68. data/test/unit/include_tag_test.rb +14 -0
  69. data/test/unit/parser_test.rb +478 -0
  70. data/test/unit/router_test.rb +34 -0
  71. data/test/unit/sample.html +21 -0
  72. data/tools/rakehelp.rb +119 -0
  73. metadata +182 -0
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__),'help.rb')
2
+
3
+ class BaseTagTest < Test::Unit::TestCase
4
+
5
+ def tag_with_request( http_params = {} )
6
+ ESI::Tag::Base.new(@test_router,http_params, {},'test',{},{})
7
+ end
8
+
9
+ def test_prepare_url_vars
10
+ # test happy path
11
+ value = 'foo'
12
+ url = tag_with_request({'HTTP_COOKIE' => "type=#{value}"}).prepare_url_vars( "http://www.example.com/$(HTTP_COOKIE{type})/hello.gif" )
13
+ assert_equal "http://www.example.com/#{value}/hello.gif", url
14
+ # test empty cookie value
15
+ value = ''
16
+ url = tag_with_request({'HTTP_COOKIE' => "type=#{value}"}).prepare_url_vars( "http://www.example.com/$(HTTP_COOKIE{type})/hello.gif" )
17
+ assert_equal "http://www.example.com/#{value}/hello.gif", url
18
+ # test no cookie http key
19
+ url = tag_with_request.prepare_url_vars( "http://www.example.com/$(HTTP_COOKIE{type})/hello.gif")
20
+ assert_equal "http://www.example.com//hello.gif", url
21
+
22
+ # test a funky variable that's not supported
23
+ url = tag_with_request.prepare_url_vars( "http://www.example.com/$(H_COOKIE{type})/hello.gif")
24
+ assert_equal "http://www.example.com//hello.gif", url
25
+
26
+ # test a syntax error
27
+ url = tag_with_request.prepare_url_vars( "http://www.example.com/$(H_COOKIE{type}/hello.gif")
28
+ assert_equal "http://www.example.com/$(H_COOKIE{type}/hello.gif", url
29
+
30
+ # test multiple variables in the URL
31
+ v1 = 'foo'
32
+ v2 = 'bar'
33
+ url = tag_with_request({'HTTP_COOKIE' => "type=#{v1};type2=#{v2}"}).prepare_url_vars( "http://www.example.com/$(HTTP_COOKIE{type})/$(HTTP_COOKIE{type2}).gif")
34
+ assert_equal "http://www.example.com/#{v1}/#{v2}.gif", url
35
+ end
36
+
37
+ def test_bug_fix_for_complex_url
38
+ url = "/content/modules/head/header_contents?pma_module_id=head%2Fheader_contents&cache_ttl=600&display_signin=true&pma_request=true&view=header_contents&display_search=true&q_module_wrap=block&b2bid=$(HTTP_COOKIE{b2bid})"
39
+ assert_match /b2b_expected/, tag_with_request({"HTTP_COOKIE" => "b2bid=b2b_expected;edn=reg_expected"}).prepare_url_vars(url)
40
+ url = "/registration/modules/mini_dashboard/show?cache_ttl=600&pma_module_id=mini_dashboard%2Fshow&q_module_wrap=block&pma_request=true&edn=$(HTTP_COOKIE{edn})"
41
+ assert_match /reg_expected/, tag_with_request({"HTTP_COOKIE" => "b2bid=b2b_expected;edn=reg_expected"}).prepare_url_vars(url)
42
+ end
43
+
44
+ end
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <title>Something else</title>
5
+ </head>
6
+ <body>
7
+ <![CDATA[
8
+ Some cdata fun fun fun
9
+ ]]>
10
+ <h1>hello</h1>
11
+ <div class="body">
12
+ <esi:include src="/test/success?id=1"/>
13
+ <div>some content</div>
14
+ <!-- a little commentary -->
15
+ <!-- a
16
+ multiline comment -->
17
+ <esi:try>
18
+ <esi:attempt>
19
+ <esi:include src="/test/success?id=2"/>
20
+ </esi:attempt>
21
+ <esi:except>
22
+ <p>it failed</p>
23
+ <esi:include src="/test/success?id=2"/>
24
+ </esi:except>
25
+ </esi:try>
26
+ <esi:include src="/test/success?id=3"/>
27
+ <esi:try>
28
+ <esi:attempt>
29
+ <p>We should get this or not?</p>
30
+ <esi:include src="/test/error"/>
31
+ <p>Now maybe we shouldn't see this?</p>
32
+ </esi:attempt>
33
+ <esi:except>
34
+ <p>except worked1</p>
35
+ <esi:include src="/test/success?id=4"/>
36
+ <p>except worked2</p>
37
+ </esi:except>
38
+ </esi:try>
39
+
40
+ <em>Support for em tags since they have an initial start sequence similar to and &lt;esi: start/end sequence</em>
41
+
42
+ <esi:invalidate>
43
+ <?xml version="1.0"?>
44
+ <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
45
+ <INVALIDATION VERSION="WCS-1.1">
46
+ <OBJECT>
47
+ <BASICSELECTOR URI="/test/success?id=1"/>
48
+ <ACTION REMOVALTTL="0"/>
49
+ <INFO VALUE="invalidating fragment test 1"/>
50
+ </OBJECT>
51
+ </INVALIDATION>
52
+ </esi:invalidate>
53
+
54
+ </div>
55
+ </body>
56
+ </html>
data/test/unit/help.rb ADDED
@@ -0,0 +1,77 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
2
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "ext")
3
+ require 'test/unit'
4
+ require 'rubygems'
5
+ require 'mongrel'
6
+ require 'mocha'
7
+
8
+ ENV["test"] = 'true'
9
+ require 'esi/cache'
10
+ require 'esi/router'
11
+ require 'esi/esi'
12
+ require 'esi/tag/base'
13
+ require 'esi/tag/include'
14
+ require 'esi/tag/attempt'
15
+ require 'esi/tag/except'
16
+ require 'esi/tag/try'
17
+ require 'esi/tag/invalidate'
18
+
19
+ require 'webrick'
20
+ class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
21
+ class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
22
+
23
+ module TestServer
24
+ def setup
25
+ @server = WEBrick::HTTPServer.new( :Port => 99999 )
26
+
27
+
28
+ # setup test server (simulates exact target)
29
+ @server.mount_proc("/test/error") do|req,res|
30
+ raise "fail"
31
+ end
32
+ @server.mount_proc("/test/redirect") do|req,res|
33
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently,"/test/success")
34
+ end
35
+ @server.mount_proc("/test/redirect_to_error") do|req,res|
36
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently,"/test/error")
37
+ end
38
+ @server.mount_proc("/test/success") do|req,res|
39
+ id = req.query["id"]
40
+ if id
41
+ res.body = "<div id='#{id}'>id string</div>"
42
+ else
43
+ res.body = "<div>hello there world</div>"
44
+ end
45
+ res['Content-Type'] = "text/html"
46
+ end
47
+ @server.mount_proc("/test/timeout") do|req,res|
48
+ sleep 0.8 # needs to be high for slower machines, like my ppc mac
49
+ res.body = "<div>We won't get this for a few seconds</div>"
50
+ res['Content-Type'] = "text/html"
51
+ end
52
+ @server.mount_proc("/test/headers") do|req,res|
53
+ res.body = "<div>hello there world</div>"
54
+ res['Content-Type'] = "text/html"
55
+ begin
56
+ assert_equal ['value1'], req.header['headers1']
57
+ assert_equal ['value2'], req.header['headers2']
58
+ rescue Object => e
59
+ puts e.message
60
+ raise e
61
+ end
62
+ end
63
+
64
+ # start up the server in a background thread
65
+ @thread = Thread.new(@server) do|server|
66
+ server.start
67
+ end
68
+
69
+ @test_router = ESI::Router.new([{:host => '127.0.0.1', :port => '99999', :match_url => 'default'}])
70
+
71
+ setup_extra if self.respond_to?(:setup_extra)
72
+ end
73
+ def teardown
74
+ @server.shutdown
75
+ @thread.join
76
+ end
77
+ end
@@ -0,0 +1,69 @@
1
+ require File.join(File.dirname(__FILE__),'help.rb')
2
+
3
+ class IncludeRequestTest < Test::Unit::TestCase
4
+ include TestServer
5
+
6
+ def request(path,alt=nil,headers={})
7
+ ir = ESI::Tag::IncludeRequest.new(headers)
8
+ buffer = ""
9
+ status = 0
10
+ info = nil
11
+ alt = "http://127.0.0.1:99999#{alt}" if alt
12
+ ir.request("http://127.0.0.1:99999#{path}",0.5,alt) do|s,r|
13
+ if s
14
+ buffer = r.read_body
15
+ status = 1
16
+ else
17
+ info = r.message
18
+ buffer = r.response.read_body if r.response
19
+ end
20
+ end
21
+ [buffer,info,status]
22
+ end
23
+
24
+ # happy paths
25
+ def test_success
26
+ ri = request('/test/success')
27
+ assert_equal 1, ri[2], "Request failed\n#{ri[0]}"
28
+ assert_equal %Q(<div>hello there world</div>), ri[0], "Request failed"
29
+ end
30
+
31
+ def test_redirect
32
+ ri = request('/test/redirect')
33
+ assert_equal 1, ri[2], "Request failed\n#{ri[0]}"
34
+ assert_equal %Q(<div>hello there world</div>), ri[0], "Request failed"
35
+ end
36
+
37
+ def test_error_alt
38
+ ri = request('/test/error','/test/success')
39
+ assert_equal 1, ri[2], "Request failed\n#{ri[0]}"
40
+ assert_equal %Q(<div>hello there world</div>), ri[0], "Request failed"
41
+ end
42
+
43
+ def test_error_no_alt
44
+ ri = request('/test/error')
45
+ assert_equal 0, ri[2], "Request should have failed\n#{ri[0]}"
46
+ end
47
+
48
+ # not so happy paths
49
+ def test_error_error_alt
50
+ ri = request('/test/error','/test/error')
51
+ assert_equal 0, ri[2], "Request should have failed\n#{ri[0]}"
52
+ end
53
+
54
+ def test_redirect_failed_to_alt
55
+ ri = request('/test/redirect_to_error','/test/redirect_to_error')
56
+ assert_equal 0, ri[2], "Request should have failed\n#{ri[0]}"
57
+ end
58
+
59
+ def test_request_timesout
60
+ ri = request('/test/timeout')
61
+ assert_equal 0, ri[2], "Request should have failed\n#{ri[0]}"
62
+ end
63
+
64
+ def test_headers_forward
65
+ ri = request('/test/headers',nil,{'Headers1' => 'value1', 'Headers2' => 'value2'})
66
+ assert_equal 1, ri[2], "Request should not have failed\n#{ri[0]}"
67
+ end
68
+
69
+ end
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__),'help.rb')
2
+
3
+ class IncludeTagTest < Test::Unit::TestCase
4
+ include TestServer
5
+ def test_close
6
+
7
+ output = ""
8
+ include_tag = ESI::Tag::Base.create(@test_router, {}, {},
9
+ 'include', {'src'=>"/test/success/"},
10
+ ESI::RubyCache.new)
11
+ include_tag.close(output)
12
+ assert_equal("<div>hello there world</div>",output)
13
+ end
14
+ end
@@ -0,0 +1,478 @@
1
+ require File.join(File.dirname(__FILE__),'help.rb')
2
+
3
+ $run_sample_once = false
4
+ class ParseOutputTest < Test::Unit::TestCase
5
+ include TestServer
6
+
7
+ def setup_extra
8
+ @sample_file = File.join(File.dirname(__FILE__),'esi-sample.html')
9
+ if !$run_sample_once
10
+ File.open('out-sample.html','w') do|output|
11
+ @cache = ESI::RubyCache.new
12
+ @parser = ESI::CParser.new
13
+ @parser.output = output
14
+
15
+ @parser.start_tag_handler do|tag_name,attrs|
16
+ tag = ESI::Tag::Base.create(@test_router, {}, {}, tag_name.gsub(/esi:/,''), attrs, @cache)
17
+ if @parser.esi_tag
18
+ @parser.esi_tag.add_child(tag)
19
+ else
20
+ @parser.esi_tag = tag
21
+ end
22
+ end
23
+
24
+ @parser.end_tag_handler do|tag_name|
25
+ #puts "match: '#{@parser.esi_tag.name}' with '#{tag_name.gsub(/esi:/,'')}'"
26
+ if @parser.esi_tag.name == tag_name.gsub(/esi:/,'')
27
+ begin
28
+ @parser.esi_tag.close(@parser.output)
29
+ rescue Object => e
30
+ puts @parser.esi_tag.name
31
+ puts e.message
32
+ end
33
+ @parser.esi_tag = nil
34
+ else
35
+ @parser.esi_tag.close_child(@parser.output,tag_name)
36
+ end
37
+ end
38
+
39
+ File.open( @sample_file,'r') do|input|
40
+ while( (buf=input.read(128)) and !input.eof? and buf.size != 0 )
41
+ @parser.process buf
42
+ end
43
+ @parser.process buf
44
+ end
45
+ @parser.finish
46
+ end
47
+
48
+ $run_sample_once = true
49
+ end
50
+ @output=File.read('out-sample.html')
51
+ end
52
+
53
+ def test_ouput_body
54
+ assert_match(/ <div class="body">/, @output)
55
+ end
56
+ def test_ouput_some_content
57
+ assert_match(/ <div>some content<\/div>/, @output)
58
+ end
59
+ def test_output_comments
60
+ assert_match(/ <!-- a little commentary -->/, @output)
61
+ assert_match(%q(<!-- a
62
+ multiline comment -->),@output)
63
+ end
64
+ def test_output_cdata
65
+ assert_match(%q(<![CDATA[
66
+ Some cdata fun fun fun
67
+ ]]>), @output)
68
+ end
69
+ def test_output_doctype
70
+ assert_match(/<!DOCTYPE html PUBLIC "-\/\/W3C\/\/DTD XHTML 1.0 Strict\/\/EN" "http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-strict.dtd">/, @output)
71
+ end
72
+ def test_output_complete
73
+ assert_match(/<\/html>/, @output)
74
+ end
75
+ def test_output_no_esi_tags
76
+ assert_no_match(/<esi:/, @output)
77
+ end
78
+
79
+ def test_includes_appeared
80
+ assert_match(/<div id='1'>id string<\/div>/, @output)
81
+ assert_match(/<div id='3'>id string<\/div>/, @output)
82
+
83
+ assert_no_match(/<p>it failed<\/p>/, @output)
84
+ assert_match(/<div id='2'>id string<\/div>/, @output)
85
+
86
+ assert_match(/<div id='4'>id string<\/div>/, @output)
87
+ assert_match(/<p>We should get this or not\?<\/p>/, @output)
88
+ assert_match(/<p>Now maybe we shouldn't see this\?<\/p>/, @output)
89
+ assert_match(/<p>except worked1<\/p>/, @output)
90
+ assert_match(/<p>except worked2<\/p>/, @output)
91
+
92
+ assert_match(/<em>Support for em tags since they have an initial start sequence similar to and &lt;esi: start\/end sequence<\/em>/, @output )
93
+ end
94
+
95
+ def test_content_echoing
96
+ output = ""
97
+ parser = ESI::CParser.new
98
+ input = "<em>Support for em tags since they have an initial start sequence similar to and &lt;esi: start/end sequence</em>"
99
+ parser.output_handler {|s| output << s }
100
+ parser.process input
101
+ parser.finish
102
+ assert_equal input, output
103
+ end
104
+
105
+ def test_with_tags
106
+ sample = @sample_file
107
+ cache = ESI::RubyCache.new
108
+ File.open('out-sample.html','w') do|output|
109
+ parser = ESI::CParser.new
110
+ parser.output_handler {|s| output << s }
111
+
112
+ parser.start_tag_handler do|tag_name,attrs|
113
+ tag = ESI::Tag::Base.create(@test_router, {}, {}, tag_name.gsub(/esi:/,''), attrs, cache)
114
+ if parser.esi_tag
115
+ parser.esi_tag.add_child(tag)
116
+ else
117
+ parser.esi_tag = tag
118
+ end
119
+ end
120
+
121
+ parser.end_tag_handler do|tag_name|
122
+ if parser.esi_tag.name == tag_name.gsub(/esi:/,'')
123
+ parser.esi_tag.close(parser.output)
124
+ parser.esi_tag = nil
125
+ else
126
+ parser.esi_tag.close_child(parser.output,tag_name)
127
+ end
128
+ end
129
+ File.open(sample,'r') do|input|
130
+ while( (buf=input.read(128)) and !input.eof? and buf.size != 0 )
131
+ parser.process buf
132
+ end
133
+ parser.process buf
134
+ end
135
+ parser.finish
136
+ end
137
+ output = File.read("out-sample.html")
138
+
139
+ assert_match(/ <div class="body">/, output)
140
+ assert_match(/ <div>some content<\/div>/, output)
141
+ assert_match(/ <!-- a little commentary -->/, output)
142
+ assert_match(%q(<!-- a
143
+ multiline comment -->),output)
144
+ assert_match(%q(<![CDATA[
145
+ Some cdata fun fun fun
146
+ ]]>), output)
147
+ assert_match(/<!DOCTYPE html PUBLIC "-\/\/W3C\/\/DTD XHTML 1.0 Strict\/\/EN" "http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-strict.dtd">/, output)
148
+ assert_no_match(/<esi:/, output)
149
+ assert_match(/<div id='1'>id string<\/div>/, output)
150
+ assert_match(/<div id='3'>id string<\/div>/, output)
151
+
152
+ assert_no_match(/<p>it failed<\/p>/, output)
153
+ assert_match(/<div id='2'>id string<\/div>/, output)
154
+
155
+ assert_match(/<div id='4'>id string<\/div>/, output)
156
+ assert_match(/<p>We should get this or not\?<\/p>/, output)
157
+ assert_match(/<p>Now maybe we shouldn't see this\?<\/p>/, output)
158
+ assert_match(/<p>except worked1<\/p>/, output)
159
+ assert_match(/<p>except worked2<\/p>/, output)
160
+ assert_match(/<\/html>/, output)
161
+ end
162
+
163
+ def test_inline_parse_basics
164
+ output = ""
165
+ parser = ESI::CParser.new
166
+ parser.output_handler {|s| output << s }
167
+ tags = []
168
+ parser.start_tag_handler do|tag_name, attrs|
169
+ tags << {:name => tag_name, :attributes => attrs}
170
+ end
171
+
172
+ parser.process "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input"
173
+ parser.process "some input<esi:include \nsrc='hello'/>some more input\nsome input<esi:include src=\"hello\"/>some more input"
174
+ parser.process "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input"
175
+ parser.process "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input"
176
+ parser.process "</body></html>"
177
+ parser.finish
178
+ assert_equal %Q(<html><head><body>some more inputsome inputsome more input
179
+ some inputsome more inputsome inputsome more input
180
+ some inputsome more input<p>some input</p>some more input
181
+ some inputsome more input</body></html>), output
182
+
183
+ assert_equal 7, tags.size
184
+ include_tags = tags.select {|tag| tag[:name] == 'esi:include'}
185
+ assert_equal 5, include_tags.size
186
+ include_tags.each do|tag|
187
+ assert_equal 'hello', tag[:attributes]['src']
188
+ end
189
+
190
+ inline_tags = tags.select {|tag| tag[:name] == 'esi:inline'}
191
+ assert_equal 1, inline_tags.size
192
+ comment_tags = tags.select {|tag| tag[:name] == 'esi:comment'}
193
+ assert_equal 1, comment_tags.size
194
+
195
+ end
196
+
197
+ def test_block_parser_basics
198
+ output = ""
199
+ parser = ESI::CParser.new
200
+ parser.output_handler {|s| output << s }
201
+ tags = []
202
+ parser.start_tag_handler do|tag_name, attrs|
203
+ tags << {:name => tag_name, :attributes => attrs}
204
+ end
205
+ parser.process "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input<br/>\n"
206
+ parser.process "some input<esi:try><esi:attempt><span>some more input</span></esi:attempt><esi:except><span>\n"
207
+ parser.process "some input</span></esi:except></esi:try>some more input<br/>\n"
208
+ parser.process "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input<br/>\n"
209
+ parser.process "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input<br/>\n"
210
+ parser.process "</body></html>"
211
+ parser.finish
212
+ # assert_equal %Q(some input<span>some more input</span><span>
213
+ #some input</span>some more input<br/>
214
+ #), output
215
+ assert_equal %Q(<html><head><body>some more input<br/>
216
+ some input<span>some more input</span><span>
217
+ some input</span>some more input<br/>
218
+ some inputsome more input
219
+ some inputsome more input<br/>
220
+ <p>some input</p>some more input
221
+ some inputsome more input<br/>
222
+ </body></html>), output
223
+ end
224
+
225
+ def test_empty_parse
226
+ output = ""
227
+ parser = ESI::CParser.new
228
+ parser.output_handler {|s| output << s }
229
+ tags = []
230
+ parser.start_tag_handler do|tag_name, attrs|
231
+ tags << {:name => tag_name, :attributes => attrs}
232
+ end
233
+ assert_nothing_raised do
234
+ parser.process ""
235
+ end
236
+ parser.finish
237
+ end
238
+
239
+ # it's a strange case but, we should still recongize the tag so that it can be pruned from the input stream
240
+ def test_parser_accepts_empty_tag
241
+ output = ""
242
+ parser = ESI::CParser.new
243
+ parser.output_handler {|s| output << s }
244
+ tags = []
245
+ parser.start_tag_handler do|tag_name, attrs|
246
+ tags << {:name => tag_name, :attributes => attrs}
247
+ end
248
+ parser.process "<p>some input</p><esi:include/>some more input\nsome input<esi:include src='hello'/>some more input"
249
+ parser.finish
250
+ assert_equal %Q(<p>some input</p>some more input
251
+ some inputsome more input), output
252
+
253
+ assert_equal 2, tags.size
254
+ assert_equal 'hello', tags.last[:attributes]['src']
255
+ end
256
+
257
+ def test_can_parse_in_chunks
258
+
259
+ output = ""
260
+ parser = ESI::CParser.new
261
+ parser.output_handler {|s| output << s }
262
+ tags = []
263
+ parser.start_tag_handler do|tag_name, attrs|
264
+ tags << {:name => tag_name, :attributes => attrs}
265
+ end
266
+ parser.process "some input<esi:in"
267
+ parser.process "line src='hel"
268
+ parser.process "lo'"
269
+ parser.process "/>some more input\nsome input<esi:comment text='hello'/>some more input"
270
+ parser.finish
271
+
272
+ assert_equal "some inputsome more input\nsome inputsome more input", output
273
+
274
+ assert_equal 2, tags.size
275
+ assert_equal 'hello', tags.first[:attributes]['src']
276
+
277
+ output = ""
278
+ parser = ESI::CParser.new
279
+ parser.output_handler {|s| output << s }
280
+ tags = []
281
+ parser.start_tag_handler do|tag_name, attrs|
282
+ tags << {:name => tag_name, :attributes => attrs}
283
+ end
284
+ parser.process "some input<"
285
+ parser.process "e"
286
+ parser.process "s"
287
+ parser.process "i"
288
+ parser.process ":"
289
+ parser.process "i"
290
+ parser.process "n"
291
+ parser.process "lin"
292
+ parser.process "e"
293
+ parser.process " "
294
+ parser.process "s"
295
+ parser.process "rc"
296
+ parser.process "="
297
+ parser.process "'hel"
298
+ parser.process "lo'"
299
+ parser.process "/"
300
+ parser.process ">some more input\nsome input"
301
+ parser.process "<esi:comment text="
302
+ parser.process "'hello'/>some more input"
303
+ parser.finish
304
+
305
+ assert_equal "some inputsome more input\nsome inputsome more input", output
306
+
307
+ assert_equal 2, tags.size
308
+ assert_equal 1, tags.select{|tag| tag[:name] == 'esi:inline'}.size, "Failed to parse esi:inline"
309
+ assert_equal 1, tags.select{|tag| tag[:name] == 'esi:comment'}.size, "Failed to parse esi:comment"
310
+ assert_equal 'hello', tags.select{|tag| tag[:name] == 'esi:inline'}.first[:attributes]['src'], "Failed to parse esi:inline attributes"
311
+
312
+ end
313
+
314
+ def assert_totals_from_parse(parser)
315
+
316
+ start_trys = 0
317
+ start_attempts = 0
318
+ start_includes = 0
319
+ start_excepts = 0
320
+ start_invalidates = 0
321
+
322
+ parser.start_tag_handler do|tag_name,attrs|
323
+ # puts "\tstart: #{tag_name.inspect}#{attrs.inspect}"
324
+ case tag_name
325
+ when "esi:try" then start_trys += 1
326
+ when "esi:attempt" then start_attempts += 1
327
+ when "esi:include" then start_includes += 1
328
+ when "esi:except" then start_excepts += 1
329
+ when "esi:invalidate" then start_invalidates += 1
330
+ else
331
+ raise "Unverified start: #{tag_name.inspect}#{attrs.inspect}"
332
+ end
333
+ end
334
+
335
+ end_trys = 0
336
+ end_attempts = 0
337
+ end_includes = 0
338
+ end_excepts = 0
339
+ end_invalidates = 0
340
+
341
+ parser.end_tag_handler do|tag_name|
342
+ # puts "\tend: #{tag_name.inspect}"
343
+ case tag_name
344
+ when "esi:try" then end_trys += 1
345
+ when "esi:attempt" then end_attempts += 1
346
+ when "esi:include" then end_includes += 1
347
+ when "esi:except" then end_excepts += 1
348
+ when "esi:invalidate" then end_invalidates += 1
349
+ else
350
+ raise "Unverified start: #{tag_name.inspect}"
351
+ end
352
+ end
353
+
354
+ yield
355
+
356
+ assert_equal 2, start_trys, "More or less esi:try tags detected #{start_trys.inspect}"
357
+ assert_equal 2, start_attempts, "More or less esi:attempt tags detected #{start_attempts.inspect}"
358
+ assert_equal 6, start_includes, "More or less esi:include tags detected #{start_includes.inspect}"
359
+ assert_equal 2, start_excepts, "More or less esi:except tags detected #{start_excepts.inspect}"
360
+ assert_equal 1, start_invalidates, "More or less esi:invalidate tags detected #{start_invalidates.inspect}"
361
+ assert_equal 2, end_trys, "More or less esi:try tags detected #{end_trys.inspect}"
362
+ assert_equal 2, end_attempts, "More or less esi:attempt tags detected #{end_attempts.inspect}"
363
+ assert_equal 6, end_includes, "More or less esi:include tags detected #{end_includes.inspect}"
364
+ assert_equal 2, end_excepts, "More or less esi:except tags detected #{end_excepts.inspect}"
365
+ assert_equal 1, end_invalidates, "More or less esi:invalidate tags detected #{end_invalidates.inspect}"
366
+ end
367
+
368
+ def test_sample
369
+ sample = @sample_file
370
+ output = ""
371
+ parser = ESI::CParser.new
372
+ parser.output_handler {|s| output << s }
373
+ assert_totals_from_parse( parser ) do
374
+ parser.process File.read(sample)
375
+ parser.finish
376
+ end
377
+ assert_no_match /<esi:/, output
378
+
379
+ #8.times do|i|
380
+ i = 4
381
+ File.open(sample,'r') do|input|
382
+ output = ""
383
+ parser = ESI::CParser.new
384
+ parser.output_handler {|s| output << s }
385
+ assert_totals_from_parse( parser ) do
386
+ while( (buf=input.read((i+1)*2)) and !input.eof? and buf.size != 0 )
387
+ parser.process buf
388
+ end
389
+ parser.process buf
390
+ parser.finish
391
+ end
392
+ assert_no_match /<esi:/, output
393
+ end
394
+ # end
395
+
396
+ end
397
+
398
+ def test_embedded_content
399
+ input = %Q(
400
+ <html>
401
+ <head>
402
+ </head>
403
+ <body>
404
+ <h1>This is a test document</h1>
405
+ <esi:try>
406
+ <esi:attempt>
407
+ <div>Some content before</div><esi:include src="/fragments/test1.html" max-age="600+600"/>
408
+ </esi:attempt>
409
+ <esi:except>
410
+ <esi:include src="/fragments/test_failover.html"/>
411
+ </esi:except>
412
+ </esi:try>
413
+ </body>
414
+ </html>)
415
+ output = ""
416
+ parser = ESI::CParser.new
417
+ parser.output_handler {|s| output << s }
418
+ starts = 0
419
+ ends = 0
420
+ parser.start_tag_handler do|tag_name, attrs|
421
+ starts += 1
422
+ end
423
+ parser.end_tag_handler do|tag_name|
424
+ ends += 1
425
+ end
426
+ parser.process input
427
+ parser.finish
428
+ assert_equal 5, starts, "Start tags"
429
+ assert_equal 5, ends, "End tags"
430
+ end
431
+
432
+ def test_basic_invalidate_tag
433
+ parser_input = %Q(<html><body>
434
+ <esi:invalidate output="no">
435
+ <?xml version="1.0"?>
436
+ <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
437
+ <INVALIDATION VERSION="WCS-1.1">
438
+ <OBJECT>
439
+ <BASICSELECTOR URI="/foo/bar"/>
440
+ <ACTION REMOVALTTL="0"/>
441
+ <INFO VALUE="invalidating fragment test 1"/>
442
+ </OBJECT>
443
+ </INVALIDATION>
444
+ </esi:invalidate>
445
+ <esi:invalidate output="no">
446
+ <?xml version="1.0"?>
447
+ <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
448
+ <INVALIDATION VERSION="WCS-1.1">
449
+ <OBJECT>
450
+ <BASICSELECTOR URI="/foo/bar"/>
451
+ <ACTION REMOVALTTL="0"/>
452
+ <INFO VALUE="invalidating fragment test 2"/>
453
+ </OBJECT>
454
+ </INVALIDATION>
455
+ </esi:invalidate>
456
+ </body></html>)
457
+ output = ""
458
+ parser = ESI::CParser.new
459
+ parser.output_handler {|s| output << s }
460
+ start_called = false
461
+ end_called = false
462
+ parser.start_tag_handler do|tag_name, attrs|
463
+ start_called = true
464
+ end
465
+ parser.end_tag_handler do|tag_name|
466
+ end_called = true
467
+ end
468
+ parser.process parser_input
469
+ parser.finish
470
+ assert start_called
471
+ assert end_called
472
+ end
473
+
474
+ # def test_setup
475
+ # puts @output
476
+ # end
477
+
478
+ end