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

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

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  * Copyright (C) Nginx, Inc.
  5  */
  6 
  7 
  8 #include <ngx_config.h>
  9 #include <ngx_core.h>
 10 #include <ngx_http.h>
 11 
 12 #include <libxml/parser.h>
 13 #include <libxml/tree.h>
 14 #include <libxslt/xslt.h>
 15 #include <libxslt/xsltInternals.h>
 16 #include <libxslt/transform.h>
 17 #include <libxslt/variables.h>
 18 #include <libxslt/xsltutils.h>
 19 
 20 #if (NGX_HAVE_EXSLT)
 21 #include <libexslt/exslt.h>
 22 #endif
 23 
 24 
 25 #ifndef NGX_HTTP_XSLT_REUSE_DTD
 26 #define NGX_HTTP_XSLT_REUSE_DTD  1
 27 #endif
 28 
 29 
 30 typedef struct {
 31     u_char                    *name;
 32     void                      *data;
 33 } ngx_http_xslt_file_t;
 34 
 35 
 36 typedef struct {
 37     ngx_array_t                dtd_files;    /* ngx_http_xslt_file_t */
 38     ngx_array_t                sheet_files;  /* ngx_http_xslt_file_t */
 39 } ngx_http_xslt_filter_main_conf_t;
 40 
 41 
 42 typedef struct {
 43     u_char                    *name;
 44     ngx_http_complex_value_t   value;
 45     ngx_uint_t                 quote;        /* unsigned  quote:1; */
 46 } ngx_http_xslt_param_t;
 47 
 48 
 49 typedef struct {
 50     xsltStylesheetPtr          stylesheet;
 51     ngx_array_t                params;       /* ngx_http_xslt_param_t */
 52 } ngx_http_xslt_sheet_t;
 53 
 54 
 55 typedef struct {
 56     xmlDtdPtr                  dtd;
 57     ngx_array_t                sheets;       /* ngx_http_xslt_sheet_t */
 58     ngx_hash_t                 types;
 59     ngx_array_t               *types_keys;
 60     ngx_array_t               *params;       /* ngx_http_xslt_param_t */
 61 } ngx_http_xslt_filter_loc_conf_t;
 62 
 63 
 64 typedef struct {
 65     xmlDocPtr                  doc;
 66     xmlParserCtxtPtr           ctxt;
 67     xsltTransformContextPtr    transform;
 68     ngx_http_request_t        *request;
 69     ngx_array_t                params;
 70 
 71     ngx_uint_t                 done;         /* unsigned  done:1; */
 72 } ngx_http_xslt_filter_ctx_t;
 73 
 74 
 75 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
 76     ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
 77 static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r,
 78     ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
 79 
 80 
 81 static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
 82     const xmlChar *externalId, const xmlChar *systemId);
 83 static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
 84 
 85 
 86 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
 87     ngx_http_xslt_filter_ctx_t *ctx);
 88 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
 89     ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final);
 90 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
 91 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
 92 static void ngx_http_xslt_cleanup(void *data);
 93 
 94 static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
 95     void *conf);
 96 static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
 97     void *conf);
 98 static char *ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd,
 99     void *conf);
