mongrel_esi 0.5.0 → 0.5.1

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 (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}"