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
data/ext/esi/parser.h ADDED
@@ -0,0 +1,113 @@
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
+
10
+ char *esi_strndup( const char *str, size_t len );
11
+
12
+ /*
13
+ * ESI Attribute is a single attribute with name and value
14
+ *
15
+ * e.g. for an esi include tag:
16
+ *
17
+ * <esi:include src='/foo/bar/' timeout='10'/>
18
+ *
19
+ * 2 attributes would be allocated
20
+ *
21
+ * attrs[0]->name => 'src'
22
+ * attrs[0]->value => '/foo/bar/'
23
+ *
24
+ * attrs[1]->name => 'timeout'
25
+ * attrs[1]->value => '10'
26
+ *
27
+ * */
28
+ typedef struct _ESIAttr {
29
+ char *name;
30
+ char *value;
31
+ struct _ESIAttr *next;
32
+ }ESIAttribute;
33
+
34
+ ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length );
35
+ ESIAttribute *esi_attribute_copy( ESIAttribute *attribute );
36
+ void esi_attribute_free( ESIAttribute *attribute );
37
+
38
+ typedef void (*start_tag_cb)(const void *data,
39
+ const char *name_start,
40
+ size_t name_length,
41
+ ESIAttribute *attributes,
42
+ void *user_data);
43
+
44
+ typedef void (*end_tag_cb)(const void *data,
45
+ const char *name_start,
46
+ size_t name_length,
47
+ void *user_data);
48
+
49
+ typedef void (*output_cb)(const void *data,
50
+ size_t length,
51
+ void *user_data);
52
+
53
+ typedef struct _ESIParser {
54
+ int cs;
55
+ int prev_state;
56
+
57
+ void *user_data;
58
+
59
+ const char *mark;
60
+ size_t overflow_data_size; /* current size of the overflow data buffer */
61
+ char *overflow_data; /* overflow buffer if execute finishes and we are not in a final state store the parse data */
62
+
63
+ size_t echobuffer_allocated; /* amount of memory allocated for the echobuffer */
64
+ size_t echobuffer_index; /* current write position of the last echo'ed character */
65
+ char *echobuffer; /* echo buffer if the parse state is not 0 we store the characters here */
66
+
67
+ const char *tag_text; /* start pointer in data */
68
+ size_t tag_text_length; /* length from tag_text within data */
69
+
70
+ const char *attr_key; /* start pointer in data */
71
+ size_t attr_key_length;
72
+
73
+ const char *attr_value; /* start pointer in data */
74
+ size_t attr_value_length;
75
+
76
+ ESIAttribute *attributes, *last;
77
+
78
+ start_tag_cb start_tag_handler;
79
+ end_tag_cb end_tag_handler;
80
+ output_cb output_handler;
81
+
82
+ } ESIParser;
83
+
84
+ /* create a new Edge Side Include Parser */
85
+ ESIParser *esi_parser_new();
86
+ void esi_parser_free( ESIParser *parser );
87
+
88
+ /* initialize the parser */
89
+ int esi_parser_init( ESIParser *parser );
90
+
91
+ /*
92
+ * send a chunk of data to the parser, the internal parser state is returned
93
+ */
94
+ int esi_parser_execute( ESIParser *parser, const char *data, size_t length );
95
+ /*
96
+ * let the parser no that it has reached the end and it should flush any remaining data to the desired output device
97
+ */
98
+ int esi_parser_finish( ESIParser *parser );
99
+
100
+ /*
101
+ * setup a callback to execute when a new esi: start tag is encountered
102
+ * this is will fire for all block tags e.g. <esi:try>, <esi:attempt> and also
103
+ * inline tags <esi:inline src='cache-key'/> <esi:include src='dest'/>
104
+ */
105
+ void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback );
106
+
107
+ void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback );
108
+
109
+ /* setup a callback to recieve data ready for output */
110
+ void esi_parser_output_handler( ESIParser *parser, output_cb output_handler );
111
+
112
+
113
+ #endif
data/ext/esi/parser.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'esi/machine'
2
+
3
+ module ESI
4
+ class Parser < ESI::ParserMachine
5
+ # Provides a stream like interface to a single parameter block
6
+ class StreamCallBack
7
+ def initialize(callback)
8
+ @callback = callback
9
+ end
10
+ def << (output)
11
+ @callback.call( output )
12
+ end
13
+ end
14
+ attr_accessor :esi_tag, :output, :depth
15
+
16
+ def initialize( options = {} )
17
+ super()
18
+ @data = nil
19
+ @prev_buffer = ""
20
+ @start_tag = nil # call back for when we encounter a start tag
21
+ @end_tag = nil # call back for when we encounter an end tag
22
+ @esi_tag = nil # the current active esi tag
23
+ @output = nil
24
+ @depth = options[:depth] || 0 # used to track the depth of requests include tags should be initialized with this depth
25
+ end
26
+
27
+ def start_tag_handler(&block)
28
+ @start_tag = block
29
+ end
30
+
31
+ def end_tag_handler(&block)
32
+ @end_tag = block
33
+ end
34
+
35
+ def output_handler(&block)
36
+ @output = StreamCallBack.new(block)
37
+ end
38
+
39
+ private
40
+ def stream_buffer(string)
41
+ if @esi_tag
42
+ @esi_tag.buffer( @output, string )# unless string.strip.empty?
43
+ else
44
+ @output << string
45
+ end
46
+ end
47
+
48
+ end
49
+ end
data/ext/esi/parser.rl ADDED
@@ -0,0 +1,398 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <ctype.h>
5
+ #include "parser.h"
6
+
7
+ /* define default callbacks */
8
+ static void
9
+ esi_parser_default_start_cb( const void *data,
10
+ const char *name_start,
11
+ size_t name_length,
12
+ ESIAttribute *attributes,
13
+ void *user_data )
14
+ {
15
+ }
16
+ static void
17
+ esi_parser_default_end_cb( const void *data,
18
+ const char *name_start,
19
+ size_t name_length,
20
+ void *user_data )
21
+ {
22
+ }
23
+ static void
24
+ esi_parser_default_output_cp(const void *data,
25
+ size_t length,
26
+ void *user_data)
27
+ {
28
+ }
29
+ #ifdef DEBUG
30
+ static void debug_string( const char *msg, const char *str, size_t len )
31
+ {
32
+ char *pstr = esi_strndup( str, len );
33
+ printf( "%s :'%s'\n", msg, pstr );
34
+ free( pstr );
35
+ }
36
+ #endif
37
+
38
+ static void esi_parser_echo_char( ESIParser *parser, char ch )
39
+ {
40
+ parser->output_handler( (void*)&ch, 1, parser->user_data );
41
+ }
42
+
43
+ static void esi_parser_echo_buffer( ESIParser *parser )
44
+ {
45
+ // debug_string( "echobuffer", parser->echobuffer, parser->echobuffer_index+1 );
46
+ parser->output_handler( parser->echobuffer, parser->echobuffer_index+1, parser->user_data );
47
+ }
48
+
49
+ static void esi_parser_echobuffer_clear( ESIParser *parser )
50
+ {
51
+ parser->echobuffer_index = -1;
52
+ }
53
+
54
+ static void esi_parser_concat_to_echobuffer( ESIParser *parser, char ch )
55
+ {
56
+ parser->echobuffer_index++;
57
+
58
+ if( parser->echobuffer_allocated <= parser->echobuffer_index ){
59
+ // double the echobuffer size
60
+ parser->echobuffer_allocated *= 2;
61
+ parser->echobuffer = (char*)realloc( parser->echobuffer, parser->echobuffer_allocated );
62
+ }
63
+ parser->echobuffer[parser->echobuffer_index] = ch;
64
+ // debug_string( "echo buffer", parser->echobuffer, parser->echobuffer_index+1 );
65
+ }
66
+
67
+ static void ltrim_pointer( const char **ptr, const char *bounds, size_t *len )
68
+ {
69
+ // remove any spaces or = at the before the value
70
+ while( isspace( **ptr ) ||
71
+ **ptr == '=' ||
72
+ **ptr == '"' ||
73
+ **ptr == '<' ||
74
+ **ptr == '\'' &&
75
+ *len > 0 &&
76
+ (*ptr != bounds) ){
77
+ (*ptr)++;
78
+ (*len)--;
79
+ }
80
+ }
81
+
82
+ %%{
83
+ machine esi;
84
+
85
+ action begin {
86
+ parser->mark = p;
87
+ //debug_string( "begin", p, 1 );
88
+ }
89
+ action finish {
90
+ // printf( "finish\n" );
91
+ }
92
+
93
+ # record the position of the start tag
94
+ action see_start_tag {
95
+ parser->tag_text = parser->mark+1;
96
+ parser->tag_text_length = p - (parser->mark+1);
97
+ // debug_string( "have esi start", parser->tag_text, parser->tag_text_length );
98
+ parser->mark = p;
99
+ //debug_string( "see_start_tag", p, 1 );
100
+ }
101
+
102
+ action see_end_tag {
103
+ //debug_string( "see_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
104
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
105
+ //debug_string( "see_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
106
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
107
+ //debug_string( "see_end_tag: after start parsed esi tag", parser->tag_text, parser->tag_text_length );
108
+ parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
109
+ //debug_string( "see_end_tag: after end parsed esi tag", parser->tag_text, parser->tag_text_length );
110
+ parser->tag_text = NULL;
111
+ parser->tag_text_length = 0;
112
+ parser->mark = p;
113
+ //debug_string( "see_end_tag", p, 1 );
114
+ }
115
+
116
+ action see_block_start_with_attributes {
117
+ // debug_string( "parsed esi tag", parser->tag_text, parser->tag_text_length );
118
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
119
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
120
+ parser->tag_text = NULL;
121
+ parser->tag_text_length = 0;
122
+ }
123
+
124
+ action see_attribute_key {
125
+ parser->attr_key = parser->mark;
126
+ parser->attr_key_length = p - parser->mark;
127
+ parser->mark = p;
128
+ ltrim_pointer( &(parser->attr_key), p, &(parser->attr_key_length) );
129
+ // debug_string( "\tattribute key", parser->attr_key, parser->attr_key_length );
130
+ //debug_string( "see_attribute_key", p, 1 );
131
+ }
132
+
133
+ action see_attribute_value {
134
+ ESIAttribute *attr;
135
+ parser->attr_value = parser->mark;
136
+ parser->attr_value_length = p - parser->mark;
137
+ parser->mark = p;
138
+
139
+ ltrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );
140
+
141
+ // allocate a new attribute
142
+ attr = esi_attribute_new( parser->attr_key, parser->attr_key_length,
143
+ parser->attr_value, parser->attr_value_length );
144
+ if( parser->attributes ){
145
+ parser->last->next = attr;
146
+ parser->last = attr;
147
+ }
148
+ else{
149
+ parser->last = parser->attributes = attr;
150
+ }
151
+ // debug_string( "\tattribute value", parser->attr_value, parser->attr_value_length );
152
+ //debug_string( "see_attribute_value", p, 1 );
153
+ }
154
+
155
+ action block_start_tag {
156
+ parser->tag_text = parser->mark;
157
+ parser->tag_text_length = p - parser->mark;
158
+ parser->mark = p;
159
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
160
+ parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, NULL, parser->user_data );
161
+ //debug_string( "block_start_tag", p, 1 );
162
+ }
163
+
164
+ action block_end_tag {
165
+ parser->tag_text = parser->mark+2;
166
+ parser->tag_text_length = p - (parser->mark+2);
167
+ //printf( "mark: [%s], p: [%s], length: %d\n", parser->mark, p, parser->tag_text_length );
168
+ parser->mark = p;
169
+ //debug_string( "block_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
170
+ ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
171
+ //debug_string( "block_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
172
+ parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
173
+ }
174
+
175
+ action echo {
176
+ switch( cs ){
177
+ case 0:
178
+ if( parser->prev_state != 12 && parser->prev_state != 7 ){
179
+ if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
180
+ // stream echobuffer
181
+ esi_parser_echo_buffer( parser );
182
+ }
183
+ // printf( "[%d: %c]", cs, *p );
184
+ // stream the current character
185
+ esi_parser_echo_char( parser, *p );
186
+ }
187
+ // clear the echobuffer
188
+ esi_parser_echobuffer_clear( parser );
189
+ break;
190
+ default:
191
+ // append characters to echobuffer
192
+ esi_parser_concat_to_echobuffer( parser, *p );
193
+ }
194
+ parser->prev_state = cs;
195
+ }
196
+
197
+ include esi_common_parser "common.rl";
198
+ }%%
199
+
200
+ %%write data;
201
+
202
+ char *esi_strndup( const char *str, size_t len )
203
+ {
204
+ char *s = (char*)malloc(sizeof(char)*(len+1));
205
+ memcpy( s, str, len );
206
+ s[len] = '\0';
207
+ return s;
208
+ }
209
+
210
+ ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length )
211
+ {
212
+ ESIAttribute *attr = (ESIAttribute*)malloc(sizeof(ESIAttribute));
213
+ attr->name = esi_strndup(name, name_length);
214
+ attr->value = esi_strndup(value, value_length);
215
+ attr->next = NULL;
216
+ return attr;
217
+ }
218
+
219
+ ESIAttribute *esi_attribute_copy( ESIAttribute *attribute )
220
+ {
221
+ ESIAttribute *head, *nattr;
222
+ if( !attribute ){ return NULL; }
223
+
224
+ // copy the first attribute
225
+ nattr = esi_attribute_new( attribute->name, strlen( attribute->name ),
226
+ attribute->value, strlen( attribute->value ) );
227
+ // save a pointer for return
228
+ head = nattr;
229
+ // copy next attributes
230
+ attribute = attribute->next;
231
+ while( attribute ) {
232
+ // set the next attribute
233
+ nattr->next = esi_attribute_new( attribute->name, strlen( attribute->name ),
234
+ attribute->value, strlen( attribute->value ) );
235
+ // next attribute
236
+ nattr = nattr->next;
237
+ attribute = attribute->next;
238
+ }
239
+ return head;
240
+ }
241
+
242
+ void esi_attribute_free( ESIAttribute *attribute )
243
+ {
244
+ ESIAttribute *ptr;
245
+ while( attribute ){
246
+ free( attribute->name );
247
+ free( attribute->value );
248
+ ptr = attribute->next;
249
+ free( attribute );
250
+ attribute = ptr;
251
+ }
252
+ }
253
+
254
+ ESIParser *esi_parser_new()
255
+ {
256
+ ESIParser *parser = (ESIParser*)malloc(sizeof(ESIParser));
257
+ parser->cs = esi_start;
258
+ parser->mark = NULL;
259
+ parser->overflow_data_size = 0;
260
+ parser->overflow_data = NULL;
261
+
262
+ /* allocate 1024 bytes for the echobuffer */
263
+ parser->echobuffer_allocated = 1024;
264
+ parser->echobuffer_index = -1;
265
+ parser->echobuffer = (char*)malloc(sizeof(char)*parser->echobuffer_allocated);
266
+
267
+ parser->attributes = NULL;
268
+ parser->last = NULL;
269
+
270
+ parser->start_tag_handler = esi_parser_default_start_cb;
271
+ parser->end_tag_handler = esi_parser_default_end_cb;
272
+ parser->output_handler = esi_parser_default_output_cp;
273
+
274
+ return parser;
275
+ }
276
+ void esi_parser_free( ESIParser *parser )
277
+ {
278
+ if( parser->overflow_data ){ free( parser->overflow_data ); }
279
+
280
+ free( parser->echobuffer );
281
+ esi_attribute_free( parser->attributes );
282
+
283
+ free( parser );
284
+ }
285
+
286
+ void esi_parser_output_handler( ESIParser *parser, output_cb output_handler )
287
+ {
288
+ parser->output_handler = output_handler;
289
+ }
290
+
291
+ int esi_parser_init( ESIParser *parser )
292
+ {
293
+ int cs;
294
+ %% write init;
295
+ parser->prev_state = parser->cs = cs;
296
+ return 0;
297
+ }
298
+
299
+ static int compute_offset( const char *mark, const char *data )
300
+ {
301
+ if( mark ){
302
+ return mark - data;
303
+ }
304
+ return -1;
305
+ }
306
+
307
+ int esi_parser_execute( ESIParser *parser, const char *data, size_t length )
308
+ {
309
+ int cs = parser->cs;
310
+ const char *p = data;
311
+ const char *pe = data + length;
312
+
313
+ if( length == 0 ){ return cs; }
314
+
315
+ if( parser->overflow_data && parser->overflow_data_size > 0 ){
316
+
317
+ // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
318
+ int mark_offset = compute_offset( parser->mark, parser->overflow_data );
319
+ int tag_text_offset = compute_offset( parser->tag_text, parser->overflow_data );
320
+ int attr_key_offset = compute_offset( parser->attr_key, parser->overflow_data );
321
+ int attr_value_offset = compute_offset( parser->attr_value, parser->overflow_data );
322
+
323
+ // debug_string("grow overflow buffer", parser->overflow_data, parser->overflow_data_size );
324
+
325
+ parser->overflow_data = (char*)realloc( parser->overflow_data, sizeof(char)*(parser->overflow_data_size+length) );
326
+ memcpy( parser->overflow_data+parser->overflow_data_size, data, length );
327
+
328
+ p = parser->overflow_data + parser->overflow_data_size;
329
+
330
+ // in our new memory space mark will now be
331
+ parser->mark = ( mark_offset >= 0 ) ? parser->overflow_data + mark_offset : NULL;
332
+ parser->tag_text = ( tag_text_offset >= 0 ) ? parser->overflow_data + tag_text_offset : NULL;
333
+ parser->attr_key = ( attr_key_offset >= 0 ) ? parser->overflow_data + attr_key_offset : NULL;
334
+ parser->attr_value = ( attr_value_offset >= 0 ) ? parser->overflow_data + attr_value_offset : NULL;
335
+
336
+ data = parser->overflow_data;
337
+ parser->overflow_data_size = length = length + parser->overflow_data_size;
338
+ pe = data + length;
339
+
340
+ // debug_string( "overflow", parser->overflow_data, parser->overflow_data_size );
341
+ }
342
+
343
+ if( !parser->mark ){
344
+ parser->mark = p;
345
+ }
346
+
347
+ // printf( "cs: %d, ", cs );
348
+ // debug_string( "data", data, length );
349
+
350
+ %% write exec;
351
+
352
+ parser->cs = cs;
353
+
354
+ if( cs != esi_start && cs != 0 ){
355
+
356
+ if( !parser->overflow_data ){
357
+ // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
358
+ int mark_offset = compute_offset( parser->mark, data );
359
+ int tag_text_offset = compute_offset( parser->tag_text, data );
360
+ int attr_key_offset = compute_offset( parser->attr_key, data );
361
+ int attr_value_offset = compute_offset( parser->attr_value, data );
362
+ //debug_string( "mark before move", parser->mark, 1 );
363
+
364
+ parser->overflow_data = (char*)malloc( sizeof( char ) * length );
365
+ memcpy( parser->overflow_data, data, length );
366
+ parser->overflow_data_size = length;
367
+
368
+ // in our new memory space mark will now be
369
+ parser->mark = ( mark_offset >= 0 ) ? parser->overflow_data + mark_offset : NULL;
370
+ parser->tag_text = ( tag_text_offset >= 0 ) ? parser->overflow_data + tag_text_offset : NULL;
371
+ parser->attr_key = ( attr_key_offset >= 0 ) ? parser->overflow_data + attr_key_offset : NULL;
372
+ parser->attr_value = ( attr_value_offset >= 0 ) ? parser->overflow_data + attr_value_offset : NULL;
373
+ //if( parser->mark ){ debug_string( "mark after move", parser->mark, 1 ); } else { printf( "mark is now empty\n" ); }
374
+ }
375
+
376
+ }else if( parser->overflow_data ){
377
+ free( parser->overflow_data );
378
+ parser->overflow_data = NULL;
379
+ parser->overflow_data_size = 0;
380
+ }
381
+
382
+ return cs;
383
+ }
384
+ int esi_parser_finish( ESIParser *parser )
385
+ {
386
+ %% write eof;
387
+ return 0;
388
+ }
389
+
390
+ void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback )
391
+ {
392
+ parser->start_tag_handler = callback;
393
+ }
394
+
395
+ void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback )
396
+ {
397
+ parser->end_tag_handler = callback;
398
+ }