mongrel_esi 0.5.2 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. data/ext/esi/esi_parser.c +1 -0
  2. data/ext/esi/extconf.rb +2 -0
  3. data/ext/esi/parser.c +2 -2
  4. data/ext/esi/parser.h +2 -0
  5. data/ext/esi/parser.rl +2 -2
  6. data/ext/esi/test/common.rl +46 -0
  7. data/ext/esi/test/parser.c +1901 -0
  8. data/ext/esi/test/parser.h +127 -0
  9. data/ext/esi/test/parser.rl +611 -0
  10. data/ext/esi/test/test.c +2 -2
  11. data/lib/esi/cache.rb +1 -1
  12. data/lib/esi/version.rb +1 -1
  13. data/test/benchmarks/perf-trunk-n1000-c1.csv +100 -100
  14. data/test/benchmarks/perf-trunk-n1000-c2.csv +100 -100
  15. data/test/benchmarks/perf-trunk-n1000-c3.csv +100 -100
  16. data/test/benchmarks/perf-trunk-n1000-c4.csv +100 -100
  17. data/test/benchmarks/perf-trunk-n1000-c5.csv +100 -100
  18. data/test/integration/docs/large-no-cache.html +688 -0
  19. data/test/integration/handler_test.rb +7 -2
  20. data/test/load_test_ab.rb +1 -1
  21. metadata +7 -222
  22. data/doc/rdoc/classes/ESI/CParser.html +0 -122
  23. data/doc/rdoc/classes/ESI/Cache.html +0 -178
  24. data/doc/rdoc/classes/ESI/Cache.src/M000087.html +0 -17
  25. data/doc/rdoc/classes/ESI/Cache.src/M000088.html +0 -20
  26. data/doc/rdoc/classes/ESI/Config.html +0 -314
  27. data/doc/rdoc/classes/ESI/Config.src/M000049.html +0 -18
  28. data/doc/rdoc/classes/ESI/Config.src/M000050.html +0 -18
  29. data/doc/rdoc/classes/ESI/Config.src/M000051.html +0 -35
  30. data/doc/rdoc/classes/ESI/Config.src/M000052.html +0 -40
  31. data/doc/rdoc/classes/ESI/Config.src/M000053.html +0 -23
  32. data/doc/rdoc/classes/ESI/Config.src/M000054.html +0 -18
  33. data/doc/rdoc/classes/ESI/Config.src/M000055.html +0 -20
  34. data/doc/rdoc/classes/ESI/Config.src/M000056.html +0 -24
  35. data/doc/rdoc/classes/ESI/Config/CacheConfig.html +0 -212
  36. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000060.html +0 -19
  37. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000061.html +0 -19
  38. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000062.html +0 -18
  39. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000063.html +0 -18
  40. data/doc/rdoc/classes/ESI/Config/CacheConfig.src/M000064.html +0 -18
  41. data/doc/rdoc/classes/ESI/Config/ConfigRouter.html +0 -187
  42. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000057.html +0 -19
  43. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000058.html +0 -21
  44. data/doc/rdoc/classes/ESI/Config/ConfigRouter.src/M000059.html +0 -21
  45. data/doc/rdoc/classes/ESI/Dispatcher.html +0 -174
  46. data/doc/rdoc/classes/ESI/Dispatcher.src/M000092.html +0 -19
  47. data/doc/rdoc/classes/ESI/Dispatcher.src/M000093.html +0 -27
  48. data/doc/rdoc/classes/ESI/Fragment.html +0 -218
  49. data/doc/rdoc/classes/ESI/Fragment.src/M000111.html +0 -20
  50. data/doc/rdoc/classes/ESI/Fragment.src/M000112.html +0 -18
  51. data/doc/rdoc/classes/ESI/Fragment.src/M000113.html +0 -18
  52. data/doc/rdoc/classes/ESI/Invalidator.html +0 -131
  53. data/doc/rdoc/classes/ESI/Invalidator.src/M000004.html +0 -41
  54. data/doc/rdoc/classes/ESI/Log.html +0 -221
  55. data/doc/rdoc/classes/ESI/Log.src/M000030.html +0 -18
  56. data/doc/rdoc/classes/ESI/Log.src/M000031.html +0 -18
  57. data/doc/rdoc/classes/ESI/Log.src/M000032.html +0 -18
  58. data/doc/rdoc/classes/ESI/Log.src/M000033.html +0 -18
  59. data/doc/rdoc/classes/ESI/Log.src/M000034.html +0 -18
  60. data/doc/rdoc/classes/ESI/Log.src/M000035.html +0 -18
  61. data/doc/rdoc/classes/ESI/Log.src/M000036.html +0 -18
  62. data/doc/rdoc/classes/ESI/MemcachedCache.html +0 -314
  63. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000037.html +0 -24
  64. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000038.html +0 -22
  65. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000039.html +0 -19
  66. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000040.html +0 -23
  67. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000041.html +0 -18
  68. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000042.html +0 -19
  69. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000043.html +0 -18
  70. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000044.html +0 -18
  71. data/doc/rdoc/classes/ESI/MemcachedCache.src/M000045.html +0 -17
  72. data/doc/rdoc/classes/ESI/OutputAdapter.html +0 -204
  73. data/doc/rdoc/classes/ESI/OutputAdapter.src/M000094.html +0 -37
  74. data/doc/rdoc/classes/ESI/OutputAdapter.src/M000095.html +0 -18
  75. data/doc/rdoc/classes/ESI/OutputAdapter.src/M000096.html +0 -18
  76. data/doc/rdoc/classes/ESI/OutputAdapter.src/M000097.html +0 -18
  77. data/doc/rdoc/classes/ESI/Parser.html +0 -184
  78. data/doc/rdoc/classes/ESI/Parser.src/M000065.html +0 -51
  79. data/doc/rdoc/classes/ESI/Parser.src/M000066.html +0 -39
  80. data/doc/rdoc/classes/ESI/Parser.src/M000067.html +0 -19
  81. data/doc/rdoc/classes/ESI/Processor.html +0 -194
  82. data/doc/rdoc/classes/ESI/Processor.src/M000046.html +0 -26
  83. data/doc/rdoc/classes/ESI/Processor.src/M000047.html +0 -44
  84. data/doc/rdoc/classes/ESI/Processor.src/M000048.html +0 -26
  85. data/doc/rdoc/classes/ESI/Proxy.html +0 -304
  86. data/doc/rdoc/classes/ESI/Proxy.src/M000071.html +0 -20
  87. data/doc/rdoc/classes/ESI/Proxy.src/M000072.html +0 -63
  88. data/doc/rdoc/classes/ESI/Proxy.src/M000073.html +0 -62
  89. data/doc/rdoc/classes/ESI/Proxy.src/M000074.html +0 -24
  90. data/doc/rdoc/classes/ESI/Proxy.src/M000075.html +0 -19
  91. data/doc/rdoc/classes/ESI/Proxy.src/M000076.html +0 -22
  92. data/doc/rdoc/classes/ESI/Proxy.src/M000077.html +0 -18
  93. data/doc/rdoc/classes/ESI/Proxy.src/M000078.html +0 -28
  94. data/doc/rdoc/classes/ESI/Proxy.src/M000079.html +0 -29
  95. data/doc/rdoc/classes/ESI/RackAdapter.html +0 -214
  96. data/doc/rdoc/classes/ESI/RackAdapter.src/M000068.html +0 -18
  97. data/doc/rdoc/classes/ESI/RackAdapter.src/M000069.html +0 -34
  98. data/doc/rdoc/classes/ESI/RackAdapter.src/M000070.html +0 -17
  99. data/doc/rdoc/classes/ESI/RackConfig.html +0 -173
  100. data/doc/rdoc/classes/ESI/RackConfig.src/M000089.html +0 -28
  101. data/doc/rdoc/classes/ESI/RackConfig.src/M000090.html +0 -18
  102. data/doc/rdoc/classes/ESI/RackConfig.src/M000091.html +0 -20
  103. data/doc/rdoc/classes/ESI/Request.html +0 -158
  104. data/doc/rdoc/classes/ESI/Request.src/M000098.html +0 -18
  105. data/doc/rdoc/classes/ESI/Request.src/M000099.html +0 -18
  106. data/doc/rdoc/classes/ESI/Response.html +0 -250
  107. data/doc/rdoc/classes/ESI/Response.src/M000080.html +0 -23
  108. data/doc/rdoc/classes/ESI/Response.src/M000081.html +0 -18
  109. data/doc/rdoc/classes/ESI/Response.src/M000082.html +0 -21
  110. data/doc/rdoc/classes/ESI/Response.src/M000083.html +0 -20
  111. data/doc/rdoc/classes/ESI/Response.src/M000084.html +0 -25
  112. data/doc/rdoc/classes/ESI/Response.src/M000085.html +0 -18
  113. data/doc/rdoc/classes/ESI/Response.src/M000086.html +0 -33
  114. data/doc/rdoc/classes/ESI/Router.html +0 -212
  115. data/doc/rdoc/classes/ESI/Router.src/M000109.html +0 -36
  116. data/doc/rdoc/classes/ESI/Router.src/M000110.html +0 -25
  117. data/doc/rdoc/classes/ESI/RubyCache.html +0 -278
  118. data/doc/rdoc/classes/ESI/RubyCache.src/M000100.html +0 -20
  119. data/doc/rdoc/classes/ESI/RubyCache.src/M000101.html +0 -20
  120. data/doc/rdoc/classes/ESI/RubyCache.src/M000102.html +0 -20
  121. data/doc/rdoc/classes/ESI/RubyCache.src/M000103.html +0 -22
  122. data/doc/rdoc/classes/ESI/RubyCache.src/M000104.html +0 -18
  123. data/doc/rdoc/classes/ESI/RubyCache.src/M000105.html +0 -22
  124. data/doc/rdoc/classes/ESI/RubyCache.src/M000106.html +0 -18
  125. data/doc/rdoc/classes/ESI/RubyCache.src/M000107.html +0 -18
  126. data/doc/rdoc/classes/ESI/RubyCache.src/M000108.html +0 -18
  127. data/doc/rdoc/classes/ESI/Tag.html +0 -141
  128. data/doc/rdoc/classes/ESI/Tag/Attempt.html +0 -113
  129. data/doc/rdoc/classes/ESI/Tag/Base.html +0 -237
  130. data/doc/rdoc/classes/ESI/Tag/Base.src/M000026.html +0 -23
  131. data/doc/rdoc/classes/ESI/Tag/Base.src/M000027.html +0 -22
  132. data/doc/rdoc/classes/ESI/Tag/Base.src/M000028.html +0 -22
  133. data/doc/rdoc/classes/ESI/Tag/Base.src/M000029.html +0 -17
  134. data/doc/rdoc/classes/ESI/Tag/Container.html +0 -206
  135. data/doc/rdoc/classes/ESI/Tag/Container.src/M000015.html +0 -20
  136. data/doc/rdoc/classes/ESI/Tag/Container.src/M000016.html +0 -22
  137. data/doc/rdoc/classes/ESI/Tag/Container.src/M000017.html +0 -25
  138. data/doc/rdoc/classes/ESI/Tag/Except.html +0 -184
  139. data/doc/rdoc/classes/ESI/Tag/Except.src/M000018.html +0 -21
  140. data/doc/rdoc/classes/ESI/Tag/Except.src/M000019.html +0 -20
  141. data/doc/rdoc/classes/ESI/Tag/Except.src/M000020.html +0 -18
  142. data/doc/rdoc/classes/ESI/Tag/Include.html +0 -257
  143. data/doc/rdoc/classes/ESI/Tag/Include.src/M000005.html +0 -20
  144. data/doc/rdoc/classes/ESI/Tag/Include.src/M000006.html +0 -18
  145. data/doc/rdoc/classes/ESI/Tag/Include.src/M000007.html +0 -34
  146. data/doc/rdoc/classes/ESI/Tag/Include.src/M000008.html +0 -22
  147. data/doc/rdoc/classes/ESI/Tag/Include.src/M000009.html +0 -27
  148. data/doc/rdoc/classes/ESI/Tag/Include.src/M000010.html +0 -30
  149. data/doc/rdoc/classes/ESI/Tag/Include.src/M000011.html +0 -51
  150. data/doc/rdoc/classes/ESI/Tag/Include/Request.html +0 -199
  151. data/doc/rdoc/classes/ESI/Tag/Include/Request.src/M000012.html +0 -18
  152. data/doc/rdoc/classes/ESI/Tag/Include/Request.src/M000013.html +0 -44
  153. data/doc/rdoc/classes/ESI/Tag/Include/Request/Error.html +0 -155
  154. data/doc/rdoc/classes/ESI/Tag/Include/Request/Error.src/M000014.html +0 -19
  155. data/doc/rdoc/classes/ESI/Tag/Invalidate.html +0 -171
  156. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000023.html +0 -19
  157. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000024.html +0 -51
  158. data/doc/rdoc/classes/ESI/Tag/Invalidate.src/M000025.html +0 -19
  159. data/doc/rdoc/classes/ESI/Tag/Try.html +0 -154
  160. data/doc/rdoc/classes/ESI/Tag/Try.src/M000021.html +0 -38
  161. data/doc/rdoc/classes/ESI/Tag/Try.src/M000022.html +0 -18
  162. data/doc/rdoc/classes/MultiDirHandler.html +0 -198
  163. data/doc/rdoc/classes/MultiDirHandler.src/M000001.html +0 -20
  164. data/doc/rdoc/classes/MultiDirHandler.src/M000002.html +0 -28
  165. data/doc/rdoc/classes/MultiDirHandler.src/M000003.html +0 -22
  166. data/doc/rdoc/created.rid +0 -1
  167. data/doc/rdoc/files/COPYING.html +0 -167
  168. data/doc/rdoc/files/LICENSE.html +0 -605
  169. data/doc/rdoc/files/README.html +0 -361
  170. data/doc/rdoc/files/ext/esi/common_rl.html +0 -160
  171. data/doc/rdoc/files/ext/esi/esi_parser_c.html +0 -101
  172. data/doc/rdoc/files/ext/esi/parser_c.html +0 -101
  173. data/doc/rdoc/files/ext/esi/parser_h.html +0 -101
  174. data/doc/rdoc/files/ext/esi/parser_rl.html +0 -867
  175. data/doc/rdoc/files/ext/esi/test/test_c.html +0 -101
  176. data/doc/rdoc/files/lib/esi/cache_rb.html +0 -120
  177. data/doc/rdoc/files/lib/esi/config_rb.html +0 -115
  178. data/doc/rdoc/files/lib/esi/dispatcher_rb.html +0 -110
  179. data/doc/rdoc/files/lib/esi/invalidator_rb.html +0 -114
  180. data/doc/rdoc/files/lib/esi/logger_rb.html +0 -108
  181. data/doc/rdoc/files/lib/esi/parser_rb.html +0 -120
  182. data/doc/rdoc/files/lib/esi/processor_rb.html +0 -115
  183. data/doc/rdoc/files/lib/esi/proxy_rb.html +0 -123
  184. data/doc/rdoc/files/lib/esi/rack_adapter_rb.html +0 -117
  185. data/doc/rdoc/files/lib/esi/response_rb.html +0 -116
  186. data/doc/rdoc/files/lib/esi/router_rb.html +0 -107
  187. data/doc/rdoc/files/lib/esi/tag/attempt_rb.html +0 -114
  188. data/doc/rdoc/files/lib/esi/tag/base_rb.html +0 -114
  189. data/doc/rdoc/files/lib/esi/tag/container_rb.html +0 -115
  190. data/doc/rdoc/files/lib/esi/tag/except_rb.html +0 -114
  191. data/doc/rdoc/files/lib/esi/tag/include_rb.html +0 -116
  192. data/doc/rdoc/files/lib/esi/tag/invalidate_rb.html +0 -115
  193. data/doc/rdoc/files/lib/esi/tag/try_rb.html +0 -115
  194. data/doc/rdoc/files/lib/esi/version_rb.html +0 -101
  195. data/doc/rdoc/files/lib/multi_dirhandler_rb.html +0 -109
  196. data/doc/rdoc/fr_class_index.html +0 -57
  197. data/doc/rdoc/fr_file_index.html +0 -55
  198. data/doc/rdoc/fr_method_index.html +0 -139
  199. data/doc/rdoc/index.html +0 -24
  200. data/doc/rdoc/rdoc-style.css +0 -208
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Copyright (c) 2007 Todd A. Fisher
3
+ * You can redistribute it and/or modify it under the same terms as Mozilla Public License 1.1.
4
+ */
5
+ #ifndef ESI_PARSER_H
6
+ #define ESI_PARSER_H
7
+ #include <sys/types.h>
8
+
9
+ /* how much output to hold in memory before sending out */
10
+ #define ESI_OUTPUT_BUFFER_SIZE 4096
11
+ #define ESI_ECHOBUFFER_SIZE 128
12
+
13
+ char *esi_strndup( const char *str, size_t len );
14
+
15
+ /*
16
+ * ESI Attribute is a single attribute with name and value
17
+ *
18
+ * e.g. for an esi include tag:
19
+ *
20
+ * <esi:include src='/foo/bar/' timeout='10'/>
21
+ *
22
+ * 2 attributes would be allocated
23
+ *
24
+ * attrs[0]->name => 'src'
25
+ * attrs[0]->value => '/foo/bar/'
26
+ *
27
+ * attrs[1]->name => 'timeout'
28
+ * attrs[1]->value => '10'
29
+ *
30
+ * */
31
+ typedef struct _ESIAttr {
32
+ const char *name;
33
+ const char *value;
34
+ size_t name_length;
35
+ size_t value_length;
36
+ struct _ESIAttr *next;
37
+ }ESIAttribute;
38
+
39
+ ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length );
40
+ ESIAttribute *esi_attribute_copy( ESIAttribute *attribute );
41
+ void esi_attribute_free( ESIAttribute *attribute );
42
+
43
+ typedef void (*start_tag_cb)(const void *data,
44
+ const char *name_start,
45
+ size_t name_length,
46
+ ESIAttribute *attributes,
47
+ void *user_data);
48
+
49
+ typedef void (*end_tag_cb)(const void *data,
50
+ const char *name_start,
51
+ size_t name_length,
52
+ void *user_data);
53
+
54
+ typedef void (*output_cb)(const void *data,
55
+ size_t length,
56
+ void *user_data);
57
+
58
+ typedef struct _ESIParser {
59
+ int cs;
60
+ int prev_state;
61
+
62
+ void *user_data;
63
+
64
+ const char *mark;
65
+ size_t overflow_data_size; /* amount of the overflow buffer being used */
66
+ size_t overflow_data_allocated; /* amount of memory allocated to use for the overflow buffer */
67
+ char *overflow_data; /* overflow buffer if execute finishes and we are not in a final state store the parse data */
68
+ unsigned using_overflow:1; /* if this is 1, overflow data is in use. */
69
+
70
+ size_t echobuffer_allocated; /* amount of memory allocated for the echobuffer */
71
+ size_t echobuffer_index; /* current write position of the last echo'ed character */
72
+ char *echobuffer; /* echo buffer if the parse state is not 0 we store the characters here */
73
+
74
+ const char *tag_text; /* start pointer in data */
75
+ size_t tag_text_length; /* length from tag_text within data */
76
+
77
+ const char *attr_key; /* start pointer in data */
78
+ size_t attr_key_length;
79
+
80
+ const char *attr_value; /* start pointer in data */
81
+ size_t attr_value_length;
82
+
83
+ ESIAttribute *attributes, *last;
84
+
85
+ /* this memory will be pass to the output_cb when either it's full
86
+ * or eof is encountered */
87
+ char output_buffer[ESI_OUTPUT_BUFFER_SIZE+1];
88
+ size_t output_buffer_size;
89
+
90
+ start_tag_cb start_tag_handler;
91
+ end_tag_cb end_tag_handler;
92
+ output_cb output_handler;
93
+
94
+ } ESIParser;
95
+
96
+ /* create a new Edge Side Include Parser */
97
+ ESIParser *esi_parser_new();
98
+ void esi_parser_free( ESIParser *parser );
99
+
100
+ /* initialize the parser */
101
+ int esi_parser_init( ESIParser *parser );
102
+
103
+ /*
104
+ * send a chunk of data to the parser, the internal parser state is returned
105
+ */
106
+ int esi_parser_execute( ESIParser *parser, const char *data, size_t length );
107
+ /*
108
+ * let the parser no that it has reached the end and it should flush any remaining data to the desired output device
109
+ */
110
+ int esi_parser_finish( ESIParser *parser );
111
+
112
+ /*
113
+ * setup a callback to execute when a new esi: start tag is encountered
114
+ * this is will fire for all block tags e.g. <esi:try>, <esi:attempt> and also
115
+ * inline tags <esi:inline src='cache-key'/> <esi:include src='dest'/>
116
+ */
117
+ void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback );
118
+
119
+ void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback );
120
+
121
+ /* setup a callback to recieve data ready for output */
122
+ void esi_parser_output_handler( ESIParser *parser, output_cb output_handler );
123
+
124
+ void esi_parser_flush_output( ESIParser *parser );
125
+
126
+
127
+ #endif
@@ -0,0 +1,611 @@
1
+ /**
2
+ * Copyright (c) 2008 Todd A. Fisher
3
+ * see LICENSE
4
+ */
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <ctype.h>
9
+ #include "parser.h"
10
+
11
+ #ifdef DEBUG
12
+ static void debug_string( const char *msg, const char *str, size_t len )
13
+ {
14
+ char *pstr = esi_strndup( str, len );
15
+ printf( "%s :'%s'\n", msg, pstr );
16
+ free( pstr );
17
+ }
18
+ #else
19
+ #define debug_string(m,s,l)
20
+ #endif
21
+
22
+ /* define default callbacks */
23
+ static void
24
+ esi_parser_default_start_cb( const void *data,
25
+ const char *name_start,
26
+ size_t name_length,
27
+ ESIAttribute *attributes,
28
+ void *user_data )
29
+ {
30
+ }
31
+ static void
32
+ esi_parser_default_end_cb( const void *data,
33
+ const char *name_start,
34
+ size_t name_length,
35
+ void *user_data )
36
+ {
37
+ }
38
+ static void
39
+ esi_parser_default_output_cp(const void *data,
40
+ size_t length,
41
+ void *user_data)
42
+ {
43
+ }
44
+
45
+ /*
46
+ * flush output buffer
47
+ */
48
+ void esi_parser_flush_output( ESIParser *parser )
49
+ {
50
+ if( parser->output_buffer_size > 0 ) {
51
+ //debug_string( "esi_parser_flush_output:", parser->output_buffer, parser->output_buffer_size );
52
+ parser->output_handler( (void*)parser->output_buffer, parser->output_buffer_size, parser->user_data );
53
+ parser->output_buffer_size = 0;
54
+ }
55
+ }
56
+ /* send the character to the output handler marking it
57
+ * as ready for consumption, e.g. not an esi tag
58
+ */
59
+ static void esi_parser_echo_char( ESIParser *parser, char ch )
60
+ {
61
+ parser->output_buffer[parser->output_buffer_size++] = ch;
62
+ if( parser->output_buffer_size == ESI_OUTPUT_BUFFER_SIZE ) {
63
+ // flush the buffer to the consumer
64
+ esi_parser_flush_output( parser );
65
+ }
66
+ }
67
+ static void esi_parser_send_buffer( ESIParser *parser, const char *seq, size_t len )
68
+ {
69
+ const char *nseq = seq + len;
70
+ size_t nlen = parser->output_buffer_size + len;
71
+
72
+ if( nlen < ESI_OUTPUT_BUFFER_SIZE ) {
73
+ memcpy( parser->output_buffer + parser->output_buffer_size, seq, len );
74
+ parser->output_buffer_size += len;
75
+ }
76
+ else if( nlen > ESI_OUTPUT_BUFFER_SIZE ) {
77
+ while( seq != nseq ) {
78
+ esi_parser_echo_char( parser, *seq++ );
79
+ }
80
+ }
81
+ }
82
+ /* send any buffered characters to the output handler.
83
+ * This happens when we enter a case such as <em> where the
84
+ * first two characters < and e match the <esi: expression
85
+ */
86
+ static void esi_parser_echo_buffer( ESIParser *parser )
87
+ {
88
+ size_t i = 0, len = parser->echobuffer_index + 1;;
89
+ //debug_string( "echobuffer", parser->echobuffer, parser->echobuffer_index+1 );
90
+ //parser->output_handler( parser->echobuffer, parser->echobuffer_index+1, parser->user_data );
91
+ for( ; i < len; ++i ) {
92
+ esi_parser_echo_char( parser, parser->echobuffer[i] );
93
+ }
94
+ }
95
+ /*
96
+ * clear the buffer, no buffered characters should be emitted .
97
+ * e.g. we matched an esi tag completely and all buffered characters can be tossed out
98
+ */
99
+ static void esi_parser_echobuffer_clear( ESIParser *parser )
100
+ {
101
+ parser->echobuffer_index = -1;
102
+ }
103
+
104
+ /*
105
+ * add a character to the echobuffer.
106
+ * this happens when we can't determine if the character is allowed to be sent to the client device
107
+ * e.g. matching <e it's not yet determined if these characters are safe to send or not
108
+ */
109
+ static void esi_parser_concat_to_echobuffer( ESIParser *parser, char ch )
110
+ {
111
+ parser->echobuffer_index++;
112
+
113
+ if( parser->echobuffer_allocated <= parser->echobuffer_index ) {
114
+ /* double the echobuffer size
115
+ * we're getting some crazy input if this case ever happens
116
+ */
117
+ printf( "increase echobuffer: %lu, %s\n", (long)parser->echobuffer_allocated, parser->echobuffer );
118
+ parser->echobuffer_allocated *= 2;
119
+ parser->echobuffer = (char*)realloc( parser->echobuffer, parser->echobuffer_allocated );
120
+ }
121
+ parser->echobuffer[parser->echobuffer_index] = ch;
122
+ // debug_string( "echo buffer", parser->echobuffer, parser->echobuffer_index+1 );
123
+ }
124
+ /*
125
+ * the mark boundary is not always going to be exactly on the attribute or tag name boundary
126
+ * this trims characters from the left to right, advancing *ptr and reducing *len
127
+ */
128
+ static void ltrim_pointer( const char **ptr, const char *bounds, size_t *len )
129
+ {
130
+ // remove any spaces or = at the before the value
131
+ while( (isspace( **ptr ) ||
132
+ **ptr == '=' ||
133
+ **ptr == '"' ||
134
+ **ptr == '<' ||
135
+ **ptr == '\'' ) && (*len > 0) && (*ptr != bounds) ) {
136
+ (*ptr)++;
137
+ (*len)--;
138
+ }
139
+ }
140
+ /*
141
+ * similar to ltrim_pointer, this walks from bounds to *ptr, reducing *len
142
+ */
143
+ static void rtrim_pointer( const char **ptr, const char *bounds, size_t *len )
144
+ {
145
+ bounds = (*ptr+(*len-1));
146
+ // remove any spaces or = at the before the value
147
+ while( (isspace( *bounds ) ||
148
+ *bounds == '=' ||
149
+ *bounds == '"' ||
150
+ *bounds == '>' ||
151
+ *bounds == '\'') && (*len > 0) && (*ptr != bounds) ){
152
+ bounds--;
153
+ (*len)--;
154
+ }
155
+ }
156
+
157
+ %%{
158
+ machine esi;
159
+
160
+ action begin {
161
+ parser->mark = p;
162
+ //debug_string( "begin", p, 1 );
163
+ }
164
+ action finish {
165
+ // printf( "finish\n" );
166
+ }
167
+
168
+ # record the position of the start tag
169
+ action see_start_tag {
170
+ parser->tag_text = parser->mark+1;
171
+ parser->tag_text_length = p - (parser->mark+1);
172
+ parser->mark = p;
173
+ }
174
+
175
+ # detected an inline tag end, sends the start tag and end tag callback
176
+ action see_end_tag {
177
+ /* trim the tag text */
178
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
179
+ rtrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
180
+
181
+ /* send the start tag and end tag message */
182
+ esi_parser_flush_output( parser );
183
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
184
+ parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
185
+ //printf("\t[see inline tag]\n");
186
+
187
+ /* mark the position */
188
+ parser->tag_text = NULL;
189
+ parser->tag_text_length = 0;
190
+ parser->mark = p;
191
+
192
+ /* clear out the echo buffer */
193
+ esi_parser_echobuffer_clear( parser );
194
+ }
195
+
196
+ # block tag start, with attributes
197
+ action see_block_start_with_attributes {
198
+ /* trim tag text */
199
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
200
+ rtrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
201
+
202
+ /* send the start and end tag message */
203
+ esi_parser_flush_output( parser );
204
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
205
+ //printf("\t[see start tag with attributes]\n");
206
+
207
+ parser->tag_text = NULL;
208
+ parser->tag_text_length = 0;
209
+ parser->mark = p;
210
+
211
+ /* clear out the echo buffer */
212
+ esi_parser_echobuffer_clear( parser );
213
+ }
214
+
215
+ # see an attribute key, /foo\s*=/
216
+ action see_attribute_key {
217
+ /* save the attribute key start */
218
+ parser->attr_key = parser->mark;
219
+ /* compute the length of the key */
220
+ parser->attr_key_length = p - parser->mark;
221
+ /* save the position following the key */
222
+ parser->mark = p;
223
+
224
+ /* trim the attribute key */
225
+ ltrim_pointer( &(parser->attr_key), p, &(parser->attr_key_length) );
226
+ rtrim_pointer( &(parser->attr_key), p, &(parser->attr_key_length) );
227
+ }
228
+
229
+ # see an attribute value, aprox ~= /['"].*['"]/
230
+ action see_attribute_value {
231
+ ESIAttribute *attr;
232
+
233
+ /* save the attribute value start */
234
+ parser->attr_value = parser->mark;
235
+ /* compute the length of the value */
236
+ parser->attr_value_length = p - parser->mark;
237
+ /* svae the position following the value */
238
+ parser->mark = p;
239
+
240
+ /* trim the attribute value */
241
+ ltrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );
242
+ rtrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );
243
+
244
+ /* using the attr_key and attr_value, allocate a new attribute object */
245
+ attr = esi_attribute_new( parser->attr_key, parser->attr_key_length,
246
+ parser->attr_value, parser->attr_value_length );
247
+
248
+ /* add the new attribute to the list of attributes */
249
+ if( parser->attributes ) {
250
+ parser->last->next = attr;
251
+ parser->last = attr;
252
+ }
253
+ else {
254
+ parser->last = parser->attributes = attr;
255
+ }
256
+ }
257
+
258
+ # simple block start tag detected, e.g. <esi:try> no attributes
259
+ action block_start_tag {
260
+
261
+ parser->tag_text = parser->mark;
262
+ parser->tag_text_length = p - parser->mark;
263
+
264
+ parser->mark = p;
265
+
266
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
267
+ rtrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
268
+
269
+ esi_parser_flush_output( parser );
270
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, NULL, parser->user_data );
271
+ //printf("\t[see start tag]\n");
272
+
273
+ esi_parser_echobuffer_clear( parser );
274
+ }
275
+
276
+ # block end tag detected, e.g. </esi:try>
277
+ action block_end_tag {
278
+ /* offset by 2 to account for the </ characters */
279
+ parser->tag_text = parser->mark+2;
280
+ parser->tag_text_length = p - (parser->mark+2);
281
+
282
+ parser->mark = p;
283
+
284
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
285
+ rtrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
286
+
287
+ esi_parser_flush_output( parser );
288
+ parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
289
+ //printf("\t[see end tag]\n");
290
+
291
+ esi_parser_echobuffer_clear( parser );
292
+ }
293
+
294
+ # process each character in the input stream for output
295
+ action echo {
296
+ //printf( "[%c:%d],", *p, cs );
297
+ switch( cs ) {
298
+ case 0: /* non matching state */
299
+ if( parser->prev_state != 12 && parser->prev_state != 7 ){ /* states following a possible end state for a tag */
300
+ if( parser->echobuffer && parser->echobuffer_index != -1 ){
301
+ /* send the echo buffer */
302
+ esi_parser_echo_buffer( parser );
303
+ }
304
+ /* send the current character */
305
+ esi_parser_echo_char( parser, *p );
306
+ }
307
+ /* clear the echo buffer */
308
+ esi_parser_echobuffer_clear( parser );
309
+ break;
310
+ default:
311
+ /* append to the echo buffer */
312
+ esi_parser_concat_to_echobuffer( parser, *p );
313
+ }
314
+ /* save the previous state, necessary for end case detection such as /> and </esi:try> the trailing > character
315
+ is state 12 and 7
316
+ */
317
+ parser->prev_state = cs;
318
+ }
319
+
320
+ include esi_common_parser "common.rl";
321
+ }%%
322
+
323
+ %%write data;
324
+
325
+ /* dup the string up to len */
326
+ char *esi_strndup( const char *str, size_t len )
327
+ {
328
+ char *s = (char*)malloc(sizeof(char)*(len+1));
329
+ memcpy( s, str, len );
330
+ s[len] = '\0';
331
+ return s;
332
+ }
333
+
334
+ ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length )
335
+ {
336
+ ESIAttribute *attr = (ESIAttribute*)malloc(sizeof(ESIAttribute));
337
+ attr->name = name;//esi_strndup(name, name_length);
338
+ attr->value = value;//esi_strndup(value, value_length);
339
+ attr->name_length = name_length;
340
+ attr->value_length = value_length;
341
+ attr->next = NULL;
342
+ return attr;
343
+ }
344
+
345
+ ESIAttribute *esi_attribute_copy( ESIAttribute *attribute )
346
+ {
347
+ ESIAttribute *head, *nattr;
348
+ if( !attribute ){ return NULL; }
349
+
350
+ // copy the first attribute
351
+ nattr = esi_attribute_new( attribute->name, attribute->name_length,
352
+ attribute->value, attribute->value_length );
353
+ // save a pointer for return
354
+ head = nattr;
355
+ // copy next attributes
356
+ attribute = attribute->next;
357
+ while( attribute ) {
358
+ // set the next attribute
359
+ nattr->next = esi_attribute_new( attribute->name, attribute->name_length,
360
+ attribute->value, attribute->value_length );
361
+ // next attribute
362
+ nattr = nattr->next;
363
+ attribute = attribute->next;
364
+ }
365
+ return head;
366
+ }
367
+
368
+ void esi_attribute_free( ESIAttribute *attribute )
369
+ {
370
+ ESIAttribute *ptr;
371
+ while( attribute ){
372
+ // free( attribute->name );
373
+ // free( attribute->value );
374
+ ptr = attribute->next;
375
+ free( attribute );
376
+ attribute = ptr;
377
+ }
378
+ }
379
+
380
+ ESIParser *esi_parser_new()
381
+ {
382
+ ESIParser *parser = (ESIParser*)malloc(sizeof(ESIParser));
383
+ parser->cs = esi_start;
384
+ parser->mark = NULL;
385
+ parser->tag_text = NULL;
386
+ parser->attr_key = NULL;
387
+ parser->attr_value = NULL;
388
+ parser->overflow_data_size = 0;
389
+ parser->overflow_data = NULL;
390
+ parser->overflow_data_allocated = 0;
391
+ parser->using_overflow = 0;
392
+
393
+ /* allocate ESI_OUTPUT_BUFFER_SIZE bytes for the echobuffer */
394
+ parser->echobuffer_allocated = ESI_ECHOBUFFER_SIZE;
395
+ parser->echobuffer_index = -1;
396
+ parser->echobuffer = (char*)malloc(sizeof(char)*parser->echobuffer_allocated);
397
+
398
+ parser->attributes = NULL;
399
+ parser->last = NULL;
400
+
401
+ parser->start_tag_handler = esi_parser_default_start_cb;
402
+ parser->end_tag_handler = esi_parser_default_end_cb;
403
+ parser->output_handler = esi_parser_default_output_cp;
404
+
405
+ parser->output_buffer_size = 0;
406
+ memset( parser->output_buffer, 0, ESI_OUTPUT_BUFFER_SIZE );
407
+
408
+ return parser;
409
+ }
410
+ void esi_parser_free( ESIParser *parser )
411
+ {
412
+ if( parser->overflow_data ){ free( parser->overflow_data ); }
413
+
414
+ free( parser->echobuffer );
415
+
416
+ esi_attribute_free( parser->attributes );
417
+
418
+ free( parser );
419
+ }
420
+
421
+ void esi_parser_output_handler( ESIParser *parser, output_cb output_handler )
422
+ {
423
+ parser->output_handler = output_handler;
424
+ }
425
+
426
+ int esi_parser_init( ESIParser *parser )
427
+ {
428
+ int cs;
429
+ %% write init;
430
+ parser->prev_state = parser->cs = cs;
431
+ return 0;
432
+ }
433
+
434
+ static int compute_offset( const char *mark, const char *data )
435
+ {
436
+ if( mark ) {
437
+ return mark - data;
438
+ }
439
+ return -1;
440
+ }
441
+
442
+ /*
443
+ * scans the data buffer for a start sequence /<$/, /<e$/, /<es$/, /<esi$/, /<esi:$/
444
+ * returns index of if start sequence found else returns -1
445
+ */
446
+ static int
447
+ esi_parser_scan_for_start( ESIParser *parser, const char *data, size_t length )
448
+ {
449
+ size_t i, f = -2, s = -2;
450
+ char ch;
451
+
452
+ for( i = 0; i < length; ++i ) {
453
+ ch = data[i];
454
+ switch( ch ) {
455
+ case '<':
456
+ f = s = i;
457
+ break;
458
+ case '/':
459
+ if( s == (i-1) && f != -2 ) { s = i; }
460
+ break;
461
+ case 'e':
462
+ if( s == (i-1) && f != -2 ) { s = i; }
463
+ break;
464
+ case 's':
465
+ if( s == (i-1) && f != -2 ) { s = i; }
466
+ break;
467
+ case 'i':
468
+ if( s == (i-1) && f != -2 ) { s = i; }
469
+ break;
470
+ case ':':
471
+ if( s == (i-1) && f != -2 ) { s = i; return f; }
472
+ break;
473
+ default:
474
+ f = s = -2;
475
+ break;
476
+ }
477
+ }
478
+
479
+ // if s and f are still valid at end of input return f
480
+ if( f != -2 && s != -2 ) {
481
+ return f;
482
+ }
483
+ else {
484
+ return -1;
485
+ }
486
+ }
487
+
488
+ static void
489
+ esi_parser_append_data_to_overflow_data( ESIParser *parser, const char *data, size_t length )
490
+ {
491
+ int mark_offset = 0;
492
+ int tag_text_offset = 0;
493
+ int attr_key_offset = 0;
494
+ int attr_value_offset = 0;
495
+
496
+ if( parser->using_overflow ) {
497
+ // recompute mark, tag_text, attr_key, and attr_value as they all exist within overflow_data
498
+ mark_offset = compute_offset( parser->mark, parser->overflow_data );
499
+ tag_text_offset = compute_offset( parser->tag_text, parser->overflow_data );
500
+ attr_key_offset = compute_offset( parser->attr_key, parser->overflow_data );
501
+ attr_value_offset = compute_offset( parser->attr_value, parser->overflow_data );
502
+ }
503
+ else {
504
+ // recompute mark, tag_text, attr_key, and attr_value as they all exist within data
505
+ mark_offset = compute_offset( parser->mark, data );
506
+ tag_text_offset = compute_offset( parser->tag_text, data );
507
+ attr_key_offset = compute_offset( parser->attr_key, data );
508
+ attr_value_offset = compute_offset( parser->attr_value, data );
509
+ }
510
+
511
+ if( parser->overflow_data ) {
512
+ // check if we need to resize or grow the buffer
513
+ if( (parser->overflow_data_size + length) > parser->overflow_data_allocated ) {
514
+ parser->overflow_data_allocated += length;
515
+ // printf( "realloc: %d bytes, using %d\n", (int)parser->overflow_data_allocated, (int)(parser->overflow_data_size+length) );
516
+ parser->overflow_data = (char*)realloc( parser->overflow_data, sizeof(char)*(parser->overflow_data_allocated) );
517
+ }
518
+ memcpy( parser->overflow_data+parser->overflow_data_size, data, length );
519
+ parser->overflow_data_size += length;
520
+ }
521
+ else {
522
+ parser->overflow_data_allocated = ESI_OUTPUT_BUFFER_SIZE > length ? ESI_OUTPUT_BUFFER_SIZE : length;
523
+ parser->overflow_data = (char*)malloc( sizeof( char ) * parser->overflow_data_allocated );
524
+ memcpy( parser->overflow_data, data, length );
525
+ parser->overflow_data_size = length;
526
+ // printf( "malloc: %d for %d bytes\n", (int)parser->overflow_data_allocated, (int)length );
527
+ }
528
+
529
+ // in our new memory space mark will now be
530
+ parser->mark = ( mark_offset >= 0 ) ? parser->overflow_data + mark_offset : NULL;
531
+ parser->tag_text = ( tag_text_offset >= 0 ) ? parser->overflow_data + tag_text_offset : NULL;
532
+ parser->attr_key = ( attr_key_offset >= 0 ) ? parser->overflow_data + attr_key_offset : NULL;
533
+ parser->attr_value = ( attr_value_offset >= 0 ) ? parser->overflow_data + attr_value_offset : NULL;
534
+ }
535
+
536
+ /* accept an arbitrary length string buffer
537
+ * when this methods exits it determines if an end state was reached
538
+ * if no end state was reached it saves the full input into an internal buffer
539
+ * when invoked next, it reuses that internable buffer copying all pointers into the
540
+ * newly allocated buffer. if it exits in a terminal state, e.g. 0 then it will dump these buffers
541
+ */
542
+ int esi_parser_execute( ESIParser *parser, const char *data, size_t length )
543
+ {
544
+ int cs = parser->cs;
545
+ const char *p = data;
546
+ const char *eof = NULL; // ragel 6.x compat
547
+ const char *pe = data + length;
548
+ int pindex;
549
+
550
+ if( length == 0 ){ return cs; }
551
+
552
+ /* scan data for any '<esi:' start sequences, /<$/, /<e$/, /<es$/, /<esi$/, /<esi:$/ */
553
+ if( cs == esi_start || cs == 0 ) {
554
+ pindex = esi_parser_scan_for_start( parser, data, length );
555
+ if( pindex == -1 ) { /* this means there are no start sequences in the buffer we recieved */
556
+ esi_parser_send_buffer( parser, data, length );
557
+ return cs; /* no esi start sequences send it all out and break out early */
558
+ }
559
+ }
560
+
561
+ /* there's an existing overflow buffer and it's being used, append the new data */
562
+ //if( parser->overflow_data && parser->overflow_data_size > 0 ) {
563
+ if( parser->using_overflow ) {
564
+ int prev_overflow_size = parser->overflow_data_size; // save the current overflow size
565
+ esi_parser_append_data_to_overflow_data( parser, data, length );
566
+
567
+ /* set parser variables */
568
+ p = parser->overflow_data + prev_overflow_size;
569
+ data = parser->overflow_data;
570
+ length = parser->overflow_data_size;
571
+ pe = data + length;
572
+ }
573
+
574
+ if( !parser->mark ) {
575
+ parser->mark = p;
576
+ }
577
+
578
+ %% write exec;
579
+
580
+ parser->cs = cs;
581
+
582
+ if( cs != esi_start && cs != 0 ) {
583
+
584
+ /* reached the end and we're not at a termination point save the buffer as overflow */
585
+ if( !parser->using_overflow ) {
586
+ esi_parser_append_data_to_overflow_data( parser, data, length );
587
+ parser->using_overflow = 1;
588
+ }
589
+
590
+ } else if ( parser->using_overflow ) {
591
+ parser->using_overflow = 0;
592
+ parser->overflow_data_size = 0;
593
+ }
594
+
595
+ return cs;
596
+ }
597
+ int esi_parser_finish( ESIParser *parser )
598
+ {
599
+ esi_parser_flush_output( parser );
600
+ return 0;
601
+ }
602
+
603
+ void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback )
604
+ {
605
+ parser->start_tag_handler = callback;
606
+ }
607
+
608
+ void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback )
609
+ {
610
+ parser->end_tag_handler = callback;
611
+ }