~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_sub_filter_module.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_http.h>
 10 
 11 
 12 typedef struct {
 13     ngx_str_t                  match;
 14     ngx_http_complex_value_t   value;
 15 
 16     ngx_hash_t                 types;
 17 
 18     ngx_flag_t                 once;
 19 
 20     ngx_array_t               *types_keys;
 21 } ngx_http_sub_loc_conf_t;
 22 
 23 
 24 typedef enum {
 25     sub_start_state = 0,
 26     sub_match_state,
 27 } ngx_http_sub_state_e;
 28 
 29 
 30 typedef struct {
 31     ngx_str_t                  match;
 32 
 33     ngx_uint_t                 once;   /* unsigned  once:1 */
 34 
 35     ngx_buf_t                 *buf;
 36 
 37     u_char                    *pos;
 38     u_char                    *copy_start;
 39     u_char                    *copy_end;
 40 
 41     ngx_chain_t               *in;
 42     ngx_chain_t               *out;
 43     ngx_chain_t              **last_out;
 44     ngx_chain_t               *busy;
 45     ngx_chain_t               *free;
 46 
 47     ngx_str_t                  sub;
 48 
 49     ngx_uint_t                 state;
 50     size_t                     saved;
 51     size_t                     looked;
 52 } ngx_http_sub_ctx_t;
 53 
 54 
 55 static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r,
 56     ngx_http_sub_ctx_t *ctx);
 57 static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r,
 58     ngx_http_sub_ctx_t *ctx);
 59 
 60 static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd,
 61     void *conf);
 62 static void *ngx_http_sub_create_conf(ngx_conf_t *cf);
 63 static char *ngx_http_sub_merge_conf(ngx_conf_t *cf,
 64     void *parent, void *child);
 65 static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf);
 66 
 67 
 68 static ngx_command_t  ngx_http_sub_filter_commands[] = {
 69 
 70     { ngx_string("sub_filter"),
 71       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
 72       ngx_http_sub_filter,
 73       NGX_HTTP_LOC_CONF_OFFSET,
 74       0,
 75       NULL },
 76 
 77     { ngx_string("sub_filter_types"),
 78       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
 79       ngx_http_types_slot,
 80       NGX_HTTP_LOC_CONF_OFFSET,
 81       offsetof(ngx_http_sub_loc_conf_t, types_keys),
 82       &ngx_http_html_default_types[0] },
 83 
 84     { ngx_string("sub_filter_once"),
 85       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
 86       ngx_conf_set_flag_slot,
 87       NGX_HTTP_LOC_CONF_OFFSET,
 88       offsetof(ngx_http_sub_loc_conf_t, once),
 89       NULL },
 90 
 91       ngx_null_command
 92 };
 93 
 94 
 95 static ngx_http_module_t  ngx_http_sub_filter_module_ctx = {
 96     NULL,                                  /* preconfiguration */
 97     ngx_http_sub_filter_init,              /* postconfiguration */
 98 
 99     NULL,                                  /* create main configuration */
100     NULL,                                  /* init main configuration */
101 
102     NULL,                                  /* create server configuration */
103     NULL,                                  /* merge server configuration */
104 
105     ngx_http_sub_create_conf,              /* create location configuration */
106     ngx_http_sub_merge_conf                /* merge location configuration */
107 };
108 
109 
110 ngx_module_t  ngx_http_sub_filter_module = {
111     NGX_MODULE_V1,
112     &ngx_http_sub_filter_module_ctx,       /* module context */
113     ngx_http_sub_filter_commands,          /* module directives */
114     NGX_HTTP_MODULE,                       /* module type */
115     NULL,                                  /* init master */
116     NULL,                                  /* init module */
117     NULL,                                  /* init process */
118     NULL,                                  /* init thread */
119     NULL,                                  /* exit thread */
120     NULL,                                  /* exit process */
121     NULL,                                  /* exit master */
122     NGX_MODULE_V1_PADDING
123 };
124 
125 
126 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
127 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
128 
129 
130 static ngx_int_t
131 ngx_http_sub_header_filter(ngx_http_request_t *r)
132 {
133     ngx_http_sub_ctx_t        *ctx;
134     ngx_http_sub_loc_conf_t  *slcf;
135 
136     slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
137 
138     if (slcf->match.len == 0
139         || r->headers_out.content_length_n == 0
140         || ngx_http_test_content_type(r, &slcf->types) == NULL)
141     {
142         return ngx_http_next_header_filter(r);
143     }
144 
145     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
146     if (ctx == NULL) {
147         return NGX_ERROR;
148     }
149 
150     ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
151 
152     ctx->match = slcf->match;
153     ctx->last_out = &ctx->out;
154 
155     r->filter_need_in_memory = 1;
156 
157     if (r == r->main) {
158         ngx_http_clear_content_length(r);
159         ngx_http_clear_last_modified(r);
160     }
161 
162     return ngx_http_next_header_filter(r);
163 }
164 
165 
166 static ngx_int_t
167 ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
168 {
169     ngx_int_t                  rc;
170     ngx_buf_t                 *b;
171     ngx_chain_t               *cl;
172     ngx_http_sub_ctx_t        *ctx;
173     ngx_http_sub_loc_conf_t   *slcf;
174 
175     ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module);
176 
177     if (ctx == NULL) {
178         return ngx_http_next_body_filter(r, in);
179     }
180 
181     if ((in == NULL
182          && ctx->buf == NULL
183          && ctx->in == NULL
184          && ctx->busy == NULL))
185     {
186         return ngx_http_next_body_filter(r, in);
187     }
188 
189     if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) {
190 
191         if (ctx->busy) {
192             if (ngx_http_sub_output(r, ctx) == NGX_ERROR) {
193                 return NGX_ERROR;
194             }
195         }
196 
197         return ngx_http_next_body_filter(r, in);
198     }
199 
200     /* add the incoming chain to the chain ctx->in */
201 
202     if (in) {
203         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
204             return NGX_ERROR;
205         }
206     }
207 
208     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
209                    "http sub filter \"%V\"", &r->uri);
210 
211     while (ctx->in || ctx->buf) {
212 
213         if (ctx->buf == NULL ){
214             ctx->buf = ctx->in->buf;
215             ctx->in = ctx->in->next;
216             ctx->pos = ctx->buf->pos;
217         }
218 
219         if (ctx->state == sub_start_state) {
220             ctx->copy_start = ctx->pos;
221             ctx->copy_end = ctx->pos;
222         }
223 
224         b = NULL;
225 
226         while (ctx->pos < ctx->buf->last) {
227 
228             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
229                            "saved: %d state: %d", ctx->saved, ctx->state);
230 
231             rc = ngx_http_sub_parse(r, ctx);
232 
233             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
234                            "parse: %d, looked: %d %p-%p",
235                            rc, ctx->looked, ctx->copy_start, ctx->copy_end);
236 
237             if (rc == NGX_ERROR) {
238                 return rc;
239             }
240 
241             if (ctx->copy_start != ctx->copy_end) {
242 
243                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
244                                "saved: %d", ctx->saved);
245 
246                 if (ctx->saved) {
247 
248                     if (ctx->free) {
249                         cl = ctx->free;
250                         ctx->free = ctx->free->next;
251                         b = cl->buf;
252                         ngx_memzero(b, sizeof(ngx_buf_t));
253 
254                     } else {
255                         b = ngx_calloc_buf(r->pool);
256                         if (b == NULL) {
257                             return NGX_ERROR;
258                         }
259 
260                         cl = ngx_alloc_chain_link(r->pool);
261                         if (cl == NULL) {
262                             return NGX_ERROR;
263                         }
264 
265                         cl->buf = b;
266                     }
267 
268                     b->memory = 1;
269                     b->pos = ctx->match.data;
270                     b->last = ctx->match.data + ctx->saved;
271 
272                     *ctx->last_out = cl;
273                     ctx->last_out = &cl->next;
274 
275                     ctx->saved = 0;
276                 }
277 
278                 if (ctx->free) {
279                     cl = ctx->free;
280                     ctx->free = ctx->free->next;
281                     b = cl->buf;
282 
283                 } else {
284                     b = ngx_alloc_buf(r->pool);
285                     if (b == NULL) {
286                         return NGX_ERROR;
287                     }
288 
289                     cl = ngx_alloc_chain_link(r->pool);
290                     if (cl == NULL) {
291                         return NGX_ERROR;
292                     }
293 
294                     cl->buf = b;
295                 }
296 
297                 ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
298 
299                 b->pos = ctx->copy_start;
300                 b->last = ctx->copy_end;
301                 b->shadow = NULL;
302                 b->last_buf = 0;
303                 b->recycled = 0;
304 
305                 if (b->in_file) {
306                     b->file_last = b->file_pos + (b->last - ctx->buf->pos);
307                     b->file_pos += b->pos - ctx->buf->pos;
308                 }
309 
310                 cl->next = NULL;
311                 *ctx->last_out = cl;
312                 ctx->last_out = &cl->next;
313             }
314 
315             if (ctx->state == sub_start_state) {
316                 ctx->copy_start = ctx->pos;
317                 ctx->copy_end = ctx->pos;
318 
319             } else {
320                 ctx->copy_start = NULL;
321                 ctx->copy_end = NULL;
322             }
323 
324             if (rc == NGX_AGAIN) {
325                 continue;
326             }
327 
328 
329             /* rc == NGX_OK */
330 
331             b = ngx_calloc_buf(r->pool);
332             if (b == NULL) {
333                 return NGX_ERROR;
334             }
335 
336             cl = ngx_alloc_chain_link(r->pool);
337             if (cl == NULL) {
338                 return NGX_ERROR;
339             }
340 
341             slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
342 
343             if (ctx->sub.data == NULL) {
344 
345                 if (ngx_http_complex_value(r, &slcf->value, &ctx->sub)
346                     != NGX_OK)
347                 {
348                     return NGX_ERROR;
349                 }
350             }
351 
352             if (ctx->sub.len) {
353                 b->memory = 1;
354                 b->pos = ctx->sub.data;
355                 b->last = ctx->sub.data + ctx->sub.len;
356 
357             } else {
358                 b->sync = 1;
359             }
360 
361             cl->buf = b;
362             cl->next = NULL;
363             *ctx->last_out = cl;
364             ctx->last_out = &cl->next;
365 
366             ctx->once = slcf->once;
367 
368             continue;
369         }
370 
371         if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) {
372             if (b == NULL) {
373                 if (ctx->free) {
374                     cl = ctx->free;
375                     ctx->free = ctx->free->next;
376                     b = cl->buf;
377                     ngx_memzero(b, sizeof(ngx_buf_t));
378 
379                 } else {
380                     b = ngx_calloc_buf(r->pool);
381                     if (b == NULL) {
382                         return NGX_ERROR;
383                     }
384 
385                     cl = ngx_alloc_chain_link(r->pool);
386                     if (cl == NULL) {
387                         return NGX_ERROR;
388                     }
389 
390                     cl->buf = b;
391                 }
392 
393                 b->sync = 1;
394 
395                 cl->next = NULL;
396                 *ctx->last_out = cl;
397                 ctx->last_out = &cl->next;
398             }
399 
400             b->last_buf = ctx->buf->last_buf;
401             b->shadow = ctx->buf;
402 
403             b->recycled = ctx->buf->recycled;
404         }
405 
406         ctx->buf = NULL;
407 
408         ctx->saved = ctx->looked;
409     }
410 
411     if (ctx->out == NULL && ctx->busy == NULL) {
412         return NGX_OK;
413     }
414 
415     return ngx_http_sub_output(r, ctx);
416 }
417 
418 
419 static ngx_int_t
420 ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
421 {
422     ngx_int_t     rc;
423     ngx_buf_t    *b;
424     ngx_chain_t  *cl;
425 
426 #if 1
427     b = NULL;
428     for (cl = ctx->out; cl; cl = cl->next) {
429         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
430                        "sub out: %p %p", cl->buf, cl->buf->pos);
431         if (cl->buf == b) {
432             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
433                           "the same buf was used in sub");
434             ngx_debug_point();
435             return NGX_ERROR;
436         }
437         b = cl->buf;
438     }
439 #endif
440 
441     rc = ngx_http_next_body_filter(r, ctx->out);
442 
443     if (ctx->busy == NULL) {
444         ctx->busy = ctx->out;
445 
446     } else {
447         for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ }
448         cl->next = ctx->out;
449     }
450 
451     ctx->out = NULL;
452     ctx->last_out = &ctx->out;
453 
454     while (ctx->busy) {
455 
456         cl = ctx->busy;
457         b = cl->buf;
458 
459         if (ngx_buf_size(b) != 0) {
460             break;
461         }
462 
463         if (b->shadow) {
464             b->shadow->pos = b->shadow->last;
465         }
466 
467         ctx->busy = cl->next;
468 
469         if (ngx_buf_in_memory(b) || b->in_file) {
470             /* add data bufs only to the free buf chain */
471 
472             cl->next = ctx->free;
473             ctx->free = cl;
474         }
475     }
476 
477     if (ctx->in || ctx->buf) {
478         r->buffered |= NGX_HTTP_SUB_BUFFERED;
479 
480     } else {
481         r->buffered &= ~NGX_HTTP_SUB_BUFFERED;
482     }
483 
484     return rc;
485 }
486 
487 
488 static ngx_int_t
489 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
490 {
491     u_char                *p, *last, *copy_end, ch, match;
492     size_t                 looked;
493     ngx_http_sub_state_e   state;
494 
495     if (ctx->once) {
496         ctx->copy_start = ctx->pos;
497         ctx->copy_end = ctx->buf->last;
498         ctx->pos = ctx->buf->last;
499         ctx->looked = 0;
500 
501         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");
502 
503         return NGX_AGAIN;
504     }
505 
506     state = ctx->state;
507     looked = ctx->looked;
508     last = ctx->buf->last;
509     copy_end = ctx->copy_end;
510 
511     for (p = ctx->pos; p < last; p++) {
512 
513         ch = *p;
514         ch = ngx_tolower(ch);
515 
516         if (state == sub_start_state) {
517 
518             /* the tight loop */
519 
520             match = ctx->match.data[0];
521 
522             for ( ;; ) {
523                 if (ch == match) {
524                     copy_end = p;
525                     looked = 1;
526                     state = sub_match_state;
527 
528                     goto match_started;
529                 }
530 
531                 if (++p == last) {
532                     break;
533                 }
534 
535                 ch = *p;
536                 ch = ngx_tolower(ch);
537             }
538 
539             ctx->state = state;
540             ctx->pos = p;
541             ctx->looked = looked;
542             ctx->copy_end = p;
543 
544             if (ctx->copy_start == NULL) {
545                 ctx->copy_start = ctx->buf->pos;
546             }
547 
548             return NGX_AGAIN;
549 
550         match_started:
551 
552             continue;
553         }
554 
555         /* state == sub_match_state */
556 
557         if (ch == ctx->match.data[looked]) {
558             looked++;
559 
560             if (looked == ctx->match.len) {
561                 if ((size_t) (p - ctx->pos) < looked) {
562                     ctx->saved = 0;
563                 }
564 
565                 ctx->state = sub_start_state;
566                 ctx->pos = p + 1;
567                 ctx->looked = 0;
568                 ctx->copy_end = copy_end;
569 
570                 if (ctx->copy_start == NULL && copy_end) {
571                     ctx->copy_start = ctx->buf->pos;
572                 }
573 
574                 return NGX_OK;
575             }
576 
577         } else if (ch == ctx->match.data[0]) {
578             copy_end = p;
579             looked = 1;
580 
581         } else {
582             copy_end = p;
583             looked = 0;
584             state = sub_start_state;
585         }
586     }
587 
588     ctx->state = state;
589     ctx->pos = p;
590     ctx->looked = looked;
591 
592     ctx->copy_end = (state == sub_start_state) ? p : copy_end;
593 
594     if (ctx->copy_start == NULL && ctx->copy_end) {
595         ctx->copy_start = ctx->buf->pos;
596     }
597 
598     return NGX_AGAIN;
599 }
600 
601 
602 static char *
603 ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
604 {
605     ngx_http_sub_loc_conf_t *slcf = conf;
606 
607     ngx_str_t                         *value;
608     ngx_http_compile_complex_value_t   ccv;
609 
610     if (slcf->match.len) {
611         return "is duplicate";
612     }
613 
614     value = cf->args->elts;
615 
616     ngx_strlow(value[1].data, value[1].data, value[1].len);
617 
618     slcf->match = value[1];
619 
620     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
621 
622     ccv.cf = cf;
623     ccv.value = &value[2];
624     ccv.complex_value = &slcf->value;
625 
626     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
627         return NGX_CONF_ERROR;
628     }
629 
630     return NGX_CONF_OK;
631 }
632 
633 
634 static void *
635 ngx_http_sub_create_conf(ngx_conf_t *cf)
636 {
637     ngx_http_sub_loc_conf_t  *slcf;
638 
639     slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
640     if (slcf == NULL) {
641         return NULL;
642     }
643 
644     /*
645      * set by ngx_pcalloc():
646      *
647      *     conf->match = { 0, NULL };
648      *     conf->sub = { 0, NULL };
649      *     conf->sub_lengths = NULL;
650      *     conf->sub_values = NULL;
651      *     conf->types = { NULL };
652      *     conf->types_keys = NULL;
653      */
654 
655     slcf->once = NGX_CONF_UNSET;
656 
657     return slcf;
658 }
659 
660 
661 static char *
662 ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
663 {
664     ngx_http_sub_loc_conf_t *prev = parent;
665     ngx_http_sub_loc_conf_t *conf = child;
666 
667     ngx_conf_merge_value(conf->once, prev->once, 1);
668     ngx_conf_merge_str_value(conf->match, prev->match, "");
669 
670     if (conf->value.value.len == 0) {
671         conf->value = prev->value;
672     }
673 
674     if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
675                              prev->types_keys, &prev->types,
676                              ngx_http_html_default_types)
677         != NGX_OK)
678     {
679         return NGX_CONF_ERROR;
680     }
681 
682     return NGX_CONF_OK;
683 }
684 
685 
686 static ngx_int_t
687 ngx_http_sub_filter_init(ngx_conf_t *cf)
688 {
689     ngx_http_next_header_filter = ngx_http_top_header_filter;
690     ngx_http_top_header_filter = ngx_http_sub_header_filter;
691 
692     ngx_http_next_body_filter = ngx_http_top_body_filter;
693     ngx_http_top_body_filter = ngx_http_sub_body_filter;
694 
695     return NGX_OK;
696 }
697 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.