mongrel_esi 0.4.1 → 0.5.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.
- data/Rakefile +15 -8
- data/bin/mongrel_esi +0 -0
- data/ext/esi/common.rl +32 -27
- data/ext/esi/esi_parser.c +11 -4
- data/ext/esi/parser.c +4536 -901
- data/ext/esi/parser.h +7 -0
- data/ext/esi/parser.rl +171 -53
- data/ext/esi/run-test.rb +0 -0
- data/ext/esi/test/common.rl +32 -27
- data/ext/esi/test/parser.c +322 -1342
- data/ext/esi/test/parser.h +7 -0
- data/ext/esi/test/parser.rl +171 -53
- data/ext/esi/test/test.c +13 -4
- data/ext/esi/test1.rb +35 -3
- data/lib/esi/cache.rb +2 -1
- data/lib/esi/config.rb +37 -0
- data/lib/esi/dispatcher.rb +3 -5
- data/lib/esi/invalidator.rb +3 -0
- data/lib/esi/logger.rb +0 -7
- data/lib/esi/parser.rb +70 -0
- data/lib/esi/processor.rb +88 -0
- data/lib/esi/proxy.rb +104 -0
- data/lib/esi/response.rb +106 -0
- data/lib/esi/router.rb +3 -0
- data/lib/esi/tag/attempt.rb +3 -0
- data/lib/esi/tag/base.rb +3 -1
- data/lib/esi/tag/except.rb +2 -0
- data/lib/esi/tag/include.rb +131 -132
- data/lib/esi/tag/invalidate.rb +2 -0
- data/lib/esi/tag/try.rb +3 -0
- data/test/integration/basic_test.rb +0 -1
- data/test/integration/docs/esi_max_age_varies.html +10 -0
- data/test/integration/handler_test.rb +31 -5
- data/test/integration/help.rb +13 -1
- data/test/load_test.rb +133 -0
- data/test/unit/include_request_test.rb +1 -1
- data/test/unit/parser_test.rb +41 -5
- data/test/unit/response_test.rb +184 -0
- metadata +50 -224
- data/doc/rdoc/classes/ESI/Cache.html +0 -178
- data/doc/rdoc/classes/ESI/Cache.src/M000060.html +0 -17
- data/doc/rdoc/classes/ESI/Cache.src/M000061.html +0 -20
- data/doc/rdoc/classes/ESI/Config/CacheConfig.html +0 -212
- data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000055.html +0 -19
- data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000056.html +0 -19
- data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000057.html +0 -18
- data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000058.html +0 -18
- data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000059.html +0 -18
- data/doc/rdoc/classes/ESI/Config/ConfigRouter.html +0 -187
- data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000052.html +0 -19
- data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000053.html +0 -21
- data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000054.html +0 -21
- data/doc/rdoc/classes/ESI/Config.html +0 -291
- data/doc/rdoc/classes/ESI/Config.src/M000043.html +0 -18
- data/doc/rdoc/classes/ESI/Config.src/M000044.html +0 -18
- data/doc/rdoc/classes/ESI/Config.src/M000045.html +0 -35
- data/doc/rdoc/classes/ESI/Config.src/M000046.html +0 -38
- data/doc/rdoc/classes/ESI/Config.src/M000047.html +0 -23
- data/doc/rdoc/classes/ESI/Config.src/M000048.html +0 -18
- data/doc/rdoc/classes/ESI/Config.src/M000049.html +0 -20
- data/doc/rdoc/classes/ESI/Config.src/M000050.html +0 -18
- data/doc/rdoc/classes/ESI/Config.src/M000051.html +0 -24
- data/doc/rdoc/classes/ESI/Dispatcher.html +0 -172
- data/doc/rdoc/classes/ESI/Dispatcher.src/M000062.html +0 -23
- data/doc/rdoc/classes/ESI/Dispatcher.src/M000063.html +0 -20
- data/doc/rdoc/classes/ESI/Fragment.html +0 -218
- data/doc/rdoc/classes/ESI/Fragment.src/M000076.html +0 -21
- data/doc/rdoc/classes/ESI/Fragment.src/M000077.html +0 -18
- data/doc/rdoc/classes/ESI/Fragment.src/M000078.html +0 -18
- data/doc/rdoc/classes/ESI/Handler.html +0 -236
- data/doc/rdoc/classes/ESI/Handler.src/M000079.html +0 -19
- data/doc/rdoc/classes/ESI/Handler.src/M000080.html +0 -161
- data/doc/rdoc/classes/ESI/Handler.src/M000081.html +0 -24
- data/doc/rdoc/classes/ESI/Handler.src/M000082.html +0 -18
- data/doc/rdoc/classes/ESI/Handler.src/M000083.html +0 -26
- data/doc/rdoc/classes/ESI/Handler.src/M000084.html +0 -30
- data/doc/rdoc/classes/ESI/Invalidator.html +0 -131
- data/doc/rdoc/classes/ESI/Invalidator.src/M000004.html +0 -41
- data/doc/rdoc/classes/ESI/Log.html +0 -251
- data/doc/rdoc/classes/ESI/Log.src/M000005.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000006.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000007.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000008.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000009.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000010.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000011.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000012.html +0 -18
- data/doc/rdoc/classes/ESI/Log.src/M000013.html +0 -18
- data/doc/rdoc/classes/ESI/MemcachedCache.html +0 -314
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000034.html +0 -24
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000035.html +0 -22
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000036.html +0 -19
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000037.html +0 -23
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000038.html +0 -18
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000039.html +0 -19
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000040.html +0 -18
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000041.html +0 -18
- data/doc/rdoc/classes/ESI/MemcachedCache.src/M000042.html +0 -17
- data/doc/rdoc/classes/ESI/Router.html +0 -229
- data/doc/rdoc/classes/ESI/Router.src/M000073.html +0 -36
- data/doc/rdoc/classes/ESI/Router.src/M000074.html +0 -25
- data/doc/rdoc/classes/ESI/Router.src/M000075.html +0 -24
- data/doc/rdoc/classes/ESI/RubyCache.html +0 -278
- data/doc/rdoc/classes/ESI/RubyCache.src/M000064.html +0 -20
- data/doc/rdoc/classes/ESI/RubyCache.src/M000065.html +0 -22
- data/doc/rdoc/classes/ESI/RubyCache.src/M000066.html +0 -21
- data/doc/rdoc/classes/ESI/RubyCache.src/M000067.html +0 -22
- data/doc/rdoc/classes/ESI/RubyCache.src/M000068.html +0 -18
- data/doc/rdoc/classes/ESI/RubyCache.src/M000069.html +0 -22
- data/doc/rdoc/classes/ESI/RubyCache.src/M000070.html +0 -18
- data/doc/rdoc/classes/ESI/RubyCache.src/M000071.html +0 -18
- data/doc/rdoc/classes/ESI/RubyCache.src/M000072.html +0 -18
- data/doc/rdoc/classes/ESI/Tag/Attempt.html +0 -113
- data/doc/rdoc/classes/ESI/Tag/Base.html +0 -267
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000028.html +0 -26
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000029.html +0 -23
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000030.html +0 -22
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000031.html +0 -18
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000032.html +0 -22
- data/doc/rdoc/classes/ESI/Tag/Base.src/M000033.html +0 -23
- data/doc/rdoc/classes/ESI/Tag/Except.html +0 -184
- data/doc/rdoc/classes/ESI/Tag/Except.src/M000020.html +0 -21
- data/doc/rdoc/classes/ESI/Tag/Except.src/M000021.html +0 -20
- data/doc/rdoc/classes/ESI/Tag/Except.src/M000022.html +0 -18
- data/doc/rdoc/classes/ESI/Tag/Include.html +0 -189
- data/doc/rdoc/classes/ESI/Tag/Include.src/M000017.html +0 -20
- data/doc/rdoc/classes/ESI/Tag/Include.src/M000018.html +0 -18
- data/doc/rdoc/classes/ESI/Tag/Include.src/M000019.html +0 -125
- data/doc/rdoc/classes/ESI/Tag/IncludeRequest/Error.html +0 -155
- data/doc/rdoc/classes/ESI/Tag/IncludeRequest/Error.src/M000016.html +0 -19
- data/doc/rdoc/classes/ESI/Tag/IncludeRequest.html +0 -199
- data/doc/rdoc/classes/ESI/Tag/IncludeRequest.src/M000014.html +0 -18
- data/doc/rdoc/classes/ESI/Tag/IncludeRequest.src/M000015.html +0 -42
- data/doc/rdoc/classes/ESI/Tag/Invalidate.html +0 -171
- data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000025.html +0 -19
- data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000026.html +0 -51
- data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000027.html +0 -19
- data/doc/rdoc/classes/ESI/Tag/Try.html +0 -161
- data/doc/rdoc/classes/ESI/Tag/Try.src/M000023.html +0 -40
- data/doc/rdoc/classes/ESI/Tag/Try.src/M000024.html +0 -18
- data/doc/rdoc/classes/ESI/Tag.html +0 -137
- data/doc/rdoc/classes/ESI.html +0 -169
- data/doc/rdoc/classes/MultiDirHandler.html +0 -198
- data/doc/rdoc/classes/MultiDirHandler.src/M000001.html +0 -20
- data/doc/rdoc/classes/MultiDirHandler.src/M000002.html +0 -28
- data/doc/rdoc/classes/MultiDirHandler.src/M000003.html +0 -22
- data/doc/rdoc/classes/Net/An/HTTP.html +0 -137
- data/doc/rdoc/classes/Net/An/HTTP.src/M000087.html +0 -17
- data/doc/rdoc/classes/Net/An/IORequest.html +0 -139
- data/doc/rdoc/classes/Net/An/IORequest.src/M000088.html +0 -17
- data/doc/rdoc/classes/Net/An/IOResponse.html +0 -139
- data/doc/rdoc/classes/Net/An/IOResponse.src/M000085.html +0 -17
- data/doc/rdoc/classes/Net/An/IOSocket.html +0 -137
- data/doc/rdoc/classes/Net/An/IOSocket.src/M000086.html +0 -17
- data/doc/rdoc/classes/Net/An.html +0 -114
- data/doc/rdoc/classes/Net.html +0 -119
- data/doc/rdoc/created.rid +0 -1
- data/doc/rdoc/files/COPYING.html +0 -168
- data/doc/rdoc/files/LICENSE.html +0 -605
- data/doc/rdoc/files/README.html +0 -361
- data/doc/rdoc/files/lib/esi/cache_rb.html +0 -113
- data/doc/rdoc/files/lib/esi/config_rb.html +0 -108
- data/doc/rdoc/files/lib/esi/dispatcher_rb.html +0 -109
- data/doc/rdoc/files/lib/esi/handler_rb.html +0 -121
- data/doc/rdoc/files/lib/esi/invalidator_rb.html +0 -117
- data/doc/rdoc/files/lib/esi/logger_rb.html +0 -108
- data/doc/rdoc/files/lib/esi/router_rb.html +0 -101
- data/doc/rdoc/files/lib/esi/tag/attempt_rb.html +0 -101
- data/doc/rdoc/files/lib/esi/tag/base_rb.html +0 -108
- data/doc/rdoc/files/lib/esi/tag/except_rb.html +0 -101
- data/doc/rdoc/files/lib/esi/tag/include_rb.html +0 -109
- data/doc/rdoc/files/lib/esi/tag/invalidate_rb.html +0 -109
- data/doc/rdoc/files/lib/esi/tag/try_rb.html +0 -108
- data/doc/rdoc/files/lib/multi_dirhandler_rb.html +0 -109
- data/doc/rdoc/files/lib/net/ahttp_rb.html +0 -109
- data/doc/rdoc/fr_class_index.html +0 -55
- data/doc/rdoc/fr_file_index.html +0 -44
- data/doc/rdoc/fr_method_index.html +0 -114
- data/doc/rdoc/index.html +0 -24
- data/doc/rdoc/rdoc-style.css +0 -208
- data/ext/esi/parser.rb +0 -49
- data/ext/esi/ruby_esi.rl +0 -135
- data/lib/esi/handler.rb +0 -221
- data/lib/net/ahttp.rb +0 -36
data/ext/esi/test/test.c
CHANGED
|
@@ -54,7 +54,7 @@ static int verify_string( const char *str, const char *str_value, int line, cons
|
|
|
54
54
|
int str_value_length = strlen( str_value );
|
|
55
55
|
|
|
56
56
|
if( str_len != str_value_length || strcmp( str, str_value ) ){
|
|
57
|
-
printf( "Strings are not equal\n\"%s\":%d\n!=\n\"%s\":%d\nat
|
|
57
|
+
printf( "Strings are not equal\n\t\"%s\":%d\n!=\t\n\"%s\":%d\nat\n%s:%d\n", str, str_len, str_value, str_value_length, test_name, line );
|
|
58
58
|
return 1;
|
|
59
59
|
}
|
|
60
60
|
return 0;
|
|
@@ -139,7 +139,6 @@ static void start_tag_handler( const void *data,
|
|
|
139
139
|
ESIAttribute *attributes,
|
|
140
140
|
void *user_data )
|
|
141
141
|
{
|
|
142
|
-
ESIAttribute *attr = attributes;
|
|
143
142
|
++start_tag_count;
|
|
144
143
|
detected_start_tags = add_detected_tag( detected_start_tags, tag_info_new( name_start, name_length, attributes ) );
|
|
145
144
|
}
|
|
@@ -244,7 +243,7 @@ static void test_simple_parser_input( ESIParser *parser )
|
|
|
244
243
|
{
|
|
245
244
|
TEST_INIT
|
|
246
245
|
|
|
247
|
-
feed_data( parser, "<p>some input</p><esi:include/>some more input\nsome input<esi:include timeout='10' src='hello'/>some more input" );
|
|
246
|
+
feed_data( parser, "<p>some input</p><esi:include />some more input\nsome input<esi:include timeout='10' src='hello'/>some more input" );
|
|
248
247
|
|
|
249
248
|
TEST_PREPARE_ASSERTIONS
|
|
250
249
|
|
|
@@ -304,7 +303,17 @@ static void test_sample_input( ESIParser *parser )
|
|
|
304
303
|
ASSERT_MATCH(" <div>some content</div>", output);
|
|
305
304
|
ASSERT_MATCH("<em>Support for em tags since they have an initial start sequence similar to and <esi: start/end sequence</em>", output );
|
|
306
305
|
ASSERT_NO_MATCH("<esi:", output);
|
|
306
|
+
/*
|
|
307
|
+
TagInfo *ptr = start_tags;
|
|
308
|
+
|
|
309
|
+
while( ptr ){
|
|
310
|
+
tag_info_show( ptr );
|
|
311
|
+
ptr = ptr->next;
|
|
312
|
+
}
|
|
307
313
|
|
|
314
|
+
printf( "start_tag_count: %d\n", start_tag_count );
|
|
315
|
+
printf( "end_tag_count: %d\n", end_tag_count );
|
|
316
|
+
*/
|
|
308
317
|
ASSERT_TRUE( start_tag_count == 13 );
|
|
309
318
|
ASSERT_TRUE( end_tag_count == 13 );
|
|
310
319
|
|
|
@@ -352,7 +361,7 @@ static void test_large_file( ESIParser *parser )
|
|
|
352
361
|
|
|
353
362
|
TEST_FINISH
|
|
354
363
|
}
|
|
355
|
-
|
|
364
|
+
|
|
356
365
|
int main( int argc, char **argv )
|
|
357
366
|
{
|
|
358
367
|
ESIParser *parser = esi_parser_new();
|
data/ext/esi/test1.rb
CHANGED
|
@@ -4,13 +4,16 @@ output = ""
|
|
|
4
4
|
|
|
5
5
|
p = ESI::CParser.new
|
|
6
6
|
|
|
7
|
+
start_tags = []
|
|
8
|
+
end_tags = []
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
p.start_tag_handler do|tag_name, attrs|
|
|
9
|
-
|
|
12
|
+
start_tags << {:name => tag_name, :attributes => attrs }
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
p.end_tag_handler do|tag_name|
|
|
13
|
-
|
|
16
|
+
end_tags << tag_name
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
p.output_handler do|data|
|
|
@@ -28,7 +31,36 @@ some inputsome more inputsome inputsome more input
|
|
|
28
31
|
some inputsome more input<p>some input</p>some more input
|
|
29
32
|
some inputsome more input</body></html>)
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
expected_start_tags = [
|
|
35
|
+
{:name => 'esi:include', :attributes => {"src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
36
|
+
{:name => 'esi:include', :attributes => {"src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
37
|
+
{:name => 'esi:include', :attributes => {"src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
38
|
+
{:name => 'esi:inline', :attributes => {"src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
39
|
+
{:name => 'esi:comment', :attributes => {"text"=>"hello", "src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
40
|
+
{:name => 'esi:include', :attributes => {"text"=>"hello", "src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} },
|
|
41
|
+
{:name => 'esi:include', :attributes => {"text"=>"hello", "src"=>"hello", "max-age"=>"600+600", "timeout"=>"1"} }
|
|
42
|
+
]
|
|
43
|
+
expected_end_tags =[ 'esi:include', 'esi:include', 'esi:include', 'esi:inline', 'esi:comment', 'esi:include', 'esi:include']
|
|
44
|
+
|
|
45
|
+
if( start_tags.size != expected_start_tags.size and end_tags.size != expected_end_tags.size )
|
|
46
|
+
puts "Failed expected start tags: #{expected_start_tags.size}, expected end tags: #{expected_end_tags.size}"
|
|
47
|
+
puts "Actual: start tags: #{start_tags.size}, end tags: #{end_tags.size}"
|
|
48
|
+
exit(1)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if expected_start_tags != start_tags
|
|
52
|
+
puts "Failed expected start tags: #{expected_start_tags.inspect}"
|
|
53
|
+
puts "Actual start tags: #{start_tags.inspect}"
|
|
54
|
+
exit(1)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if expected_end_tags != end_tags
|
|
58
|
+
puts "Failed expected end tags: #{expected_end_tags.inspect}"
|
|
59
|
+
puts "Actual end tags: #{end_tags.inspect}"
|
|
60
|
+
exit(1)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if( expected != output )
|
|
32
64
|
puts "Failed output was different from the expected"
|
|
33
65
|
puts "Expected: #{expected}"
|
|
34
66
|
puts "\n"
|
data/lib/esi/cache.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# Copyright (c) 2008 Todd A. Fisher
|
|
2
|
+
# see LICENSE
|
|
1
3
|
require 'digest/sha1'
|
|
2
4
|
require 'thread'
|
|
3
5
|
require 'ostruct'
|
|
@@ -12,7 +14,6 @@ module ESI
|
|
|
12
14
|
|
|
13
15
|
def initialize(uri,max_age,body)
|
|
14
16
|
@uri = uri
|
|
15
|
-
max_age.gsub!(/\+.*$/,'') if max_age.class == String
|
|
16
17
|
@max_age = Time.now.to_i + max_age.to_i
|
|
17
18
|
@body = body
|
|
18
19
|
end
|
data/lib/esi/config.rb
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
|
+
# Copyright (c) 2008 Todd A. Fisher
|
|
2
|
+
# see LICENSE
|
|
1
3
|
require 'ostruct'
|
|
2
4
|
|
|
3
5
|
module ESI
|
|
6
|
+
# This file provides configuration options to mongrel-esi
|
|
7
|
+
# Mongrel ESI is a proxy caching server with limited load balancing capablities
|
|
8
|
+
#
|
|
9
|
+
# ESI::Config.define(listeners) do|config|
|
|
10
|
+
#
|
|
11
|
+
# # define the caching rules globally for all routes, defaults to ruby
|
|
12
|
+
# config.cache do|c|
|
|
13
|
+
# c.memcached do|mc|
|
|
14
|
+
# mc.servers = ['localhost:11211'] # memcahed servers
|
|
15
|
+
# mc.namespace = 'mesi' # namespace for cache storage
|
|
16
|
+
# end
|
|
17
|
+
# c.ttl = 600 # default fragment time to live, when <esi:include does not include the max-age attribute
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# # define rules for when to enable esi processing globally for all routes
|
|
21
|
+
# # using content type it is more flexible, but sometimes you will want to be
|
|
22
|
+
# # explicit about when to enable esi processing. For those cases, enable_for_surrogate_only will
|
|
23
|
+
# # require the presense of the Surrogate-Control header to contain the content="ESI/1.0" line.
|
|
24
|
+
# # see [http://www.w3.org/TR/edge-arch Edge Arch] for details.
|
|
25
|
+
# config.esi do|c|
|
|
26
|
+
# c.allowed_content_types = ['text/plain', 'text/html']
|
|
27
|
+
# #c.enable_for_surrogate_only = true # default is false
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# # define request path routing rules, these rules match against request path to select a specific server
|
|
31
|
+
# config.routes do|s|
|
|
32
|
+
# #s.match( /content/ ) do|r|
|
|
33
|
+
# # r.servers = ['127.0.0.1:4000']
|
|
34
|
+
# #end
|
|
35
|
+
# s.default do|r|
|
|
36
|
+
# r.servers = ['127.0.0.1:3000']
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# end
|
|
4
41
|
class Config
|
|
5
42
|
|
|
6
43
|
attr_reader :config
|
data/lib/esi/dispatcher.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
require 'esi/
|
|
2
|
-
require 'mongrel'
|
|
1
|
+
require 'esi/proxy'
|
|
3
2
|
|
|
4
3
|
module ESI
|
|
5
4
|
|
|
6
|
-
class Dispatcher <
|
|
5
|
+
class Dispatcher < ESI::Proxy
|
|
7
6
|
attr_reader :config, :router
|
|
8
7
|
|
|
9
8
|
Thread.abort_on_exception = false
|
|
@@ -19,8 +18,7 @@ module ESI
|
|
|
19
18
|
|
|
20
19
|
def process(request, response)
|
|
21
20
|
@router = @config.router
|
|
22
|
-
|
|
23
|
-
handler.process(request, response)
|
|
21
|
+
super
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
end
|
data/lib/esi/invalidator.rb
CHANGED
data/lib/esi/logger.rb
CHANGED
data/lib/esi/parser.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright (c) 2008 Todd A. Fisher
|
|
2
|
+
# see LICENSE
|
|
3
|
+
require 'esi/esi'
|
|
4
|
+
require 'esi/tag/base'
|
|
5
|
+
require 'esi/tag/include'
|
|
6
|
+
require 'esi/tag/invalidate'
|
|
7
|
+
require 'esi/tag/attempt'
|
|
8
|
+
require 'esi/tag/except'
|
|
9
|
+
require 'esi/tag/try'
|
|
10
|
+
|
|
11
|
+
module ESI
|
|
12
|
+
class Parser < CParser
|
|
13
|
+
attr_reader :response
|
|
14
|
+
|
|
15
|
+
def initialize( output, router, cache, max_depth )
|
|
16
|
+
super()
|
|
17
|
+
@router = router
|
|
18
|
+
@cache = cache
|
|
19
|
+
@max_depth = max_depth
|
|
20
|
+
@response = ESI::Response.new( output )
|
|
21
|
+
|
|
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
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
self.esi_tag = nil
|
|
35
|
+
|
|
36
|
+
@response.wait_thread( thread )
|
|
37
|
+
else
|
|
38
|
+
self.esi_tag.close_child(self.output,tag_name)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def prepare( request_params, http_params, &block )
|
|
44
|
+
start_tag_handler do|tag_name, attrs|
|
|
45
|
+
tag = ESI::Tag::Base.create( @router,
|
|
46
|
+
request_params,
|
|
47
|
+
http_params,
|
|
48
|
+
tag_name.gsub(/esi:/,''),
|
|
49
|
+
attrs,
|
|
50
|
+
@cache )
|
|
51
|
+
# set the tag depth
|
|
52
|
+
tag.depth = self.depth if tag.respond_to?(:depth=)
|
|
53
|
+
tag.max_depth = @max_depth if tag.respond_to?(:max_depth=)
|
|
54
|
+
|
|
55
|
+
if self.esi_tag
|
|
56
|
+
self.esi_tag.add_child(tag)
|
|
57
|
+
else
|
|
58
|
+
self.esi_tag = tag
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
self.output=block if block_given?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def finish
|
|
65
|
+
super
|
|
66
|
+
@response.flush
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright (c) 2008 Todd A. Fisher
|
|
2
|
+
require 'esi/parser'
|
|
3
|
+
require 'esi/response'
|
|
4
|
+
|
|
5
|
+
module ESI
|
|
6
|
+
class Processor
|
|
7
|
+
attr_reader :config, :router
|
|
8
|
+
|
|
9
|
+
include ESI::Log
|
|
10
|
+
|
|
11
|
+
def initialize( config, router )
|
|
12
|
+
@config = config
|
|
13
|
+
@router = router
|
|
14
|
+
@chunk_count = 0
|
|
15
|
+
@chunk_size = @config[:chunk_size] || 4096
|
|
16
|
+
@max_depth = @config[:max_depth] || 3
|
|
17
|
+
@chunk_buffer = StringIO.new # when buffer reaches chunk_size write to the http_response socket
|
|
18
|
+
@parser = ESI::Parser.new( @chunk_buffer, @router, @config.cache, @max_depth )
|
|
19
|
+
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
|
+
|
|
37
|
+
def send_body( http_request, params, http_response, proxy_response )
|
|
38
|
+
|
|
39
|
+
@http_response = http_response
|
|
40
|
+
|
|
41
|
+
# 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
|
|
48
|
+
if @chunk_buffer.size > @chunk_size
|
|
49
|
+
send_chunk
|
|
50
|
+
@chunk_buffer = StringIO.new
|
|
51
|
+
@parser.response.update_output( @chunk_buffer )
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
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
|
+
@parser.finish
|
|
63
|
+
#puts "finish time: #{Time.now - timer}"
|
|
64
|
+
|
|
65
|
+
send_chunk
|
|
66
|
+
|
|
67
|
+
@chunk_count
|
|
68
|
+
rescue => e
|
|
69
|
+
STDERR.puts "\n#{e.message}: #{e.backtrace.join("\n")}\n"
|
|
70
|
+
ensure
|
|
71
|
+
http_response.write( "0\r\n\r\n" )
|
|
72
|
+
http_response.done = true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def send_chunk
|
|
76
|
+
@chunk_buffer.rewind
|
|
77
|
+
size = @chunk_buffer.size
|
|
78
|
+
chunk_header = "#{"%x" % size}" + Mongrel::Const::LINE_END
|
|
79
|
+
#puts chunk_header.inspect
|
|
80
|
+
@http_response.write( chunk_header ) # write the chunk size
|
|
81
|
+
#puts buffer.inspect
|
|
82
|
+
@http_response.write( @chunk_buffer.read + Mongrel::Const::LINE_END ) # write the chunk
|
|
83
|
+
|
|
84
|
+
@chunk_count += 1
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/esi/proxy.rb
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Copyright (c) 2008 Todd A. Fisher
|
|
2
|
+
# see LICENSE
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'timeout'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
require 'mongrel'
|
|
7
|
+
require 'esi/logger'
|
|
8
|
+
require 'esi/cache'
|
|
9
|
+
require 'esi/config'
|
|
10
|
+
require 'esi/router'
|
|
11
|
+
require 'esi/processor'
|
|
12
|
+
|
|
13
|
+
module ESI
|
|
14
|
+
|
|
15
|
+
class Proxy < Mongrel::HttpHandler
|
|
16
|
+
attr_reader :config, :router
|
|
17
|
+
include ESI::Log
|
|
18
|
+
|
|
19
|
+
def process(request, response)
|
|
20
|
+
|
|
21
|
+
start = Time.now
|
|
22
|
+
status = 200
|
|
23
|
+
url = @router.url_for(request.params["REQUEST_URI"])
|
|
24
|
+
|
|
25
|
+
params = http_params(request.params)
|
|
26
|
+
|
|
27
|
+
log_debug "#{request.params["REQUEST_METHOD"]} => #{url}"
|
|
28
|
+
chunk_count = 0
|
|
29
|
+
uri = URI.parse(url)
|
|
30
|
+
|
|
31
|
+
path_with_query = uri.query ? "#{uri.path}?#{uri.query}" : uri.path
|
|
32
|
+
|
|
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)
|
|
38
|
+
|
|
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|
|
|
41
|
+
|
|
42
|
+
status = read_status( proxy_response )
|
|
43
|
+
|
|
44
|
+
copy_headers( response.header, proxy_response ) unless status >= 500
|
|
45
|
+
|
|
46
|
+
if status >= 500 or !@config.enable_esi_processor?( proxy_response )
|
|
47
|
+
response.start(status, true) do|head,out|
|
|
48
|
+
|
|
49
|
+
# proxy the 500 response
|
|
50
|
+
proxy_response.read_body do|fragment|
|
|
51
|
+
out << fragment
|
|
52
|
+
end
|
|
53
|
+
|
|
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 )
|
|
59
|
+
end
|
|
60
|
+
end # end request
|
|
61
|
+
|
|
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"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
protected
|
|
69
|
+
|
|
70
|
+
def read_status(response)
|
|
71
|
+
Net::HTTPResponse::CODE_TO_OBJ.select { |k,v| v == response.class }.first[0].to_i rescue 500
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def http_params(params)
|
|
75
|
+
updated_params = {}
|
|
76
|
+
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
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
updated_params
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def copy_headers(head,response)
|
|
87
|
+
response.to_hash.each do |k,v|
|
|
88
|
+
# for Set-Cookie we need to split on ,
|
|
89
|
+
# some edge cases with , since things like expires might be a date with , in them.
|
|
90
|
+
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
|
|
98
|
+
end
|
|
99
|
+
head["Server"] = "MongrelESI 0.4"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
end # Handler
|
|
103
|
+
|
|
104
|
+
end # ESI
|