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 @@
1
+ <div>test1</div>
@@ -0,0 +1,9 @@
1
+ <div>test3</div>
2
+ <esi:try>
3
+ <esi:attempt>
4
+ <esi:include src="/fragments/test1.html" max-age="600+600"/>
5
+ </esi:attempt>
6
+ <esi:except>
7
+ <esi:include src="/fragments/test1.html"/>
8
+ </esi:except>
9
+ </esi:try>
@@ -0,0 +1 @@
1
+ <div>test failover</div>
@@ -0,0 +1,270 @@
1
+ require "#{File.dirname(__FILE__)}/help"
2
+
3
+ class HandlerTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ ESI::Server.start
7
+ end
8
+
9
+ def test_more_web_server
10
+ results = hit([ "http://localhost:9997/esi_test_content.html", "http://localhost:9997/esi_mixed_content.html"])
11
+
12
+ results.each do |res|
13
+ assert_match $fragment_test1, res
14
+ assert_no_match /<esi:/, res # assert there are no esi tags in the result
15
+ end
16
+ check_status results, String
17
+ end
18
+
19
+ def test_simple_esi
20
+ Net::HTTP.start("localhost", 9997) do |h|
21
+ req = h.get("/esi_test_content.html")
22
+ assert_not_nil req
23
+ assert_not_nil req.header
24
+ assert_not_nil req.body
25
+ assert_equal Net::HTTPOK, req.header.class
26
+ assert_match $fragment_test1, req.body, "Fragment not found"
27
+ assert_match $fragment_test2, req.body, "Fragment not found"
28
+ end
29
+ end
30
+
31
+ def test_large_document
32
+ Net::HTTP.start("localhost", 9997) do |h|
33
+ req = h.get("/index.html")
34
+ assert_not_nil req
35
+ assert_not_nil req.header
36
+ assert_not_nil req.body
37
+ assert_equal Net::HTTPOK, req.header.class
38
+ assert_match $fragment_test1, req.body, "Fragment not found"
39
+ # should have 37 fragments
40
+ count = 0
41
+ req.body.scan $fragment_test1 do|m|
42
+ count += 1
43
+ end
44
+ assert_equal 37, count, "There should be 37 fragments in the document"
45
+ end
46
+ end
47
+
48
+ def test_reverse_proxy
49
+ Net::HTTP.start("localhost", 9997) do |h|
50
+ req = h.get("/content/foo.html")
51
+ assert_not_nil req
52
+ assert_not_nil req.header
53
+ assert_not_nil req.body
54
+ assert_equal Net::HTTPOK, req.header.class
55
+ assert_match $fragment_test2, req.body, "Fragment not found"
56
+ end
57
+ end
58
+
59
+ def test_post
60
+ Net::HTTP.start("localhost","9997") do |http|
61
+ post_str = "key=value"
62
+ assert_match post_str, http.post("/post_test",post_str).read_body, "HTTP POST failed"
63
+ end
64
+ end
65
+
66
+ def test_ajax_post
67
+ Net::HTTP.start("localhost","9997") do |http|
68
+ post_str = "key=value"
69
+ post_result = http.post("/post_test", post_str,{"X-Requested-With" => "XMLHttpRequest"}).read_body
70
+ assert_match post_str, post_result, "HTTP Ajax POST failed"
71
+ end
72
+ end
73
+
74
+ def test_post_redirect
75
+ Net::HTTP.start("localhost","9997") do |http|
76
+ post_str = "key=value"
77
+ res = http.post("/post_redirect_test", post_str)
78
+ assert_equal Net::HTTPFound, res.class
79
+ assert_equal "/esi_test_content.html", res["Location"]
80
+ end
81
+ end
82
+
83
+ def test_get_redirect
84
+ Net::HTTP.start("localhost","9997") do |http|
85
+ res = http.get("/post_redirect_test")
86
+ assert_equal Net::HTTPFound, res.class
87
+ assert_equal "/esi_test_content.html", res["Location"]
88
+ end
89
+ end
90
+
91
+ # test that we're including http headers as part of the request fragment cache
92
+ def test_ajax_caching
93
+ # start by making the request using the X-Requested-With Header
94
+ Net::HTTP.start("localhost", 9997) do |h|
95
+ req = h.get("/content/ajax_test_page.html", {"X-Requested-With" => "XMLHttpRequest"})
96
+ assert_not_nil req
97
+ assert_not_nil req.header
98
+ assert_not_nil req.body
99
+ assert_equal Net::HTTPOK, req.header.class
100
+ assert_match "XMLHttpRequest", req.body, "Did not get the expected response for Javascript, should see XMLHttpRequest in the response"
101
+ end
102
+ # now the content should be cached so make the request again without the javascript header to get the alternate version
103
+ Net::HTTP.start("localhost", 9997) do |h|
104
+ req = h.get("/content/ajax_test_page.html")
105
+ assert_not_nil req
106
+ assert_not_nil req.header
107
+ assert_not_nil req.body
108
+ assert_equal Net::HTTPOK, req.header.class
109
+ assert_match "HTTP Request", req.body, "Did not get the expected response for noscript"
110
+ end
111
+ # make the ajax request one more time for good measure
112
+ Net::HTTP.start("localhost", 9997) do |h|
113
+ req = h.get("/content/ajax_test_page.html", {"X-Requested-With" => "XMLHttpRequest"})
114
+ assert_not_nil req
115
+ assert_not_nil req.header
116
+ assert_not_nil req.body
117
+ assert_equal Net::HTTPOK, req.header.class
118
+ assert_match "XMLHttpRequest", req.body, "Did not get the expected response for Javascript"
119
+ end
120
+ end
121
+
122
+ # test that if a fragment has a <esi include in it, that response comes back with a rendered module
123
+ def test_fragment_in_fragment
124
+ Net::HTTP.start("localhost", 9997) do |h|
125
+ req = h.get("/content/include_in_include.html")
126
+ assert_not_nil req
127
+ assert_not_nil req.header
128
+ assert_not_nil req.body
129
+ assert_equal Net::HTTPOK, req.header.class
130
+ assert_no_match /<esi:/, req.body, "Result still contains esi includes" # assert there are no esi tags in the result
131
+ assert_match /<div>test3<\/div>/, req.body, "assert fragment is included"
132
+ assert_match /<div>test1<\/div>/, req.body, "assert inner fragment is included"
133
+ end
134
+ end
135
+
136
+ # test whether the cache server alters the markup
137
+ def test_markup
138
+ Net::HTTP.start("localhost", 9997) do |h|
139
+ req = h.get("/content/malformed_transforms.html")
140
+ assert_not_nil req
141
+ assert_not_nil req.header
142
+ assert_not_nil req.body
143
+ assert_equal Net::HTTPOK, req.header.class
144
+ assert_equal File.open("#{DOCROOT}/content/malformed_transforms.html-correct").read, req.body
145
+ end
146
+ end
147
+
148
+ def test_failing_fragments
149
+ Net::HTTP.start("localhost", 9997) do |h|
150
+ res = h.get("/content/500.html")
151
+ assert_not_nil res
152
+ assert_not_nil res.header
153
+ assert_not_nil res.body
154
+ assert_equal Net::HTTPOK, res.header.class, res.body
155
+ end
156
+ end
157
+
158
+ def test_failing_fragments_can_failover
159
+ Net::HTTP.start("localhost", 9997) do |h|
160
+ res = h.get("/content/500_with_failover.html")
161
+ assert_not_nil res
162
+ assert_not_nil res.header
163
+ assert_not_nil res.body
164
+ assert_equal Net::HTTPOK, res.header.class, res.body
165
+ assert_match /<div>test1<\/div>/, res.body, "The failover esi include should have been requested"
166
+ end
167
+ end
168
+
169
+ def test_failing_fragments_can_failover_to_alt_attribute
170
+ Net::HTTP.start("localhost", 9997) do |h|
171
+ res = h.get("/content/500_with_failover_to_alt.html")
172
+ assert_not_nil res
173
+ assert_not_nil res.header
174
+ assert_not_nil res.body
175
+ assert_equal Net::HTTPOK, res.header.class, res.body
176
+ assert_match /<div>test1<\/div>/, res.body, "The failover esi include should have been requested"
177
+ end
178
+ end
179
+
180
+ def test_static_failover
181
+ Net::HTTP.start("localhost", 9997) do |h|
182
+ res = h.get("/content/static-failover.html")
183
+ assert_not_nil res
184
+ assert_not_nil res.header
185
+ assert_not_nil res.body
186
+ #puts res.body
187
+ assert_equal Net::HTTPOK, res.header.class, res.body
188
+ assert_match /<div>test1<\/div>/, res.body, "Normal esi include tags failed"
189
+ assert_match /<div>test1<\/div>/, res.body, "Normal esi include tags failed"
190
+ assert_match /<a href="www.akamai.com">www.example.com <\/a>/, res.body, "Static Failover failed"
191
+ end
192
+ end
193
+
194
+ def test_cookies_proxied
195
+ Net::HTTP.start("localhost", 9997) do |h|
196
+ post_str = "key=value"
197
+ req = h.post("/post_test",post_str)
198
+ assert_not_nil req
199
+ assert_not_nil req.header
200
+ assert_not_nil req.body
201
+ assert_equal Net::HTTPOK, req.header.class
202
+ assert_match TEST_COOKIE1, req.header["Set-Cookie"]
203
+ assert_match TEST_COOKIE2, req.header["Set-Cookie"]
204
+ assert_match TEST_COOKIE3, req.header["Set-Cookie"]
205
+ end
206
+ end
207
+
208
+ def test_markup_in_attempt_passed_through
209
+ Net::HTTP.start("localhost", 9997) do |h|
210
+ res = h.get("/content/test3.html")
211
+ assert_not_nil res
212
+ assert_not_nil res.header
213
+ assert_not_nil res.body
214
+ assert_equal Net::HTTPOK, res.header.class
215
+ assert_match /<p>Some markup that should not be lost<\/p>/, res.body
216
+ end
217
+ end
218
+
219
+ def test_markup_in_except_passed_through
220
+ # TODO
221
+ end
222
+
223
+ def test_surrogate_control_header
224
+ # first tell the esi handler to use the surrogate control header
225
+ $esi_dispatcher.config.config.send(:store,:enable_for_surrogate_only, true)
226
+ Net::HTTP.start("localhost", 9997) do |h|
227
+ res = h.get("/404")
228
+ assert_not_nil res
229
+ assert_not_nil res.header
230
+ assert_not_nil res.body
231
+ assert_equal Net::HTTPNotFound, res.header.class
232
+ assert_match /#{$fragment_test1}/, res.body
233
+ end
234
+ $esi_dispatcher.config.config.send(:store,:enable_for_surrogate_only, nil)
235
+
236
+ Net::HTTP.start("localhost", 9997) do |h|
237
+ res = h.get("/404-no-surrogate")
238
+ assert_not_nil res
239
+ assert_not_nil res.header
240
+ assert_not_nil res.body
241
+ assert_equal Net::HTTPNotFound, res.header.class
242
+ assert_no_match /#{$fragment_test1}/, res.body
243
+ end
244
+ end
245
+
246
+ def test_invalidation
247
+ Net::HTTP.start("localhost", 9997) do |h|
248
+ res = h.get("/esi_test_content.html")
249
+ assert_not_nil res
250
+ assert_not_nil res.header
251
+ assert_not_nil res.body
252
+ assert_equal Net::HTTPOK, res.header.class
253
+ assert_match $fragment_test1, res.body, "Fragment not found"
254
+ assert_match $fragment_test2, res.body, "Fragment not found"
255
+ end
256
+
257
+ assert cached?( FRAGMENT_TEST1_URI ), "Error Fragment should be cached!"
258
+ assert cached?( FRAGMENT_TEST2_URI ), "Error Fragment should be cached!"
259
+
260
+ Net::HTTP.start("localhost", 9997) do |h|
261
+ res = h.get("/esi_invalidate.html")
262
+ end
263
+
264
+ assert !cached?( FRAGMENT_TEST1_URI ), "Error Fragment 1 should not be cached!"
265
+ assert !cached?( FRAGMENT_TEST2_URI ), "Error Fragment 2 should not be cached!"
266
+ end
267
+
268
+
269
+ end
270
+
@@ -0,0 +1,234 @@
1
+ # modified version from mongrel
2
+ # This code is moving into integration test folder
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
4
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "ext")
5
+ require 'esi/dispatcher'
6
+ require 'test/unit'
7
+ SERVER_ROOT = "#{File.dirname(__FILE__)}/../../"
8
+ ENV["test"] = "true"
9
+ DOCROOT = "#{File.dirname(__FILE__)}/docs/"
10
+
11
+ # Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
12
+ # HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
13
+ def hit(uris)
14
+ results = []
15
+ uris.each do |u|
16
+ res = nil
17
+
18
+ assert_nothing_raised do
19
+ if u.kind_of? String
20
+ res = Net::HTTP.get(URI.parse(u))
21
+ else
22
+ url = URI.parse(u[0])
23
+ res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) }
24
+ end
25
+ end
26
+
27
+ assert_not_nil res, "Didn't get a response: #{u}"
28
+ results << res
29
+ end
30
+
31
+ return results
32
+ end
33
+
34
+ def check_status(results, expecting)
35
+ results.each do |res|
36
+ assert(res.kind_of?(expecting), "Didn't get #{expecting}, got: #{res.class}")
37
+ end
38
+ end
39
+
40
+
41
+ class MockRequest
42
+ def initialize(params={})
43
+ @params = params
44
+ end
45
+ def params
46
+ @params
47
+ end
48
+ end
49
+
50
+ def cached?( uri )
51
+ $esi_dispatcher.config.cache.get( uri, {} )
52
+ end
53
+
54
+ require 'singleton'
55
+
56
+ TEST_COOKIE1 = "s_cc=true; s_sq=%5B%5BB%5D%5D; _session_id=367df8904d23ee48ddac56012b9d509f;".freeze
57
+ TEST_COOKIE2 = "rhg_gsid=83d7e46425b431c6651e2beb3e4fd9e41175970072%3A; cookies_enabled=true;".freeze
58
+ TEST_COOKIE3 = "RTOKEN=dG9kZGZAc2ltb2hlYWx0aC5jb20%3D; rhg_sa=xbSssuHwmP5rohZ0Pcu%2BmaU3bSFU%2Br1eBq4iZgTd%2BbQ%3D; edn=Z%25A16W%25E9F%25D4f%25A5%2522j%255D%25DA%2528%2585%2586; ems=%25F2%25A9%25FBlZ%2594.a%253D%250A%251F%2506%25BD%251B%25BA%25EC; av=13; s_se_sig=dG9kZGZAc2ltb2hlYWx0aC5jb20%253D; rhg_css_to_warn=1175974191515".freeze
59
+ FRAGMENT_TEST1_URI = "http://127.0.0.1:9998/fragments/test1.html".freeze
60
+ FRAGMENT_TEST2_URI = "http://127.0.0.1:9999/content/test2.html".freeze
61
+
62
+ class PostHandler < Mongrel::HttpHandler
63
+ include Mongrel::HttpHandlerPlugin
64
+ def process(request, response)
65
+ response.start(200,true) do |head,out|
66
+ head["Set-Cookie"] = TEST_COOKIE1
67
+ head["Set-Cookie"] = TEST_COOKIE2
68
+ head["Set-Cookie"] = TEST_COOKIE3
69
+ out << request.body.read
70
+ end
71
+ end
72
+ end
73
+
74
+ class PostRedirectHandler < Mongrel::HttpHandler
75
+ include Mongrel::HttpHandlerPlugin
76
+ def process(request, response)
77
+ response.start(302,true) do |head,out|
78
+ head["Location"] = "/esi_test_content.html"
79
+ out << %Q(<html><body>You are being <a href="/test1.html">redirected</a>.</body></html>)
80
+ end
81
+ end
82
+ end
83
+
84
+ class Basic404Handler < Mongrel::HttpHandler
85
+ include Mongrel::HttpHandlerPlugin
86
+ def process(request, response)
87
+ response.start(404,true) do |head,out|
88
+ head["Surrogate-Control"] = %q(max-age=0, content="ESI/1.0 ESI-INV/1.0")
89
+ out << %q(<html><body><esi:include src='/test1.html'/></body></html>)
90
+ end
91
+ end
92
+ end
93
+
94
+ class Basic404HandlerWithoutHeader < Mongrel::HttpHandler
95
+ include Mongrel::HttpHandlerPlugin
96
+ def process(request, response)
97
+ response.start(404,true) do |head,out|
98
+ #head["Surrogate-Control"] = %q(max-age=0, content="ESI/1.0 ESI-INV/1.0")
99
+ out << %q(<html><body><esi:include src='/test1.html'/></body></html>)
100
+ end
101
+ end
102
+ end
103
+
104
+ class AjaxCacheHandler < Mongrel::HttpHandler
105
+ include Mongrel::HttpHandlerPlugin
106
+ def process(request, response)
107
+ response.start(200,true) do |head,out|
108
+ # return hello if requested with
109
+ if request.params["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
110
+ out << "XMLHttpRequest Request"
111
+ else
112
+ out << "HTTP Request"
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ class InvalidateHandler < Mongrel::HttpHandler
119
+ include Mongrel::HttpHandlerPlugin
120
+ def process(request, response)
121
+ response.start(200,true) do |head,out|
122
+ head["Surrogate-Control"] = %q(max-age=0, content="ESI/1.0 ESI-INV/1.0")
123
+
124
+ out << %Q(<html><body>
125
+ <esi:invalidate output="no">
126
+ <?xml version="1.0"?>
127
+ <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
128
+ <INVALIDATION VERSION="WCS-1.1">
129
+ <OBJECT>
130
+ <BASICSELECTOR URI="#{FRAGMENT_TEST1_URI}"/>
131
+ <ACTION REMOVALTTL="0"/>
132
+ <INFO VALUE="invalidating fragment test 1"/>
133
+ </OBJECT>
134
+ </INVALIDATION>
135
+ </esi:invalidate>
136
+ <esi:invalidate output="no">
137
+ <?xml version="1.0"?>
138
+ <!DOCTYPE INVALIDATION SYSTEM "internal:///WCSinvalidation.dtd">
139
+ <INVALIDATION VERSION="WCS-1.1">
140
+ <OBJECT>
141
+ <BASICSELECTOR URI="#{FRAGMENT_TEST2_URI}"/>
142
+ <ACTION REMOVALTTL="0"/>
143
+ <INFO VALUE="invalidating fragment test 2"/>
144
+ </OBJECT>
145
+ </INVALIDATION>
146
+ </esi:invalidate>
147
+ </body></html>)
148
+ end
149
+ end
150
+ end
151
+
152
+ $fragment_test1 = File.open("#{DOCROOT}/test1.html").read
153
+ $fragment_test2 = File.open("#{DOCROOT}/content/test2.html").read
154
+
155
+
156
+
157
+ $esi_dispatcher = ESI::Dispatcher.new(
158
+ :host => '127.0.0.1',
159
+ :port => 9997,
160
+ :cwd => SERVER_ROOT,
161
+ :log_file => 'log/test.log',
162
+ :pid_file => 'log/test.pid',
163
+ :daemon => false,
164
+ :debug => true,
165
+ :includes => ["mongrel-esi"],
166
+ :user => nil,
167
+ :group => nil,
168
+ :prefix => '/',
169
+ :config_file => nil,
170
+ :routing => [{:host => '127.0.0.1', :port => '9999', :match_url => '^\/(content|samples|extra|get_test).*'},
171
+ {:host => '127.0.0.1', :port => '9998', :match_url => 'default'}],
172
+ :cache => 'ruby',
173
+ :cache_options => {:servers => ['localhost:11211'], :debug => false, :namespace => 'mesi', :readyonly => false},
174
+ :allowed_content_types => ['text/plain', 'text/html'],
175
+ :enable_for_surrogate_only => false,
176
+ :invalidator => false
177
+ )
178
+
179
+ # allow access to the internal parser
180
+ class ESI::Handler
181
+ attr_reader :parser
182
+ end
183
+
184
+ module ESI
185
+ class Server
186
+ include Singleton
187
+
188
+ CONFIG = [
189
+ { :host_port => { :host => '127.0.0.1', :port => 9999 },
190
+ :handlers => [
191
+ { :uri => '/', :handler => Mongrel::DirHandler.new(DOCROOT) },
192
+ { :uri => '/get_test', :handler => AjaxCacheHandler.new(DOCROOT) }
193
+ ]
194
+ },
195
+ { :host_port => { :host => '127.0.0.1', :port => 9998 },
196
+ :handlers => [
197
+ { :uri => "/", :handler => Mongrel::DirHandler.new(DOCROOT) },
198
+ { :uri => "/fragments/", :handler => Mongrel::DirHandler.new(DOCROOT) },
199
+ { :uri => '/post_test', :handler => PostHandler.new },
200
+ { :uri => '/post_redirect_test', :handler => PostRedirectHandler.new },
201
+ { :uri => '/404', :handler => Basic404Handler.new },
202
+ { :uri => '/404-no-surrogate', :handler => Basic404HandlerWithoutHeader.new },
203
+ { :uri => '/invalidate', :handler => InvalidateHandler.new }
204
+ ]
205
+ },
206
+ { :host_port => { :host => '127.0.0.1', :port => 9997 },
207
+ :handlers => [
208
+ { :uri => "/", :handler => $esi_dispatcher }
209
+ ]
210
+ }
211
+ ]
212
+
213
+ def self.start
214
+ ESI::Server.instance
215
+ end
216
+
217
+ def initialize
218
+ @servers = CONFIG.collect do|conf|
219
+ Mongrel::Configurator.new conf[:host_port] do
220
+ listener do
221
+ conf[:handlers].each do|handler|
222
+ uri handler[:uri], :handler => handler[:handler]
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ @servers.each { |server| server.run }
229
+ at_exit do
230
+ @servers.each { |server| server.stop }
231
+ end
232
+ end
233
+ end
234
+ end