mongrel_esi 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (202) hide show
  1. data/Rakefile +14 -6
  2. data/doc/rdoc/classes/ESI/CParser.html +122 -0
  3. data/doc/rdoc/classes/ESI/Cache.html +178 -0
  4. data/doc/rdoc/classes/ESI/Cache.src/M000085.html +17 -0
  5. data/doc/rdoc/classes/ESI/Cache.src/M000086.html +20 -0
  6. data/doc/rdoc/classes/ESI/Config.html +333 -0
  7. data/doc/rdoc/classes/ESI/Config.src/M000052.html +18 -0
  8. data/doc/rdoc/classes/ESI/Config.src/M000053.html +18 -0
  9. data/doc/rdoc/classes/ESI/Config.src/M000054.html +35 -0
  10. data/doc/rdoc/classes/ESI/Config.src/M000055.html +38 -0
  11. data/doc/rdoc/classes/ESI/Config.src/M000056.html +23 -0
  12. data/doc/rdoc/classes/ESI/Config.src/M000057.html +18 -0
  13. data/doc/rdoc/classes/ESI/Config.src/M000058.html +20 -0
  14. data/doc/rdoc/classes/ESI/Config.src/M000059.html +18 -0
  15. data/doc/rdoc/classes/ESI/Config.src/M000060.html +24 -0
  16. data/doc/rdoc/classes/ESI/Config/CacheConfig.html +212 -0
  17. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000064.html +19 -0
  18. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000065.html +19 -0
  19. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000066.html +18 -0
  20. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000067.html +18 -0
  21. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000068.html +18 -0
  22. data/doc/rdoc/classes/ESI/Config/ConfigRouter.html +187 -0
  23. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000061.html +19 -0
  24. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000062.html +21 -0
  25. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000063.html +21 -0
  26. data/doc/rdoc/classes/ESI/Dispatcher.html +172 -0
  27. data/doc/rdoc/classes/ESI/Dispatcher.src/M000087.html +22 -0
  28. data/doc/rdoc/classes/ESI/Dispatcher.src/M000088.html +18 -0
  29. data/doc/rdoc/classes/ESI/Fragment.html +218 -0
  30. data/doc/rdoc/classes/ESI/Fragment.src/M000100.html +20 -0
  31. data/doc/rdoc/classes/ESI/Fragment.src/M000101.html +18 -0
  32. data/doc/rdoc/classes/ESI/Fragment.src/M000102.html +18 -0
  33. data/doc/rdoc/classes/ESI/Invalidator.html +131 -0
  34. data/doc/rdoc/classes/ESI/Invalidator.src/M000004.html +41 -0
  35. data/doc/rdoc/classes/ESI/Log.html +221 -0
  36. data/doc/rdoc/classes/ESI/Log.src/M000030.html +18 -0
  37. data/doc/rdoc/classes/ESI/Log.src/M000031.html +18 -0
  38. data/doc/rdoc/classes/ESI/Log.src/M000032.html +18 -0
  39. data/doc/rdoc/classes/ESI/Log.src/M000033.html +18 -0
  40. data/doc/rdoc/classes/ESI/Log.src/M000034.html +18 -0
  41. data/doc/rdoc/classes/ESI/Log.src/M000035.html +18 -0
  42. data/doc/rdoc/classes/ESI/Log.src/M000036.html +18 -0
  43. data/doc/rdoc/classes/ESI/MemcachedCache.html +314 -0
  44. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000040.html +24 -0
  45. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000041.html +22 -0
  46. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000042.html +19 -0
  47. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000043.html +23 -0
  48. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000044.html +18 -0
  49. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000045.html +19 -0
  50. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000046.html +18 -0
  51. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000047.html +18 -0
  52. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000048.html +17 -0
  53. data/doc/rdoc/classes/ESI/Parser.html +184 -0
  54. data/doc/rdoc/classes/ESI/Parser.src/M000049.html +51 -0
  55. data/doc/rdoc/classes/ESI/Parser.src/M000050.html +39 -0
  56. data/doc/rdoc/classes/ESI/Parser.src/M000051.html +19 -0
  57. data/doc/rdoc/classes/ESI/Processor.html +194 -0
  58. data/doc/rdoc/classes/ESI/Processor.src/M000037.html +26 -0
  59. data/doc/rdoc/classes/ESI/Processor.src/M000038.html +44 -0
  60. data/doc/rdoc/classes/ESI/Processor.src/M000039.html +26 -0
  61. data/doc/rdoc/classes/ESI/Proxy.html +304 -0
  62. data/doc/rdoc/classes/ESI/Proxy.src/M000069.html +20 -0
  63. data/doc/rdoc/classes/ESI/Proxy.src/M000070.html +55 -0
  64. data/doc/rdoc/classes/ESI/Proxy.src/M000071.html +53 -0
  65. data/doc/rdoc/classes/ESI/Proxy.src/M000072.html +25 -0
  66. data/doc/rdoc/classes/ESI/Proxy.src/M000073.html +19 -0
  67. data/doc/rdoc/classes/ESI/Proxy.src/M000074.html +27 -0
  68. data/doc/rdoc/classes/ESI/Proxy.src/M000075.html +18 -0
  69. data/doc/rdoc/classes/ESI/Proxy.src/M000076.html +28 -0
  70. data/doc/rdoc/classes/ESI/Proxy.src/M000077.html +29 -0
  71. data/doc/rdoc/classes/ESI/Response.html +250 -0
  72. data/doc/rdoc/classes/ESI/Response.src/M000078.html +23 -0
  73. data/doc/rdoc/classes/ESI/Response.src/M000079.html +18 -0
  74. data/doc/rdoc/classes/ESI/Response.src/M000080.html +21 -0
  75. data/doc/rdoc/classes/ESI/Response.src/M000081.html +20 -0
  76. data/doc/rdoc/classes/ESI/Response.src/M000082.html +25 -0
  77. data/doc/rdoc/classes/ESI/Response.src/M000083.html +18 -0
  78. data/doc/rdoc/classes/ESI/Response.src/M000084.html +33 -0
  79. data/doc/rdoc/classes/ESI/Router.html +212 -0
  80. data/doc/rdoc/classes/ESI/Router.src/M000098.html +36 -0
  81. data/doc/rdoc/classes/ESI/Router.src/M000099.html +25 -0
  82. data/doc/rdoc/classes/ESI/RubyCache.html +278 -0
  83. data/doc/rdoc/classes/ESI/RubyCache.src/M000089.html +20 -0
  84. data/doc/rdoc/classes/ESI/RubyCache.src/M000090.html +20 -0
  85. data/doc/rdoc/classes/ESI/RubyCache.src/M000091.html +20 -0
  86. data/doc/rdoc/classes/ESI/RubyCache.src/M000092.html +22 -0
  87. data/doc/rdoc/classes/ESI/RubyCache.src/M000093.html +18 -0
  88. data/doc/rdoc/classes/ESI/RubyCache.src/M000094.html +22 -0
  89. data/doc/rdoc/classes/ESI/RubyCache.src/M000095.html +18 -0
  90. data/doc/rdoc/classes/ESI/RubyCache.src/M000096.html +18 -0
  91. data/doc/rdoc/classes/ESI/RubyCache.src/M000097.html +18 -0
  92. data/doc/rdoc/classes/ESI/Tag.html +141 -0
  93. data/doc/rdoc/classes/ESI/Tag/Attempt.html +113 -0
  94. data/doc/rdoc/classes/ESI/Tag/Base.html +237 -0
  95. data/doc/rdoc/classes/ESI/Tag/Base.src/M000026.html +23 -0
  96. data/doc/rdoc/classes/ESI/Tag/Base.src/M000027.html +22 -0
  97. data/doc/rdoc/classes/ESI/Tag/Base.src/M000028.html +22 -0
  98. data/doc/rdoc/classes/ESI/Tag/Base.src/M000029.html +17 -0
  99. data/doc/rdoc/classes/ESI/Tag/Container.html +206 -0
  100. data/doc/rdoc/classes/ESI/Tag/Container.src/M000015.html +20 -0
  101. data/doc/rdoc/classes/ESI/Tag/Container.src/M000016.html +22 -0
  102. data/doc/rdoc/classes/ESI/Tag/Container.src/M000017.html +25 -0
  103. data/doc/rdoc/classes/ESI/Tag/Except.html +184 -0
  104. data/doc/rdoc/classes/ESI/Tag/Except.src/M000018.html +21 -0
  105. data/doc/rdoc/classes/ESI/Tag/Except.src/M000019.html +20 -0
  106. data/doc/rdoc/classes/ESI/Tag/Except.src/M000020.html +18 -0
  107. data/doc/rdoc/classes/ESI/Tag/Include.html +257 -0
  108. data/doc/rdoc/classes/ESI/Tag/Include.src/M000005.html +20 -0
  109. data/doc/rdoc/classes/ESI/Tag/Include.src/M000006.html +18 -0
  110. data/doc/rdoc/classes/ESI/Tag/Include.src/M000007.html +34 -0
  111. data/doc/rdoc/classes/ESI/Tag/Include.src/M000008.html +22 -0
  112. data/doc/rdoc/classes/ESI/Tag/Include.src/M000009.html +27 -0
  113. data/doc/rdoc/classes/ESI/Tag/Include.src/M000010.html +30 -0
  114. data/doc/rdoc/classes/ESI/Tag/Include.src/M000011.html +51 -0
  115. data/doc/rdoc/classes/ESI/Tag/Include/Request.html +199 -0
  116. data/doc/rdoc/classes/ESI/Tag/Include/Request.src/M000012.html +18 -0
  117. data/doc/rdoc/classes/ESI/Tag/Include/Request.src/M000013.html +44 -0
  118. data/doc/rdoc/classes/ESI/Tag/Include/Request/Error.html +155 -0
  119. data/doc/rdoc/classes/ESI/Tag/Include/Request/Error.src/M000014.html +19 -0
  120. data/doc/rdoc/classes/ESI/Tag/Invalidate.html +171 -0
  121. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000023.html +19 -0
  122. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000024.html +51 -0
  123. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000025.html +19 -0
  124. data/doc/rdoc/classes/ESI/Tag/Try.html +154 -0
  125. data/doc/rdoc/classes/ESI/Tag/Try.src/M000021.html +38 -0
  126. data/doc/rdoc/classes/ESI/Tag/Try.src/M000022.html +18 -0
  127. data/doc/rdoc/classes/MultiDirHandler.html +198 -0
  128. data/doc/rdoc/classes/MultiDirHandler.src/M000001.html +20 -0
  129. data/doc/rdoc/classes/MultiDirHandler.src/M000002.html +28 -0
  130. data/doc/rdoc/classes/MultiDirHandler.src/M000003.html +22 -0
  131. data/doc/rdoc/created.rid +1 -0
  132. data/doc/rdoc/files/COPYING.html +167 -0
  133. data/doc/rdoc/files/LICENSE.html +605 -0
  134. data/doc/rdoc/files/README.html +359 -0
  135. data/doc/rdoc/files/ext/esi/common_rl.html +160 -0
  136. data/doc/rdoc/files/ext/esi/esi_parser_c.html +101 -0
  137. data/doc/rdoc/files/ext/esi/parser_c.html +101 -0
  138. data/doc/rdoc/files/ext/esi/parser_h.html +101 -0
  139. data/doc/rdoc/files/ext/esi/parser_rl.html +827 -0
  140. data/doc/rdoc/files/ext/esi/test/common_rl.html +160 -0
  141. data/doc/rdoc/files/ext/esi/test/parser_c.html +101 -0
  142. data/doc/rdoc/files/ext/esi/test/parser_h.html +101 -0
  143. data/doc/rdoc/files/ext/esi/test/parser_rl.html +827 -0
  144. data/doc/rdoc/files/ext/esi/test/sp_c.html +101 -0
  145. data/doc/rdoc/files/ext/esi/test/test_c.html +101 -0
  146. data/doc/rdoc/files/lib/esi/cache_rb.html +119 -0
  147. data/doc/rdoc/files/lib/esi/config_rb.html +114 -0
  148. data/doc/rdoc/files/lib/esi/dispatcher_rb.html +108 -0
  149. data/doc/rdoc/files/lib/esi/invalidator_rb.html +114 -0
  150. data/doc/rdoc/files/lib/esi/logger_rb.html +108 -0
  151. data/doc/rdoc/files/lib/esi/parser_rb.html +120 -0
  152. data/doc/rdoc/files/lib/esi/processor_rb.html +115 -0
  153. data/doc/rdoc/files/lib/esi/proxy_rb.html +123 -0
  154. data/doc/rdoc/files/lib/esi/response_rb.html +116 -0
  155. data/doc/rdoc/files/lib/esi/router_rb.html +107 -0
  156. data/doc/rdoc/files/lib/esi/tag/attempt_rb.html +114 -0
  157. data/doc/rdoc/files/lib/esi/tag/base_rb.html +114 -0
  158. data/doc/rdoc/files/lib/esi/tag/container_rb.html +115 -0
  159. data/doc/rdoc/files/lib/esi/tag/except_rb.html +114 -0
  160. data/doc/rdoc/files/lib/esi/tag/include_rb.html +116 -0
  161. data/doc/rdoc/files/lib/esi/tag/invalidate_rb.html +115 -0
  162. data/doc/rdoc/files/lib/esi/tag/try_rb.html +115 -0
  163. data/doc/rdoc/files/lib/esi/version_rb.html +101 -0
  164. data/doc/rdoc/files/lib/multi_dirhandler_rb.html +109 -0
  165. data/doc/rdoc/fr_class_index.html +53 -0
  166. data/doc/rdoc/fr_file_index.html +59 -0
  167. data/doc/rdoc/fr_method_index.html +128 -0
  168. data/doc/rdoc/index.html +24 -0
  169. data/doc/rdoc/rdoc-style.css +208 -0
  170. data/ext/esi/esi_parser.c +12 -1
  171. data/ext/esi/parser.c +492 -3927
  172. data/ext/esi/parser.rl +83 -14
  173. data/ext/esi/test/parser.c +1587 -367
  174. data/ext/esi/test/parser.rl +83 -14
  175. data/ext/esi/test/sp.c +125 -0
  176. data/ext/esi/test/test.c +198 -6
  177. data/lib/esi/cache.rb +5 -8
  178. data/lib/esi/config.rb +3 -3
  179. data/lib/esi/dispatcher.rb +2 -4
  180. data/lib/esi/parser.rb +26 -13
  181. data/lib/esi/processor.rb +13 -35
  182. data/lib/esi/proxy.rb +113 -44
  183. data/lib/esi/response.rb +23 -55
  184. data/lib/esi/router.rb +0 -11
  185. data/lib/esi/tag/attempt.rb +2 -1
  186. data/lib/esi/tag/base.rb +1 -24
  187. data/lib/esi/tag/container.rb +40 -0
  188. data/lib/esi/tag/except.rb +3 -1
  189. data/lib/esi/tag/include.rb +53 -62
  190. data/lib/esi/tag/try.rb +16 -18
  191. data/lib/esi/version.rb +9 -0
  192. data/test/integration/handler_test.rb +49 -12
  193. data/test/integration/help.rb +12 -0
  194. data/test/load_test.rb +8 -4
  195. data/test/load_test_ab.rb +8 -0
  196. data/test/sample.html +31 -0
  197. data/test/unit/help.rb +12 -8
  198. data/test/unit/include_request_test.rb +14 -21
  199. data/test/unit/parser_test.rb +2 -1
  200. data/test/unit/response_test.rb +4 -8
  201. data/tools/rakehelp.rb +1 -1
  202. metadata +216 -5
