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,373 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <sys/types.h>
5
+ #include <sys/stat.h>
6
+ #include <regex.h>
7
+ #include <fcntl.h>
8
+ #include <unistd.h> /* for write */
9
+ #define DEBUG
10
+ #include "parser.h"
11
+
12
+ #ifdef DEBUG
13
+ #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
14
+ #else
15
+ #define TRACE()
16
+ #endif
17
+
18
+
19
+ /*
20
+ * TagInfo is used for collecting tags and asserting we have generated the correct tag names
21
+ */
22
+ typedef struct _TagInfo {
23
+ char *name;
24
+ ESIAttribute *attributes;
25
+ struct _TagInfo *next;
26
+ }TagInfo;
27
+
28
+ static
29
+ TagInfo* tag_info_new( const char *name, size_t len, ESIAttribute *attributes )
30
+ {
31
+ TagInfo *ti = (TagInfo*)malloc(sizeof(TagInfo));
32
+ ti->name = esi_strndup( name, len );
33
+ ti->attributes = esi_attribute_copy( attributes );
34
+ ti->next = NULL;
35
+ return ti;
36
+ }
37
+
38
+ static
39
+ void tag_info_free( TagInfo *ti )
40
+ {
41
+ TagInfo *ptr = NULL;
42
+ while( ti ){
43
+ free( ti->name );
44
+ if( ti->attributes ) esi_attribute_free( ti->attributes );
45
+ ptr = ti->next; /* save the next pointer */
46
+ free( ti );
47
+ ti = ptr;
48
+ }
49
+ }
50
+
51
+ static int verify_string( const char *str, const char *str_value, int line, const char *test_name )
52
+ {
53
+ int str_len = strlen( str );
54
+ int str_value_length = strlen( str_value );
55
+
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 %s:%d\n", str, str_len, str_value, str_value_length, test_name, line );
58
+ return 1;
59
+ }
60
+ return 0;
61
+ }
62
+
63
+ static int verify_match_string( const char *expr, const char *str_value, int line, const char *test_name )
64
+ {
65
+ int status;
66
+ regex_t reg_expr;
67
+ regcomp( &reg_expr, expr, REG_EXTENDED|REG_NOSUB );
68
+ status = regexec( &reg_expr, str_value, (size_t) 0, NULL, 0 );
69
+ regfree( &reg_expr );
70
+ if( status != 0 ){
71
+ printf( "No matching %s expression found in '%s' at %s:%d ", expr, str_value, test_name, line );
72
+ return 1;
73
+ }
74
+ return 0;
75
+ }
76
+
77
+ static int verify_no_match_string( const char *expr, const char *str_value, int line, const char *test_name )
78
+ {
79
+ int status;
80
+ regex_t reg_expr;
81
+ regcomp( &reg_expr, expr, REG_EXTENDED|REG_NOSUB );
82
+ status = regexec( &reg_expr, str_value, (size_t) 0, NULL, 0 );
83
+ regfree( &reg_expr );
84
+ if( status == 0 ){
85
+ printf( "Found matching %s expression found in '%s' at %s:%d ", expr, str_value, test_name, line );
86
+ return 1;
87
+ }
88
+ return 0;
89
+ }
90
+
91
+ static int verify_true( int expr, int line, const char *test_name )
92
+ {
93
+ if( !expr ){
94
+ printf( "Expression is not true at %s:%d\n", test_name, line );
95
+ return 1;
96
+ }
97
+ return 0;
98
+ }
99
+
100
+ static int start_tag_count = 0;
101
+ static int end_tag_count = 0;
102
+ static TagInfo *detected_start_tags = NULL; /* store parsed start tags from each test */
103
+ static TagInfo *detected_end_tags = NULL; /* store parsed end tags from each test */
104
+
105
+ static
106
+ TagInfo *add_detected_tag( TagInfo *tags, TagInfo *ti )
107
+ {
108
+ if( tags ){
109
+ TagInfo *next = tags;
110
+ TagInfo *prev = NULL;
111
+ while( next ){
112
+ prev = next;
113
+ next = next->next;
114
+ }
115
+ prev->next = ti;
116
+ }
117
+ else{
118
+ tags = ti;
119
+ }
120
+ return tags;
121
+ }
122
+
123
+ static
124
+ void free_detected_tags()
125
+ {
126
+ if( detected_start_tags ){
127
+ tag_info_free( detected_start_tags );
128
+ }
129
+ if( detected_end_tags ){
130
+ tag_info_free( detected_end_tags );
131
+ }
132
+ detected_end_tags = NULL;
133
+ detected_start_tags = NULL;
134
+ }
135
+
136
+ static void start_tag_handler( const void *data,
137
+ const char *name_start,
138
+ size_t name_length,
139
+ ESIAttribute *attributes,
140
+ void *user_data )
141
+ {
142
+ ESIAttribute *attr = attributes;
143
+ ++start_tag_count;
144
+ detected_start_tags = add_detected_tag( detected_start_tags, tag_info_new( name_start, name_length, attributes ) );
145
+ }
146
+ static void end_tag_handler( const void *data, const char *name_start, size_t name_length, void *user_data )
147
+ {
148
+ ++end_tag_count;
149
+ detected_end_tags = add_detected_tag( detected_end_tags, tag_info_new( name_start, name_length, NULL ) );
150
+ }
151
+
152
+ static void output_handler( const void *data, size_t size, void *user_data )
153
+ {
154
+ write( (int)user_data, data, size );
155
+ }
156
+
157
+ static void feed_data( ESIParser *parser, const char *data )
158
+ {
159
+ // printf( "feeding: %s\n", data );
160
+ esi_parser_execute( parser, data, strlen(data) );
161
+ }
162
+
163
+ #define TEST_INIT \
164
+ int fd; \
165
+ struct stat st; \
166
+ char *output = NULL; \
167
+ size_t output_size; \
168
+ int status = 0;\
169
+ start_tag_count = 0; \
170
+ end_tag_count = 0; \
171
+ printf( "%s: ", __FUNCTION__ ); \
172
+ esi_parser_init( parser ); \
173
+ \
174
+ esi_parser_start_tag_handler( parser, start_tag_handler ); \
175
+ esi_parser_end_tag_handler( parser, end_tag_handler ); \
176
+ \
177
+ unlink( "output.html" ); \
178
+ fd = open( "output.html", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); \
179
+ parser->user_data = (void*)fd; \
180
+ esi_parser_output_handler( parser, output_handler );
181
+
182
+ #define TEST_WITH_FILE(file)\
183
+ int size = 0;\
184
+ FILE *input = NULL;\
185
+ char buffer[16]; /* intentially using a small buffer size */\
186
+ TEST_INIT\
187
+ \
188
+ input = fopen( file, "r" );\
189
+ if( !input ){\
190
+ printf( "Failed to open %s\n", file );\
191
+ return;\
192
+ }\
193
+ \
194
+ while( (size = fread( buffer, sizeof(char), 15, input )) > 0 ){\
195
+ esi_parser_execute( parser, buffer, size );\
196
+ }\
197
+ \
198
+ fclose( input );
199
+
200
+ #define TEST_PREPARE_ASSERTIONS \
201
+ esi_parser_finish( parser ); \
202
+ \
203
+ close( fd ); \
204
+ \
205
+ fd = open( "output.html", O_RDONLY ); \
206
+ fstat( fd, &st ); \
207
+ output_size = st.st_size; \
208
+ output = (char*)malloc(sizeof(char)*(output_size+1)); \
209
+ read( fd, output, output_size ); \
210
+ output[output_size] = '\0'; \
211
+ close( fd ); \
212
+ TagInfo *start_tags = detected_start_tags; \
213
+ TagInfo *end_tags = detected_end_tags;
214
+
215
+ #define TEST_FINISH\
216
+ free( output ); \
217
+ free_detected_tags(); \
218
+ if( status ){ \
219
+ printf( "FAILED\n" ); \
220
+ }else{ \
221
+ printf( "PASSED\n" ); \
222
+ }
223
+ #define ASSERT_EQUAL( s1, s2 )\
224
+ status |= verify_string( s1, s2, __LINE__, __FUNCTION__ )
225
+
226
+ #define ASSERT_MATCH( regex, str )\
227
+ status |= verify_match_string( regex, str, __LINE__, __FUNCTION__ )
228
+ #define ASSERT_NO_MATCH( regex, str )\
229
+ status |= verify_no_match_string( regex, str, __LINE__, __FUNCTION__ )
230
+ #define ASSERT_TRUE( expr )\
231
+ status |= verify_true( expr, __LINE__, __FUNCTION__ )
232
+
233
+ #define ASSERT_TAG_NAME( name )\
234
+ ASSERT_NO_MATCH( "<", name ); \
235
+ ASSERT_MATCH( "esi:", name );
236
+
237
+ #define ASSERT_TAG_NAMES( tags )\
238
+ while( tags ){ \
239
+ ASSERT_TAG_NAME( tags->name );\
240
+ tags = tags->next;\
241
+ }
242
+
243
+ static void test_simple_parser_input( ESIParser *parser )
244
+ {
245
+ TEST_INIT
246
+
247
+ feed_data( parser, "<p>some input</p><esi:include/>some more input\nsome input<esi:include timeout='10' src='hello'/>some more input" );
248
+
249
+ TEST_PREPARE_ASSERTIONS
250
+
251
+ ASSERT_EQUAL( "<p>some input</p>some more input\nsome inputsome more input", output );
252
+ ASSERT_TRUE( start_tag_count == 2 );
253
+ ASSERT_TRUE( end_tag_count == 2 );
254
+
255
+ ASSERT_TAG_NAMES( start_tags )
256
+ ASSERT_TAG_NAMES( end_tags )
257
+
258
+ TEST_FINISH
259
+ }
260
+
261
+ static void test_chunked_input( ESIParser *parser )
262
+ {
263
+ TEST_INIT
264
+
265
+ feed_data( parser, "some input<" );
266
+ feed_data( parser, "e" );
267
+ feed_data( parser, "s" );
268
+ feed_data( parser, "i" );
269
+ feed_data( parser, ":" );
270
+ feed_data( parser, "i" );
271
+ feed_data( parser, "n" );
272
+ feed_data( parser, "lin" );
273
+ feed_data( parser, "e" );
274
+ feed_data( parser, " " );
275
+ feed_data( parser, "s" );
276
+ feed_data( parser, "rc" );
277
+ feed_data( parser, "=" );
278
+ feed_data( parser, "'hel" );
279
+ feed_data( parser, "lo'" );
280
+ feed_data( parser, "/" );
281
+ feed_data( parser, ">some more input\nsome input" );
282
+ feed_data( parser, "<esi:comment text=" );
283
+ feed_data( parser, "'hello'/>some more input" );
284
+
285
+ TEST_PREPARE_ASSERTIONS
286
+
287
+ ASSERT_EQUAL( "some inputsome more input\nsome inputsome more input", output );
288
+ ASSERT_TRUE( start_tag_count == 2 );
289
+ ASSERT_TRUE( end_tag_count == 2 );
290
+
291
+ ASSERT_TAG_NAMES( start_tags )
292
+ ASSERT_TAG_NAMES( end_tags )
293
+
294
+ TEST_FINISH
295
+ }
296
+ #define ESI_SAMPLE "../../../test/unit/esi-sample.html"
297
+ static void test_sample_input( ESIParser *parser )
298
+ {
299
+ TEST_WITH_FILE( ESI_SAMPLE );
300
+
301
+ TEST_PREPARE_ASSERTIONS
302
+
303
+ ASSERT_MATCH(" <div class=\"body\">", output );
304
+ ASSERT_MATCH(" <div>some content</div>", output);
305
+ ASSERT_MATCH("<em>Support for em tags since they have an initial start sequence similar to and &lt;esi: start/end sequence</em>", output );
306
+ ASSERT_NO_MATCH("<esi:", output);
307
+
308
+ ASSERT_TRUE( start_tag_count == 13 );
309
+ ASSERT_TRUE( end_tag_count == 13 );
310
+
311
+ ASSERT_TAG_NAMES( start_tags )
312
+ ASSERT_TAG_NAMES( end_tags )
313
+
314
+ TEST_FINISH
315
+ }
316
+
317
+ static void test_line_by_line( ESIParser *parser )
318
+ {
319
+ TEST_INIT
320
+
321
+ feed_data( parser, "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input" );
322
+ feed_data( parser, "some input<esi:include \nsrc='hello'/>some more input\nsome input<esi:include src=\"hello\"/>some more input" );
323
+ feed_data( parser, "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input" );
324
+ feed_data( parser, "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input" );
325
+ feed_data( parser, "</body></html>" );
326
+
327
+ TEST_PREPARE_ASSERTIONS
328
+
329
+ ASSERT_EQUAL("<html><head><body>some more inputsome inputsome more input\nsome inputsome more inputsome inputsome more input\nsome inputsome more input<p>some input</p>some more input\nsome inputsome more input</body></html>", output );
330
+ ASSERT_TRUE( start_tag_count == 7 );
331
+ ASSERT_TRUE( end_tag_count == 7 );
332
+
333
+ ASSERT_TAG_NAMES( start_tags )
334
+ ASSERT_TAG_NAMES( end_tags )
335
+
336
+ TEST_FINISH
337
+ }
338
+
339
+ #define ESI_LARGE_FILE "../../../test/integration/docs/index.html"
340
+ static void test_large_file( ESIParser *parser )
341
+ {
342
+ TEST_WITH_FILE( ESI_LARGE_FILE );
343
+
344
+ TEST_PREPARE_ASSERTIONS
345
+
346
+ ASSERT_NO_MATCH("<esi:", output);
347
+
348
+ ASSERT_MATCH( "</html>", output );
349
+
350
+ ASSERT_TAG_NAMES( start_tags )
351
+ ASSERT_TAG_NAMES( end_tags )
352
+
353
+ TEST_FINISH
354
+ }
355
+
356
+ int main( int argc, char **argv )
357
+ {
358
+ ESIParser *parser = esi_parser_new();
359
+
360
+ test_simple_parser_input( parser );
361
+
362
+ test_chunked_input( parser );
363
+
364
+ test_sample_input( parser );
365
+
366
+ test_line_by_line( parser );
367
+
368
+ test_large_file( parser );
369
+
370
+ esi_parser_free( parser );
371
+
372
+ return 0;
373
+ }
data/ext/esi/test1.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'esi'
2
+
3
+ output = ""
4
+ # TODO: support passing output stream to new
5
+ p = ESI::CParser.new
6
+
7
+ # TODO: support attributes
8
+ p.start_tag_handler do|tag_name, attrs|
9
+ puts "Start: #{tag_name} #{attrs.inspect}"
10
+ end
11
+
12
+ p.end_tag_handler do|tag_name|
13
+ puts "End: #{tag_name}"
14
+ end
15
+
16
+ p.output_handler do|data|
17
+ output << data
18
+ end
19
+
20
+ p.process "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input"
21
+ p.process "some input<esi:include \nsrc='hello'/>some more input\nsome input<esi:include src=\"hello\"/>some more input"
22
+ p.process "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input"
23
+ p.process "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input"
24
+ p.process "</body></html>"
25
+ p.finish
26
+ expected = %Q(<html><head><body>some more inputsome inputsome more input
27
+ some inputsome more inputsome inputsome more input
28
+ some inputsome more input<p>some input</p>some more input
29
+ some inputsome more input</body></html>)
30
+
31
+ if( expected != output )
32
+ puts "Failed output was different from the expected"
33
+ puts "Expected: #{expected}"
34
+ puts "\n"
35
+ puts "Actual: #{output}"
36
+ exit(1)
37
+ end
38
+
39
+ p.esi_tag = "hello"
40
+
41
+ if( "hello" != p.esi_tag )
42
+ puts "Failed esi_tag could not be set"
43
+ exit(1)
44
+ end
45
+
46
+ p.depth = 1
47
+ if( 1 != p.depth )
48
+ puts "Failed depth could not be set"
49
+ exit(1)
50
+ end
51
+
52
+ puts "PASSED"
53
+
54
+ p = nil
55
+
56
+ GC.start
data/ext/esi/test2.rb ADDED
@@ -0,0 +1,45 @@
1
+ require 'esi'
2
+
3
+ 10.times do
4
+ output = ""
5
+ # TODO: support passing output stream to new
6
+ p = ESI::CParser.new
7
+
8
+ # TODO: support attributes
9
+ p.start_tag_handler do|tag_name, attrs|
10
+ puts "Start: #{tag_name} #{attrs.inspect}"
11
+ end
12
+
13
+ p.end_tag_handler do|tag_name|
14
+ puts "End: #{tag_name}"
15
+ end
16
+
17
+ p.output_handler do|data|
18
+ output << data
19
+ end
20
+
21
+ p.process "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input"
22
+ p.process "some input<esi:include \nsrc='hello'/>some more input\nsome input<esi:include src=\"hello\"/>some more input"
23
+ p.process "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input"
24
+ p.process "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input"
25
+ p.process "</body></html>"
26
+ p.finish
27
+ expected = %Q(<html><head><body>some more inputsome inputsome more input
28
+ some inputsome more inputsome inputsome more input
29
+ some inputsome more input<p>some input</p>some more input
30
+ some inputsome more input</body></html>)
31
+
32
+ if( expected != output )
33
+ puts "Failed output was different from the expected"
34
+ puts "Expected: #{expected}"
35
+ puts "\n"
36
+ puts "Actual: #{output}"
37
+ exit(1)
38
+ end
39
+ end
40
+
41
+ puts "PASSED"
42
+
43
+ #p = nil
44
+
45
+ GC.start