100 static void ngx_http_xslt_cleanup_dtd(void *data);
101 static void ngx_http_xslt_cleanup_stylesheet(void *data);
102 static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
103 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
104 static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
105     void *child);
106 static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
107 static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle);
108 
109 
110 ngx_str_t  ngx_http_xslt_default_types[] = {
111     ngx_string("text/xml"),
112     ngx_null_string
113 };
114 
115 
116 static ngx_command_t  ngx_http_xslt_filter_commands[] = {
117 
118     { ngx_string("xml_entities"),
119       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
120       ngx_http_xslt_entities,
121       NGX_HTTP_LOC_CONF_OFFSET,
122       0,
123       NULL },
124 
125     { ngx_string("xslt_stylesheet"),
126       NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
127       ngx_http_xslt_stylesheet,
128       NGX_HTTP_LOC_CONF_OFFSET,
129       0,
130       NULL },
131 
132     { ngx_string("xslt_param"),
133       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
134       ngx_http_xslt_param,
135       NGX_HTTP_LOC_CONF_OFFSET,
136       0,
137       NULL },
138 
139     { ngx_string("xslt_string_param"),
140       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
141       ngx_http_xslt_param,
142       NGX_HTTP_LOC_CONF_OFFSET,
143       0,
144       (void *) 1 },
145 
146     { ngx_string("xslt_types"),
147       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
148       ngx_http_types_slot,
149       NGX_HTTP_LOC_CONF_OFFSET,
150       offsetof(ngx_http_xslt_filter_loc_conf_t, types_keys),
151       &ngx_http_xslt_default_types[0] },
152 
153       ngx_null_command
154 };
155 
156 
157 static ngx_http_module_t  ngx_http_xslt_filter_module_ctx = {
158     NULL,                                  /* preconfiguration */
159     ngx_http_xslt_filter_init,             /* postconfiguration */
160 
161     ngx_http_xslt_filter_create_main_conf, /* create main configuration */
162     NULL,                                  /* init main configuration */
163 
164     NULL,                                  /* create server configuration */
165     NULL,                                  /* merge server configuration */
166 
167     ngx_http_xslt_filter_create_conf,      /* create location configuration */
168     ngx_http_xslt_filter_merge_conf        /* merge location configuration */
169 };
170 
171 
172 ngx_module_t  ngx_http_xslt_filter_module = {
173     NGX_MODULE_V1,
174     &ngx_http_xslt_filter_module_ctx,      /* module context */
175     ngx_http_xslt_filter_commands,         /* module directives */
176     NGX_HTTP_MODULE,                       /* module type */
177     NULL,                                  /* init master */
178     NULL,                                  /* init module */
179     NULL,                                  /* init process */
180     NULL,                                  /* init thread */
181     NULL,                                  /* exit thread */
182     ngx_http_xslt_filter_exit,             /* exit process */
183     ngx_http_xslt_filter_exit,             /* exit master */
184     NGX_MODULE_V1_PADDING
185 };
186 
187 
188 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
189 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
190 
191 
192 static ngx_int_t
193 ngx_http_xslt_header_filter(ngx_http_request_t *r)
194 {
195     ngx_http_xslt_filter_ctx_t       *ctx;
196     ngx_http_xslt_filter_loc_conf_t  *conf;
197 
198     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
199                    "xslt filter header");
200 
201     if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
202         return ngx_http_next_header_filter(r);
203     }
204 
205     conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
206 
207     if (conf->sheets.nelts == 0
208         || ngx_http_test_content_type(r, &conf->types) == NULL)
209     {
210         return ngx_http_next_header_filter(r);
211     }
212 
213     ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
214 
215     if (ctx) {
216         return ngx_http_next_header_filter(r);
217     }
218 
219     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t));
220     if (ctx == NULL) {
221         return NGX_ERROR;
222     }
223 
224     ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
225 
226     r->main_filter_need_in_memory = 1;
227 
228     return NGX_OK;
229 }
230 
231 
232 static ngx_int_t
233 ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
234 {
235     int                          wellFormed;
236     ngx_chain_t                 *cl;
237     ngx_http_xslt_filter_ctx_t  *ctx;
238 
239     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
240                    "xslt filter body");
241 
242     if (in == NULL) {
243         return ngx_http_next_body_filter(r, in);
244     }
245 
246     ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
247 
248     if (ctx == NULL || ctx->done) {
249         return ngx_http_next_body_filter(r, in);
250     }
251 
252     for (cl = in; cl; cl = cl->next) {
253 
254         if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
255 
256             if (ctx->ctxt->myDoc) {
257 
258 #if (NGX_HTTP_XSLT_REUSE_DTD)
259                 ctx->ctxt->myDoc->extSubset = NULL;
260 #endif
261                 xmlFreeDoc(ctx->ctxt->myDoc);
262             }
263 
264             xmlFreeParserCtxt(ctx->ctxt);
265 
266             return ngx_http_xslt_send(r, ctx, NULL);
267         }
268 
269         if (cl->buf->last_buf || cl->buf->last_in_chain) {
270 
271             ctx->doc = ctx->ctxt->myDoc;
272 
273 #if (NGX_HTTP_XSLT_REUSE_DTD)
274             ctx->doc->extSubset = NULL;
275 #endif
276 
277             wellFormed = ctx->ctxt->wellFormed;
278 
279             xmlFreeParserCtxt(ctx->ctxt);
280 
281             if (wellFormed) {
282                 return ngx_http_xslt_send(r, ctx,
283                                        ngx_http_xslt_apply_stylesheet(r, ctx));
284             }
285 
286             xmlFreeDoc(ctx->doc);
287 
288             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
289                           "not well formed XML document");
290 
291             return ngx_http_xslt_send(r, ctx, NULL);
292         }
293     }
294 
295     return NGX_OK;
296 }
297 
298 
299 static ngx_int_t
300 ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
301     ngx_buf_t *b)
302 {
303     ngx_int_t            rc;
304     ngx_chain_t          out;
305     ngx_pool_cleanup_t  *cln;
306 
307     ctx->done = 1;
308 
309     if (b == NULL) {
310         return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module,
311                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
312     }
313 
314     cln = ngx_pool_cleanup_add(r->pool, 0);
315 
316     if (cln == NULL) {
317         ngx_free(b->pos);
318         return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module,
319                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
320     }
321 
322     if (r == r->main) {
323         r->headers_out.content_length_n = b->last - b->pos;
324 
325         if (r->headers_out.content_length) {
326             r->headers_out.content_length->hash = 0;
327             r->headers_out.content_length = NULL;
328         }
329 
330         ngx_http_clear_last_modified(r);
331         ngx_http_clear_etag(r);
332     }
333 
334     rc = ngx_http_next_header_filter(r);
335 
336     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
337         ngx_free(b->pos);
338         return rc;
339     }
340 
341     cln->handler = ngx_http_xslt_cleanup;
342     cln->data = b->pos;
343 
344     out.buf = b;
345     out.next = NULL;
346 
347     return ngx_http_next_body_filter(r, &out);
348 }
349 
350 
351 static ngx_int_t
352 ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
353     ngx_buf_t *b)
354 {
355     int               err;
356     xmlParserCtxtPtr  ctxt;
357 
358     if (ctx->ctxt == NULL) {
359 
360         ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
361         if (ctxt == NULL) {
362             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
363                           "xmlCreatePushParserCtxt() failed");
364             return NGX_ERROR;
365         }
366         xmlCtxtUseOptions(ctxt, XML_PARSE_NOENT|XML_PARSE_DTDLOAD
367                                                |XML_PARSE_NOWARNING);
368 
369         ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
370         ctxt->sax->setDocumentLocator = NULL;
371         ctxt->sax->error = ngx_http_xslt_sax_error;
372         ctxt->sax->fatalError = ngx_http_xslt_sax_error;
373         ctxt->sax->_private = ctx;
374 
375         ctx->ctxt = ctxt;
376         ctx->request = r;
377     }
378 
379     err = xmlParseChunk(ctx->ctxt, (char *) b->pos, (int) (b->last - b->pos),
380                         (b->last_buf) || (b->last_in_chain));
381 
382     if (err == 0) {
383         b->pos = b->last;
384         return NGX_OK;
385     }
386 
387     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
388                   "xmlParseChunk() failed, error:%d", err);
389 
390     return NGX_ERROR;
391 }
392 
393 
394 static void
395 ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
396     const xmlChar *externalId, const xmlChar *systemId)
397 {
398     xmlParserCtxtPtr ctxt = data;
399 
400     xmlDocPtr                         doc;
401     xmlDtdPtr                         dtd;
402     ngx_http_request_t               *r;
403     ngx_http_xslt_filter_ctx_t       *ctx;
404     ngx_http_xslt_filter_loc_conf_t  *conf;
405 
406     ctx = ctxt->sax->_private;
407     r = ctx->request;
408 
409     conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
410 
411     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
412                    "xslt filter extSubset: \"%s\" \"%s\" \"%s\"",
413                    name ? name : (xmlChar *) "",
414                    externalId ? externalId : (xmlChar *) "",
415                    systemId ? systemId : (xmlChar *) "");
416 
417     doc = ctxt->myDoc;
418 
419 #if (NGX_HTTP_XSLT_REUSE_DTD)
420 
421     dtd = conf->dtd;
422 
423 #else
424 
425     dtd = xmlCopyDtd(conf->dtd);
426     if (dtd == NULL) {
427         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
428                       "xmlCopyDtd() failed");
429         return;
430     }
431 
432     if (doc->children == NULL) {
433         xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
434 
435     } else {
436         xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
437     }
438 
439 #endif
440 
441     doc->extSubset = dtd;
442 }
443 
444 
445 static void ngx_cdecl
446 ngx_http_xslt_sax_error(void *data, const char *msg, ...)
447 {
448     xmlParserCtxtPtr ctxt = data;
449 
450     size_t                       n;
451     va_list                      args;
452     ngx_http_xslt_filter_ctx_t  *ctx;
453     u_char                       buf[NGX_MAX_ERROR_STR];
454 
455     ctx = ctxt->sax->_private;
456 
457     buf[0] = '\0';
458 
459     va_start(args, msg);
460     n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args);
461     va_end(args);
462 
463     while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ }
464 
465     ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
466                   "libxml2 error: \"%*s\"", n + 1, buf);
467 }
468 
469 
470 static ngx_buf_t *
471 ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
472     ngx_http_xslt_filter_ctx_t *ctx)
473 {
474     int                               len, rc, doc_type;
475     u_char                           *type, *encoding;
476     ngx_buf_t                        *b;
477     ngx_uint_t                        i;
478     xmlChar                          *buf;
479     xmlDocPtr                         doc, res;
480     ngx_http_xslt_sheet_t            *sheet;
481     ngx_http_xslt_filter_loc_conf_t  *conf;
482 
483     conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
484     sheet = conf->sheets.elts;
485     doc = ctx->doc;
486 
487     /* preallocate array for 4 params */
488 
489     if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *))
490         != NGX_OK)
491     {
492         xmlFreeDoc(doc);
493         return NULL;
494     }
495 
496     for (i = 0; i < conf->sheets.nelts; i++) {
497 
498         ctx->transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
499         if (ctx->transform == NULL) {
500             xmlFreeDoc(doc);
501             return NULL;
502         }
503 
504         if (conf->params
505             && ngx_http_xslt_params(r, ctx, conf->params, 0) != NGX_OK)
506         {
507             xsltFreeTransformContext(ctx->transform);
508             xmlFreeDoc(doc);
509             return NULL;
510         }
511 
512         if (ngx_http_xslt_params(r, ctx, &sheet[i].params, 1) != NGX_OK) {
513             xsltFreeTransformContext(ctx->transform);
514             xmlFreeDoc(doc);
515             return NULL;
516         }
517 
518         res = xsltApplyStylesheetUser(sheet[i].stylesheet, doc,
519                                       ctx->params.elts, NULL, NULL,
520                                       ctx->transform);
521 
522         xsltFreeTransformContext(ctx->transform);
523         xmlFreeDoc(doc);
524 
525         if (res == NULL) {
526             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
527                           "xsltApplyStylesheet() failed");
528             return NULL;
529         }
530 
531         doc = res;
532 
533         /* reset array elements */
534         ctx->params.nelts = 0;
535     }
536 
537     /* there must be at least one stylesheet */
538 
539     if (r == r->main) {
540         type = ngx_http_xslt_content_type(sheet[i - 1].stylesheet);
541 
542     } else {
543         type = NULL;
544     }
545 
546     encoding = ngx_http_xslt_encoding(sheet[i - 1].stylesheet);
547     doc_type = doc->type;
548 
549     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
550                    "xslt filter type: %d t:%s e:%s",
551                    doc_type, type ? type : (u_char *) "(null)",
552                    encoding ? encoding : (u_char *) "(null)");
553 
554     rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet);
555 
556     xmlFreeDoc(doc);
557 
558     if (rc != 0) {
559         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
560                       "xsltSaveResultToString() failed");
561         return NULL;
562     }
563 
564     if (len == 0) {
565         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
566                       "xsltSaveResultToString() returned zero-length result");
567         return NULL;
568     }
569 
570     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
571     if (b == NULL) {
572         ngx_free(buf);
573         return NULL;
574     }
575 
576     b->pos = buf;
577     b->last = buf + len;
578     b->memory = 1;
579 
580     if (encoding) {
581         r->headers_out.charset.len = ngx_strlen(encoding);
582         r->headers_out.charset.data = encoding;
583     }
584 
585     if (r != r->main) {
586         return b;
587     }
588 
589     b->last_buf = 1;
590 
591     if (type) {
592         len = ngx_strlen(type);
593 
594         r->headers_out.content_type_len = len;
595         r->headers_out.content_type.len = len;
596         r->headers_out.content_type.data = type;
597 
598     } else if (doc_type == XML_HTML_DOCUMENT_NODE) {
599 
600         r->headers_out.content_type_len = sizeof("text/html") - 1;
601         ngx_str_set(&r->headers_out.content_type, "text/html");
602     }
603 
604     r->headers_out.content_type_lowcase = NULL;
605 
606     return b;
607 }
608 
609 
610 static ngx_int_t
611 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
612     ngx_array_t *params, ngx_uint_t final)
613 {
614     u_char                 *p, *last, *value, *dst, *src, **s;
615     size_t                  len;
616     ngx_uint_t              i;
617     ngx_str_t               string;
618     ngx_http_xslt_param_t  *param;
619 
620     param = params->elts;
621 
622     for (i = 0; i < params->nelts; i++) {
623 
624         if (ngx_http_complex_value(r, &param[i].value, &string) != NGX_OK) {
625             return NGX_ERROR;
626         }
627 
628         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
629                        "xslt filter param: \"%s\"", string.data);
630 
631         if (param[i].name) {
632 
633             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
634                            "xslt filter param name: \"%s\"", param[i].name);
635 
636             if (param[i].quote) {
637                 if (xsltQuoteOneUserParam(ctx->transform, param[i].name,
638                                           string.data)
639                     != 0)
640                 {
641                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
642                                 "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
643                                 param[i].name, string.data);
644                     return NGX_ERROR;
645                 }
646 
647                 continue;
648             }
649 
650             s = ngx_array_push(&ctx->params);
651             if (s == NULL) {
652                 return NGX_ERROR;
653             }
654 
655             *s = param[i].name;
656 
657             s = ngx_array_push(&ctx->params);
658             if (s == NULL) {
659                 return NGX_ERROR;
660             }
661 
662             *s = string.data;
663 
664             continue;
665         }
666 
667         /*
668          * parse param1=value1:param2=value2 syntax as used by parameters
669          * specified in xslt_stylesheet directives
670          */
671 
672         p = string.data;
673         last = string.data + string.len;
674 
675         while (p && *p) {
676 
677             value = p;
678             p = (u_char *) ngx_strchr(p, '=');
679             if (p == NULL) {
680                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
681                                 "invalid libxslt parameter \"%s\"", value);
682                 return NGX_ERROR;
683             }
684             *p++ = '\0';
685 
686             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
687                            "xslt filter param name: \"%s\"", value);
688 
689             s = ngx_array_push(&ctx->params);
690             if (s == NULL) {
691                 return NGX_ERROR;
692             }
693 
694             *s = value;
695 
696             value = p;
697             p = (u_char *) ngx_strchr(p, ':');
698 
699             if (p) {
700                 len = p - value;
701                 *p++ = '\0';
702 
703             } else {
704                 len = last - value;
705             }
706 
707             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
708                            "xslt filter param value: \"%s\"", value);
709 
710             dst = value;
711             src = value;
712 
713             ngx_unescape_uri(&dst, &src, len, 0);
714 
715             *dst = '\0';
716 
717             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
718                            "xslt filter param unescaped: \"%s\"", value);
719 
720             s = ngx_array_push(&ctx->params);
721             if (s == NULL) {
722                 return NGX_ERROR;
723             }
724 
725             *s = value;
726         }
727     }
728 
729     if (final) {
730         s = ngx_array_push(&ctx->params);
731         if (s == NULL) {
732             return NGX_ERROR;
733         }
734 
735         *s = NULL;
736     }
737 
738     return NGX_OK;
739 }
740 
741 
742 static u_char *
743 ngx_http_xslt_content_type(xsltStylesheetPtr s)
744 {
745     u_char  *type;
746 
747     if (s->mediaType) {
748         return s->mediaType;
749     }
750 
751     for (s = s->imports; s; s = s->next) {
752 
753         type = ngx_http_xslt_content_type(s);
754 
755         if (type) {
756             return type;
757         }
758     }
759 
760     return NULL;
761 }
762 
763 
764 static u_char *
765 ngx_http_xslt_encoding(xsltStylesheetPtr s)
766 {
767     u_char  *encoding;
768 
769     if (s->encoding) {
770         return s->encoding;
771     }
772 
773     for (s = s->imports; s; s = s->next) {
774 
775         encoding = ngx_http_xslt_encoding(s);
776 
777         if (encoding) {
778             return encoding;
779         }
780     }
781 
782     return NULL;
783 }
784 
785 
786 static void
787 ngx_http_xslt_cleanup(void *data)
788 {
789     ngx_free(data);
790 }
791 
792 
793 static char *
794 ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
795 {
796     ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
797 
798     ngx_str_t                         *value;
799     ngx_uint_t                         i;
800     ngx_pool_cleanup_t                *cln;
801     ngx_http_xslt_file_t              *file;
802     ngx_http_xslt_filter_main_conf_t  *xmcf;
803 
804     if (xlcf->dtd) {
805         return "is duplicate";
806     }
807 
808     value = cf->args->elts;
809 
810     xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
811 
812     file = xmcf->dtd_files.elts;
813     for (i = 0; i < xmcf->dtd_files.nelts; i++) {
814         if (ngx_strcmp(file[i].name, value[1].data) == 0) {
815             xlcf->dtd = file[i].data;
816             return NGX_CONF_OK;
817         }
818     }
819 
820     cln = ngx_pool_cleanup_add(cf->pool, 0);
821     if (cln == NULL) {
822         return NGX_CONF_ERROR;
823     }
824 
825     xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data);
826 
827     if (xlcf->dtd == NULL) {
828         ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed");
829         return NGX_CONF_ERROR;
830     }
831 
832     cln->handler = ngx_http_xslt_cleanup_dtd;
833     cln->data = xlcf->dtd;
834 
835     file = ngx_array_push(&xmcf->dtd_files);
836     if (file == NULL) {
837         return NGX_CONF_ERROR;
838     }
839 
840     file->name = value[1].data;
841     file->data = xlcf->dtd;
842 
843     return NGX_CONF_OK;
844 }
845 
846 
847 
848 static char *
849 ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
850 {
851     ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
852 
853     ngx_str_t                         *value;
854     ngx_uint_t                         i, n;
855     ngx_pool_cleanup_t                *cln;
856     ngx_http_xslt_file_t              *file;
857     ngx_http_xslt_sheet_t             *sheet;
858     ngx_http_xslt_param_t             *param;
859     ngx_http_compile_complex_value_t   ccv;
860     ngx_http_xslt_filter_main_conf_t  *xmcf;
861 
862     value = cf->args->elts;
863 
864     if (xlcf->sheets.elts == NULL) {
865         if (ngx_array_init(&xlcf->sheets, cf->pool, 1,
866                            sizeof(ngx_http_xslt_sheet_t))
867             != NGX_OK)
868         {
869             return NGX_CONF_ERROR;
870         }
871     }
872 
873     sheet = ngx_array_push(&xlcf->sheets);
874     if (sheet == NULL) {
875         return NGX_CONF_ERROR;
876     }
877 
878     ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t));
879 
880     if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
881         return NGX_CONF_ERROR;
882     }
883 
884     xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
885 
886     file = xmcf->sheet_files.elts;
887     for (i = 0; i < xmcf->sheet_files.nelts; i++) {
888         if (ngx_strcmp(file[i].name, value[1].data) == 0) {
889             sheet->stylesheet = file[i].data;
890             goto found;
891         }
892     }
893 
894     cln = ngx_pool_cleanup_add(cf->pool, 0);
895     if (cln == NULL) {
896         return NGX_CONF_ERROR;
897     }
898 
899     sheet->stylesheet = xsltParseStylesheetFile(value[1].data);
900     if (sheet->stylesheet == NULL) {
901         ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
902                            "xsltParseStylesheetFile(\"%s\") failed",
903                            value[1].data);
904         return NGX_CONF_ERROR;
905     }
906 
907     cln->handler = ngx_http_xslt_cleanup_stylesheet;
908     cln->data = sheet->stylesheet;
909 
910     file = ngx_array_push(&xmcf->sheet_files);
911     if (file == NULL) {
912         return NGX_CONF_ERROR;
913     }
914 
915     file->name = value[1].data;
916     file->data = sheet->stylesheet;
917 
918 found:
919 
920     n = cf->args->nelts;
921 
922     if (n == 2) {
923         return NGX_CONF_OK;
924     }
925 
926     if (ngx_array_init(&sheet->params, cf->pool, n - 2,
927                        sizeof(ngx_http_xslt_param_t))
928         != NGX_OK)
929     {
930         return NGX_CONF_ERROR;
931     }
932 
933     for (i = 2; i < n; i++) {
934 
935         param = ngx_array_push(&sheet->params);
936         if (param == NULL) {
937             return NGX_CONF_ERROR;
938         }
939 
940         ngx_memzero(param, sizeof(ngx_http_xslt_param_t));
941         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
942 
943         ccv.cf = cf;
944         ccv.value = &value[i];
945         ccv.complex_value = &param->value;
946         ccv.zero = 1;
947 
948         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
949             return NGX_CONF_ERROR;
950         }
951     }
952 
953     return NGX_CONF_OK;
954 }
955 
956 
957 static char *
958 ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
959 {
960     ngx_http_xslt_filter_loc_conf_t  *xlcf = conf;
961 
962     ngx_http_xslt_param_t            *param;
963     ngx_http_compile_complex_value_t  ccv;
964     ngx_str_t                        *value;
965 
966     value = cf->args->elts;
967 
968     if (xlcf->params == NULL) {
969         xlcf->params = ngx_array_create(cf->pool, 2,
970                                         sizeof(ngx_http_xslt_param_t));
971         if (xlcf->params == NULL) {
972             return NGX_CONF_ERROR;
973         }
974     }
975 
976     param = ngx_array_push(xlcf->params);
977     if (param == NULL) {
978         return NGX_CONF_ERROR;
979     }
980 
981     param->name = value[1].data;
982     param->quote = (cmd->post == NULL) ? 0 : 1;
983 
984     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
985 
986     ccv.cf = cf;
987     ccv.value = &value[2];
988     ccv.complex_value = &param->value;
989     ccv.zero = 1;
990 
991     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
992         return NGX_CONF_ERROR;
993     }
994 
995     return NGX_CONF_OK;
996 }
997 
998 
999 static void
1000 ngx_http_xslt_cleanup_dtd(void *data)
1001 {
1002     xmlFreeDtd(data);
1003 }
1004 
1005 
1006 static void
1007 ngx_http_xslt_cleanup_stylesheet(void *data)
1008 {
1009     xsltFreeStylesheet(data);
1010 }
1011 
1012 
1013 static void *
1014 ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf)
1015 {
1016     ngx_http_xslt_filter_main_conf_t  *conf;
1017 
1018     conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t));
1019     if (conf == NULL) {
1020         return NULL;
1021     }
1022 
1023     if (ngx_array_init(&conf->dtd_files, cf->pool, 1,
1024                        sizeof(ngx_http_xslt_file_t))
1025         != NGX_OK)
1026     {
1027         return NULL;
1028     }
1029 
1030     if (ngx_array_init(&conf->sheet_files, cf->pool, 1,
1031                        sizeof(ngx_http_xslt_file_t))
1032         != NGX_OK)
1033     {
1034         return NULL;
1035     }
1036 
1037     return conf;
1038 }
1039 
1040 
1041 static void *
1042 ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
1043 {
1044     ngx_http_xslt_filter_loc_conf_t  *conf;
1045 
1046     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t));
1047     if (conf == NULL) {
1048         return NULL;
1049     }
1050 
1051     /*
1052      * set by ngx_pcalloc():
1053      *
1054      *     conf->dtd = NULL;
1055      *     conf->sheets = { NULL };
1056      *     conf->types = { NULL };
1057      *     conf->types_keys = NULL;
1058      *     conf->params = NULL;
1059      */
1060 
1061     return conf;
1062 }
1063 
1064 
1065 static char *
1066 ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1067 {
1068     ngx_http_xslt_filter_loc_conf_t *prev = parent;
1069     ngx_http_xslt_filter_loc_conf_t *conf = child;
1070 
1071     if (conf->dtd == NULL) {
1072         conf->dtd = prev->dtd;
1073     }
1074 
1075     if (conf->sheets.nelts == 0) {
1076         conf->sheets = prev->sheets;
1077     }
1078 
1079     if (conf->params == NULL) {
1080         conf->params = prev->params;
1081     }
1082 
1083     if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
1084                              &prev->types_keys, &prev->types,
1085                              ngx_http_xslt_default_types)
1086         != NGX_OK)
1087     {
1088         return NGX_CONF_ERROR;
1089     }
1090 
1091     return NGX_CONF_OK;
1092 }
1093 
1094 
1095 static ngx_int_t
1096 ngx_http_xslt_filter_init(ngx_conf_t *cf)
1097 {
1098     xmlInitParser();
1099 
1100 #if (NGX_HAVE_EXSLT)
1101     exsltRegisterAll();
1102 #endif
1103 
1104     ngx_http_next_header_filter = ngx_http_top_header_filter;
1105     ngx_http_top_header_filter = ngx_http_xslt_header_filter;
1106 
1107     ngx_http_next_body_filter = ngx_http_top_body_filter;
1108     ngx_http_top_body_filter = ngx_http_xslt_body_filter;
1109 
1110     return NGX_OK;
1111 }
1112 
1113 
1114 static void
1115 ngx_http_xslt_filter_exit(ngx_cycle_t *cycle)
1116 {
1117     xsltCleanupGlobals();
1118     xmlCleanupParser();
1119 }
1120 

~ [ 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.