data/lib/esi/cache.rb CHANGED
@@ -168,17 +168,14 @@ module ESI
168
168
 
169
169
  def cached?( uri, params )
170
170
  key = cache_key(uri,params)
171
- @semaphore.synchronize do
172
- fragment = @cache[key]
173
- fragment and fragment.valid?
174
- end
171
+ fragment = @semaphore.synchronize { @cache[key] }
172
+ fragment and fragment.valid?
175
173
  end
176
174
 
177
175
  def get( uri, params )
178
- @semaphore.synchronize do
179
- fragment = @cache[cache_key(uri,params)]
180
- fragment.dup if fragment and fragment.respond_to?(:dup)
181
- end
176
+ key = cache_key(uri,params)
177
+ fragment = @semaphore.synchronize { @cache[key] }
178
+ fragment.dup if fragment and fragment.respond_to?(:dup)
182
179
  end
183
180
 
184
181
  def put( uri, params, max_age, body )
data/lib/esi/config.rb CHANGED
@@ -58,15 +58,15 @@ module ESI
58
58
  use_esi = false
59
59
  allowed_content_types = @config[:allowed_content_types]
60
60
 
61
- if allowed_content_types and headers["Content-Type"] and allowed_content_types.respond_to?(:detect)
61
+ if allowed_content_types and headers["content-type"] and allowed_content_types.respond_to?(:detect)
62
62
  use_esi = allowed_content_types.detect do |type|
