mongrel_esi 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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