63
- headers["Content-Type"].match( type )
63
+ headers["content-type"].match( type )
64
64
  end
65
65
  use_esi = true if use_esi
66
66
  end
67
67
 
68
68
  if @config[:enable_for_surrogate_only]
69
- use_esi = headers["Surrogate-Control"] and /ESI/.match(headers["Surrogate-Control"])
69
+ use_esi = headers["surrogate-control"] and /ESI/.match(headers["surrogate-control"])
70
70
  end
71
71
 
72
72
  use_esi
@@ -2,7 +2,7 @@ require 'esi/proxy'
2
2
 
3
3
  module ESI
4
4
 
5
- class Dispatcher < ESI::Proxy
5
+ class Dispatcher < Mongrel::HttpHandler
6
6
  attr_reader :config, :router
7
7
 
8
8
  Thread.abort_on_exception = false
@@ -10,15 +10,13 @@ module ESI
10
10
  def initialize( options )
11
11
  super()
12
12
  @config = ESI::Config.new( options )
13
- @router = nil
14
13
  if @config.start_invalidator?
15
14
  ESI::Invalidator.start( self )
16
15
  end
17
16
  end
18
17
 
19
18
  def process(request, response)
20
- @router = @config.router
21
- super
19
+ ESI::Proxy.new(@config).process(request,response)
22
20
  end
23
21
 
24
22
  end
data/lib/esi/parser.rb CHANGED
@@ -20,28 +20,38 @@ module ESI
20
20
  @response = ESI::Response.new( output )
21
21
 
22
22
  end_tag_handler do|tag_name|
23
- if self.esi_tag.name == tag_name.gsub(/esi:/,'')
24
- @response.close_active_buffer
25
- tag_buffer = @response.reserve_buffer
26
- tag = self.esi_tag.clone
27
- thread = Thread.new(tag,tag_buffer) do|tag,buffer|
28
- begin
29
- tag.close(tag_buffer)
30
- ensure
31
- tag_buffer.close_write
23
+ #puts "rb end #{tag_name.inspect}"
24
+ if self.esi_tag.name == tag_name.sub(/esi:/,'')
25
+
26
+ if tag_name.match(/try|include/) # run these in parallel
27
+ tag = self.esi_tag.clone
28
+ tag_buffer = @response.partial_buffer
29
+
30
+ #puts "start #{tag_name}"
31
+ thread = Thread.new(tag,tag_buffer) do|tag,buffer|
32
+ begin
33
+ tag.close(buffer)
34
+ ensure
35
+ buffer.close_write
36
+ #puts "finish #{tag_name}"
37
+ end
32
38
  end
39
+ @response.wait_thread( thread )
40
+ else
41
+ self.esi_tag.close( @response.active_buffer )
33
42
  end
43
+
34
44
  self.esi_tag = nil
35
45
 
36
- @response.wait_thread( thread )
37
46
  else
38
47
  self.esi_tag.close_child(self.output,tag_name)
39
48
  end
40
49
  end
41
50
  end
42
51
 
43
- def prepare( request_params, http_params, &block )
52
+ def prepare( request_params, http_params )
44
53
  start_tag_handler do|tag_name, attrs|
54
+ #puts "rb start #{tag_name.inspect}"
45
55
  tag = ESI::Tag::Base.create( @router,
46
56
  request_params,
47
57
  http_params,
@@ -52,13 +62,16 @@ module ESI
52
62
  tag.depth = self.depth if tag.respond_to?(:depth=)
53
63
  tag.max_depth = @max_depth if tag.respond_to?(:max_depth=)
54
64
 
55
- if self.esi_tag
65
+ if self.esi_tag and self.esi_tag.respond_to?(:add_child)
56
66
  self.esi_tag.add_child(tag)
57
67
  else
58
68
  self.esi_tag = tag
59
69
  end
60
70
  end
61
- self.output=block if block_given?
71
+ self.output_handler do|chars|
72
+ @response.active_buffer << chars
73
+ @response.send
74
+ end
62
75
  end
63
76
 
64
77
  def finish
data/lib/esi/processor.rb CHANGED
@@ -8,43 +8,29 @@ module ESI
8
8
 
9
9
  include ESI::Log
10
10
 
11
- def initialize( config, router )
11
+ def initialize( config, router, cache_buffer = nil )
12
12
  @config = config
13
13
  @router = router
14
14
  @chunk_count = 0
15
15
  @chunk_size = @config[:chunk_size] || 4096
16
+ @bytes_sent = 0
16
17
  @max_depth = @config[:max_depth] || 3
17
18
  @chunk_buffer = StringIO.new # when buffer reaches chunk_size write to the http_response socket
18
19
  @parser = ESI::Parser.new( @chunk_buffer, @router, @config.cache, @max_depth )
20
+ @cache_buffer = cache_buffer
19
21
  end
20
-
21
- def send_head( http_response, status )
22
-
23
- http_response.header["Transfer-Encoding"] = "chunked"
24
- # this is the important part, rather then send the whole document back we send in chunks
25
- # each fragment is roughly in it's own chunk, this does mean we require http 1.1, chunk size is still a limit
26
- header = Mongrel::Const::STATUS_FORMAT % [status, Mongrel::HTTP_STATUS_CODES[status]]
27
- header.gsub!(/Connection: close\r\n/,'')
28
- http_response.header.out.rewind
29
- header << http_response.header.out.read + Mongrel::Const::LINE_END
30
- header.gsub!(/Status:.*?\r\n/,'')
31
- http_response.write( header )
32
-
33
- #print header
34
-
35
- end
36
-
22
+
37
23
  def send_body( http_request, params, http_response, proxy_response )
38
24
 
39
25
  @http_response = http_response
40
26
 
41
27
  # prepare the parser given the raw request params and the preprocessed request params
42
- @parser.prepare( http_request.params, params ) do|chars|
43
- if @parser.response.active_buffer.closed_write?
44
- @parser.response.open_active_buffer
45
- @parser.response.send
46
- end
47
- @parser.response.active_buffer << chars
28
+ @parser.prepare( http_request.params, params )
29
+
30
+ # feed data to the parser
31
+ proxy_response.read_body do |data|
32
+ @parser.process data
33
+ @cache_buffer << data if @cache_buffer
48
34
  if @chunk_buffer.size > @chunk_size
49
35
  send_chunk
50
36
  @chunk_buffer = StringIO.new
@@ -52,19 +38,11 @@ module ESI
52
38
  end
53
39
  end
54
40
 
55
- #timer = Time.now
56
- # feed data to the parser
57
- proxy_response.read_body { |data| @parser.process data }
58
- #puts "processing time: #{Time.now - timer}"
59
-
60
- #timer = Time.now
61
- # finish the request
62
41
  @parser.finish
63
- #puts "finish time: #{Time.now - timer}"
64
42
 
65
43
  send_chunk
66
44
 
67
- @chunk_count
45
+ [@chunk_count,@bytes_sent]
68
46
  rescue => e
69
47
  STDERR.puts "\n#{e.message}: #{e.backtrace.join("\n")}\n"
70
48
  ensure
@@ -76,10 +54,10 @@ module ESI
76
54
  @chunk_buffer.rewind
77
55
  size = @chunk_buffer.size
78
56
  chunk_header = "#{"%x" % size}" + Mongrel::Const::LINE_END
79
- #puts chunk_header.inspect
57
+ #print chunk_header
80
58
  @http_response.write( chunk_header ) # write the chunk size
81
- #puts buffer.inspect
82
59
  @http_response.write( @chunk_buffer.read + Mongrel::Const::LINE_END ) # write the chunk
60
+ @bytes_sent += size
83
61
 
84
62
  @chunk_count += 1
85
63
  end
data/lib/esi/proxy.rb CHANGED
@@ -9,63 +9,131 @@ require 'esi/cache'
9
9
  require 'esi/config'
10
10
  require 'esi/router'
11
11
  require 'esi/processor'
12
+ require 'esi/version'
12
13
 
13
14
  module ESI
14
15
 
15
- class Proxy < Mongrel::HttpHandler
16
- attr_reader :config, :router
16
+ class Proxy
17
+ attr_reader :config, :router, :cache_buffer
17
18
  include ESI::Log
19
+ SERVER="mongrel-esi/#{ESI::VERSION::STRING}"
20
+
21
+ def initialize( config )
22
+ @config = config
23
+ @router = config.router
24
+ @cache_buffer = nil
25
+ end
18
26
 
19
27
  def process(request, response)
20
28
 
21
29
  start = Time.now
22
30
  status = 200
23
- url = @router.url_for(request.params["REQUEST_URI"])
24
31
 
25
- params = http_params(request.params)
32
+ http_params = http_params(request.params)
26
33
 
27
- log_debug "#{request.params["REQUEST_METHOD"]} => #{url}"
34
+ url = @router.url_for(request.params["REQUEST_URI"])
35
+ #log_debug "#{request.params["REQUEST_METHOD"]} => #{url}"
28
36
  chunk_count = 0
37
+ bytes_sent = 0
29
38
  uri = URI.parse(url)
30
39
 
31
40
  path_with_query = uri.query ? "#{uri.path}?#{uri.query}" : uri.path
41
+
42
+ if @config.cache.cached?( path_with_query, http_params )
43
+ cache_buffer = @config.cache.get( path_with_query, http_params ).body
44
+ bytes_sent = send_esi_buffered( status, response, request, http_params, cache_buffer )
45
+ else
46
+ proxy_request = (request.params["REQUEST_METHOD"] == "POST") ?
47
+ Net::HTTP::Post.new( path_with_query, http_params ) :
48
+ Net::HTTP::Get.new( path_with_query, http_params )
49
+
50
+ # open the conneciton up so we can start to stream the connection
51
+ Net::HTTP.start(uri.host, uri.port).request(proxy_request,request.body.read) do|proxy_response|
52
+ chunk_count,bytes_sent = send_response( request, response, http_params, proxy_response )
53
+ end # end request
54
+
55
+ if !@control.nil? and !@cache_buffer.nil? and @control['max-age'].to_i > 0 and @cache_buffer.size > 0
56
+ @cache_buffer.rewind
57
+ @config.cache.put(path_with_query, http_params, @control['max-age'].to_i, @cache_buffer.read )
58
+ end
32
59
 
33
- proxy_request = (request.params["REQUEST_METHOD"] == "POST") ?
34
- Net::HTTP::Post.new( path_with_query, params ) :
35
- Net::HTTP::Get.new( path_with_query, params )
36
-
37
- proxy_connection = Net::HTTP.start(uri.host, uri.port)
60
+ end
38
61
 
39
- # open the conneciton up so we can start to stream the connection
40
- proxy_connection.request(proxy_request,request.body.read) do|proxy_response|
62
+ rescue => e
63
+ STDERR.puts "\n#{e.message}: error at #{e.backtrace.first} msg at #{__FILE__}:#{__LINE__}\n"
64
+ ensure
65
+ log_request "\n#{url}, #{Time.now - start} seconds with status #{status} and #{chunk_count} chunks, #{bytes_sent} bytes\n"
66
+ end
41
67
 
42
- status = read_status( proxy_response )
68
+ protected
69
+ def send_response( http_request, http_response, http_params, proxy_response )
70
+ status = read_status( proxy_response )
71
+
72
+ headers = copy_headers( proxy_response )
73
+
74
+ if proxy_response.header["Surrogate-Control"]
75
+ @control = {}
76
+ proxy_response.header["Surrogate-Control"].split(',').each do |pair|
77
+ k,v = pair.strip.split('=')
78
+ @control[k] = v
79
+ end
80
+ if @control['max-age'].to_i > 0
81
+ @cache_buffer = StringIO.new
82
+ end
83
+ end
43
84
 
44
- copy_headers( response.header, proxy_response ) unless status >= 500
45
85
 
46
- if status >= 500 or !@config.enable_esi_processor?( proxy_response )
47
- response.start(status, true) do|head,out|
86
+ if status >= 500 or !@config.enable_esi_processor?( proxy_response )
87
+ headers.each do|k,v|
88
+ http_response.header[k] = v
89
+ end
90
+ proxy_direct( http_response, status, proxy_response )
91
+ else
92
+ if http_request.params["HTTP_VERSION"].match(/1.0/)
93
+ buffer = proxy_response.read_body
94
+ bytes=send_esi_buffered( status, http_response, http_request, http_params, buffer )
95
+ @cache_buffer << buffer if @cache_buffer
96
+ [0,bytes]
97
+ else
98
+ header = Mongrel::Const::STATUS_FORMAT % [status, Mongrel::HTTP_STATUS_CODES[status]]
99
+ headers.each {|k,v| header << "#{k}: #{v}\r\n" }
100
+ header << "Transfer-Encoding: chunked\r\n\r\n"
101
+ http_response.write( header )
102
+ proxy_filter_esi( http_request, http_response, http_params, proxy_response )
103
+ end
104
+ end
48
105
 
49
- # proxy the 500 response
50
- proxy_response.read_body do|fragment|
51
- out << fragment
52
- end
106
+ end
53
107
 
54
- end
55
- else
56
- processor = Processor.new( @config, @router )
57
- processor.send_head( response, status )
58
- chunk_count = processor.send_body( request, params, response, proxy_response )
108
+ def proxy_direct( http_response, status, proxy_response )
109
+ bytes_sent = 0
110
+ http_response.start(status, true) do|head,out|
111
+ proxy_response.read_body do|fragment|
112
+ out << fragment
113
+ bytes_sent += fragment.size
59
114
  end
60
- end # end request
115
+ end
116
+ return [0,bytes_sent]
117
+ end
61
118
 
62
- rescue => e
63
- STDERR.puts "\n#{e.message}: error at #{e.backtrace.first} msg at #{__FILE__}:#{__LINE__}\n"
64
- ensure
65
- log_request "\nCompleted => #{url}, #{Time.now - start} seconds with status #{status} and #{chunk_count} chunks\n"
119
+ def proxy_filter_esi( http_request, http_response, http_params, proxy_response )
120
+ processor = Processor.new( @config, @router, @cache_buffer )
121
+ processor.send_body( http_request, http_params, http_response, proxy_response )
122
+ end
123
+
124
+ def send_esi_buffered( status, response, request, http_params, buffer )
125
+ bytes = 0
126
+ response.start(status, true) do|head,out|
127
+ head["Server"] = SERVER
128
+ parser = ESI::Parser.new( out, @router, @config.cache, 3 )
129
+ parser.prepare( request.params, http_params )
130
+ parser.process buffer
131
+ parser.finish
132
+ bytes = out.size
133
+ end
134
+ bytes
66
135
  end
67
136
 
68
- protected
69
137
 
70
138
  def read_status(response)
71
139
  Net::HTTPResponse::CODE_TO_OBJ.select { |k,v| v == response.class }.first[0].to_i rescue 500
@@ -74,29 +142,30 @@ module ESI
74
142
  def http_params(params)
75
143
  updated_params = {}
76
144
  params.each do|k,v|
77
- k = k.split('_').collect { |t| t.capitalize }.join('-')
78
- if k[0,5] =='Http-'
79
- k[0,5] = ''
80
- updated_params[k] = v
145
+ if k.match(/HTTP/i)
146
+ k = k.split('_').collect { |t| t.capitalize }.join('-')
147
+ if k[0,5] =='Http-'
148
+ k[0,5] = ''
149
+ updated_params[k] = v
150
+ end
81
151
  end
82
152
  end
83
153
  updated_params
84
154
  end
85
155
 
86
- def copy_headers(head,response)
156
+ def copy_headers(response)
157
+ headers = {}
87
158
  response.to_hash.each do |k,v|
88
159
  # for Set-Cookie we need to split on ,
89
160
  # some edge cases with , since things like expires might be a date with , in them.
90
161
  k = k.split(/-/).map{|s| s.capitalize }.join('-')
91
- if k == "Set-Cookie"
92
- v.each do|cookie|
93
- head["Set-Cookie"] = cookie.strip # mongrel is case sensitive about handling duplicates
94
- end
95
- else
96
- head[k] = v unless k == "Content-Length" or k == "Surrogate-Control" or k == "Server"
97
- end
162
+
163
+ next if k.match(/Content-Length|Surrogate-Control|Server|Connection|Status/i)
164
+
165
+ headers[k] = v
98
166
  end
99
- head["Server"] = "MongrelESI 0.4"
167
+ headers["Server"] = SERVER
168
+ headers
100
169
  end
101
170
 
102
171
  end # Handler
data/lib/esi/response.rb CHANGED
@@ -1,81 +1,49 @@
1
+ # Copyright (c) 2008 Todd A. Fisher
2
+ # see LICENSE
1
3
  require 'fastthread'
2
4
  require 'thread'
3
5
  require 'stringio'
4
6
 
5
-
6
7
  module ESI
7
8
  class Response
8
9
  attr_reader :active_buffer
9
10
  attr_accessor :output
10
11
 
11
12
  def initialize( output )
12
- @lock = Mutex.new
13
13
  @count = 0
14
14
  @back_buffer = []
15
15
  @output = output
16
- @last_out = -1
16
+ @last_out = 0
17
17
  @threads = []
18
- @active_buffer = reserve_buffer
18
+ @active_buffer = reserve_buffer
19
19
  end
20
20
 
21
21
  def update_output(output)
22
- @lock.synchronize do
23
- @output = output
24
- end
25
- end
26
-
27
- def close_active_buffer
28
- @lock.synchronize do
29
- if !@active_buffer.closed_write?
30
- @active_buffer.close_write
31
- end
32
- end
33
- end
34
-
35
- def back_buffer_ready?
36
- @lock.synchronize do
37
- @back_buffer[@last_out+1..@count].size > 2
38
- end
22
+ @output = output
39
23
  end
40
24
 
41
- def open_active_buffer
42
- @lock.synchronize do
43
- if @active_buffer.closed_write?
44
- begin
45
- @lock.unlock
46
- @active_buffer = reserve_buffer
47
- ensure
48
- @lock.lock
49
- end
50
- end
51
- end
25
+ def partial_buffer
26
+ @active_buffer.close_write
27
+ temp = reserve_buffer
28
+ @active_buffer = reserve_buffer
29
+ temp
52
30
  end
53
31
 
54
32
  # return's new buffer
55
33
  def reserve_buffer
56
- @lock.synchronize do
57
- buffer = @back_buffer[@count] = StringIO.new
58
- @count += 1
59
- buffer
60
- end
34
+ buffer = @back_buffer[@count] = StringIO.new
35
+ @count += 1
36
+ buffer
61
37
  end
62
38
 
63
39
  def send
64
- @lock.synchronize do
65
- # roll up requests
66
- until @last_out == @count
67
- o = @back_buffer[@last_out+1]
68
- if o.nil? or !o.closed_write?
69
- #puts "#{self} buffering...#{@last_out} to #{@count} #{@back_buffer[@last_out+1..@count].map{|b| b ? b.closed_write? : 'nil' }.join(',')}"
70
- break
71
- end
72
- o.rewind
73
- buf = o.read
74
- #puts "#{Thread.current} #{self} sending: #{@last_out+1} #{buf.inspect}"
75
- @back_buffer[@last_out+1] = nil # clear it out, release memory
76
- @output << buf
77
- @last_out += 1
78
- end
40
+ check_buffers = @back_buffer[@last_out..@count]
41
+
42
+ for buffer in check_buffers do
43
+ break if buffer.nil? or !buffer.closed_write?
44
+ buffer.rewind
45
+ @output << buffer.read
46
+ @last_out += 1
79
47
  end
80
48
  end
81
49
 
@@ -85,17 +53,17 @@ module ESI
85
53
 
86
54
  def flush
87
55
  @threads.each{|t| t.join }
88
- @active_buffer.close_write
56
+ @active_buffer.close_write if !@active_buffer.closed_write?
89
57
  # roll up requests
90
58
  @last_out = 0 if @last_out == -1
91
59
  tail_buffer = (@back_buffer[@last_out..@back_buffer.size]||[])
92
- #puts "\nflushing:#{Thread.current} #{self} with #{tail_buffer.inspect}"
60
+ #puts "\nflushing: #{tail_buffer.inspect} from #{@back_buffer.inspect}"
93
61
  while !tail_buffer.empty?
94
62
  o = tail_buffer.shift
95
63
  unless o.nil?
96
64
  o.rewind
97
65
  buf = o.read
98
- #puts "#{Thread.current} #{self} flush : #{buf.inspect}"
66
+ #puts "flush : #{buf.inspect}"
99
67
  @output << buf
100
68
  end
101
69
  #puts "#{self} sending: #{@count-tail_buffer.size}"