3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13 #include <libxslt/xslt.h>
14 #include <libxslt/xsltInternals.h>
15 #include <libxslt/transform.h>
16 #include <libxslt/xsltutils.h>
19 #include <libexslt/exslt.h>
23 #ifndef NGX_HTTP_XSLT_REUSE_DTD
24 #define NGX_HTTP_XSLT_REUSE_DTD 1
31 } ngx_http_xslt_file_t;
35 ngx_array_t dtd_files; /* ngx_http_xslt_file_t */
36 ngx_array_t sheet_files; /* ngx_http_xslt_file_t */
37 } ngx_http_xslt_filter_main_conf_t;
43 } ngx_http_xslt_param_t;
47 xsltStylesheetPtr stylesheet;
48 ngx_array_t params; /* ngx_http_xslt_param_t */
49 } ngx_http_xslt_sheet_t;
54 ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
56 ngx_array_t *types_keys;
57 } ngx_http_xslt_filter_loc_conf_t;
62 xmlParserCtxtPtr ctxt;
64 ngx_http_request_t *request;
67 ngx_uint_t done; /* unsigned done:1; */
68 } ngx_http_xslt_filter_ctx_t;
71 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
72 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
73 static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r);
74 static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r,
75 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
78 static void ngx_http_xslt_sax_start_document(void *data);
79 static void ngx_http_xslt_sax_end_document(void *data);
80 static void ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
81 const xmlChar *externalId, const xmlChar *systemId);
82 static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
83 const xmlChar *externalId, const xmlChar *systemId);
84 static void ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name,
85 int type, const xmlChar *publicId, const xmlChar *systemId,
87 static void ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
88 const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
89 xmlEnumerationPtr tree);
90 static void ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name,
91 int type, xmlElementContentPtr content);
92 static void ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
93 const xmlChar *publicId, const xmlChar *systemId);
94 static void ngx_http_xslt_sax_unparsed_entity_decl(void *data,
95 const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId,
96 const xmlChar *notationName);
97 static void ngx_http_xslt_sax_start_element(void *data,
98 const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
99 int nb_namespaces, const xmlChar **namespaces, int nb_attributes,
100 int nb_defaulted, const xmlChar **attributes);
101 static void ngx_http_xslt_sax_end_element(void *data,
102 const xmlChar * localname ATTRIBUTE_UNUSED,
103 const xmlChar * prefix ATTRIBUTE_UNUSED,
104 const xmlChar * URI ATTRIBUTE_UNUSED);
105 static void ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len);
106 static void ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p,
108 static xmlEntityPtr ngx_http_xslt_sax_get_entity(void *data,
109 const xmlChar *name);
110 static xmlEntityPtr ngx_http_xslt_sax_get_parameter_entity(void *data,
111 const xmlChar *name);
112 static xmlParserInputPtr ngx_http_xslt_sax_resolve_entity(void *data,
113 const xmlChar *publicId, const xmlChar *systemId);
114 static void ngx_http_xslt_sax_reference(void *data, const xmlChar *name);
115 static void ngx_http_xslt_sax_comment(void *data, const xmlChar *value);
116 static void ngx_http_xslt_sax_processing_instruction(void *data,
117 const xmlChar *target, const xmlChar *pidata);
118 static int ngx_http_xslt_sax_is_standalone(void *data);
119 static int ngx_http_xslt_sax_has_internal_subset(void *data);
120 static int ngx_http_xslt_sax_has_external_subset(void *data);
121 static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
124 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
125 ngx_http_xslt_filter_ctx_t *ctx);
126 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
127 ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params);
128 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
129 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
130 static void ngx_http_xslt_cleanup(void *data);
132 static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
134 static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
136 static void ngx_http_xslt_cleanup_dtd(void *data);
137 static void ngx_http_xslt_cleanup_stylesheet(void *data);
138 static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
139 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
140 static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
142 static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
143 static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle);
146 ngx_str_t ngx_http_xslt_default_types[] = {
147 ngx_string("text/xml"),
152 static ngx_command_t ngx_http_xslt_filter_commands[] = {
154 { ngx_string("xml_entities"),
155 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
156 ngx_http_xslt_entities,
157 NGX_HTTP_LOC_CONF_OFFSET,
161 { ngx_string("xslt_stylesheet"),
162 NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
163 ngx_http_xslt_stylesheet,
164 NGX_HTTP_LOC_CONF_OFFSET,
168 { ngx_string("xslt_types"),
169 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
171 NGX_HTTP_LOC_CONF_OFFSET,
172 offsetof(ngx_http_xslt_filter_loc_conf_t, types_keys),
173 &ngx_http_xslt_default_types[0] },
179 static ngx_http_module_t ngx_http_xslt_filter_module_ctx = {
180 NULL, /* preconfiguration */
181 ngx_http_xslt_filter_init, /* postconfiguration */
183 ngx_http_xslt_filter_create_main_conf, /* create main configuration */
184 NULL, /* init main configuration */
186 NULL, /* create server configuration */
187 NULL, /* merge server configuration */
189 ngx_http_xslt_filter_create_conf, /* create location configuration */
190 ngx_http_xslt_filter_merge_conf /* merge location configuration */
194 ngx_module_t ngx_http_xslt_filter_module = {
196 &ngx_http_xslt_filter_module_ctx, /* module context */
197 ngx_http_xslt_filter_commands, /* module directives */
198 NGX_HTTP_MODULE, /* module type */
199 NULL, /* init master */
200 NULL, /* init module */
201 NULL, /* init process */
202 NULL, /* init thread */
203 NULL, /* exit thread */
204 ngx_http_xslt_filter_exit, /* exit process */
205 ngx_http_xslt_filter_exit, /* exit master */
206 NGX_MODULE_V1_PADDING
210 static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
211 static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
215 ngx_http_xslt_header_filter(ngx_http_request_t *r)
217 ngx_http_xslt_filter_ctx_t *ctx;
218 ngx_http_xslt_filter_loc_conf_t *conf;
220 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
221 "xslt filter header");
223 if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
224 return ngx_http_next_header_filter(r);
227 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
229 if (conf->sheets.nelts == 0
230 || ngx_http_test_content_type(r, &conf->types) == NULL)
232 return ngx_http_next_header_filter(r);
235 ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
238 return ngx_http_next_header_filter(r);
241 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t));
246 ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
248 r->main_filter_need_in_memory = 1;
255 ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
258 ngx_http_xslt_filter_ctx_t *ctx;
260 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
264 return ngx_http_next_body_filter(r, in);
267 ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
269 if (ctx == NULL || ctx->done) {
270 return ngx_http_next_body_filter(r, in);
273 for (cl = in; cl; cl = cl->next) {
275 if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
277 if (ctx->ctxt->myDoc){
279 #if (NGX_HTTP_XSLT_REUSE_DTD)
280 ctx->ctxt->myDoc->extSubset = NULL;
282 xmlFreeDoc(ctx->ctxt->myDoc);
285 xmlFreeParserCtxt(ctx->ctxt);
287 return ngx_http_xslt_send(r, ctx, NULL);
290 if (cl->buf->last_buf) {
292 ctx->doc = ctx->ctxt->myDoc;
294 #if (NGX_HTTP_XSLT_REUSE_DTD)
295 ctx->doc->extSubset = NULL;
298 xmlFreeParserCtxt(ctx->ctxt);
300 if (ctx->ctxt->wellFormed) {
301 return ngx_http_xslt_send(r, ctx,
302 ngx_http_xslt_apply_stylesheet(r, ctx));
305 xmlFreeDoc(ctx->doc);
307 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
308 "not well formed XML document");
310 return ngx_http_xslt_send(r, ctx, NULL);
319 ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
324 ngx_pool_cleanup_t *cln;
329 return ngx_http_xslt_filter_internal_error(r);
332 cln = ngx_pool_cleanup_add(r->pool, 0);
336 return ngx_http_special_response_handler(r,
337 NGX_HTTP_INTERNAL_SERVER_ERROR);
341 r->headers_out.content_length_n = b->last - b->pos;
343 if (r->headers_out.content_length) {
344 r->headers_out.content_length->hash = 0;
345 r->headers_out.content_length = NULL;
348 ngx_http_clear_last_modified(r);
351 rc = ngx_http_next_header_filter(r);
353 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
358 cln->handler = ngx_http_xslt_cleanup;
364 return ngx_http_next_body_filter(r, &out);
369 ngx_http_xslt_filter_internal_error(ngx_http_request_t *r)
373 /* clear the modules contexts */
374 ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
376 rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
378 /* NGX_ERROR resets any pending data */
380 return (rc == NGX_OK) ? NGX_ERROR : rc;
385 ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
390 xmlParserCtxtPtr ctxt;
392 if (ctx->ctxt == NULL) {
394 ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
396 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
397 "xmlCreatePushParserCtxt() failed");
401 ctx->sax = ngx_palloc(r->pool, sizeof(xmlSAXHandler));
402 if (ctx->sax == NULL) {
408 ngx_memcpy(ctx->sax, sax, sizeof(xmlSAXHandler));
410 sax->startDocument = ngx_http_xslt_sax_start_document;
411 sax->endDocument = ngx_http_xslt_sax_end_document;
413 sax->internalSubset = ngx_http_xslt_sax_internal_subset;
414 sax->externalSubset = ngx_http_xslt_sax_external_subset;
415 sax->entityDecl = ngx_http_xslt_sax_entity_decl;
416 sax->attributeDecl = ngx_http_xslt_sax_attribute_decl;
417 sax->elementDecl = ngx_http_xslt_sax_element_decl;
418 sax->notationDecl = ngx_http_xslt_sax_notation_decl;
419 sax->unparsedEntityDecl = ngx_http_xslt_sax_unparsed_entity_decl;
420 sax->setDocumentLocator = NULL;
422 sax->startElementNs = ngx_http_xslt_sax_start_element;
423 sax->endElementNs = ngx_http_xslt_sax_end_element;
425 sax->characters = ngx_http_xslt_sax_characters;
426 sax->ignorableWhitespace = ngx_http_xslt_sax_characters;
427 sax->cdataBlock = ngx_http_xslt_sax_cdata_block;
428 sax->getEntity = ngx_http_xslt_sax_get_entity;
429 sax->resolveEntity = ngx_http_xslt_sax_resolve_entity;
430 sax->getParameterEntity = ngx_http_xslt_sax_get_parameter_entity;
431 sax->reference = ngx_http_xslt_sax_reference;
432 sax->comment = ngx_http_xslt_sax_comment;
433 sax->processingInstruction = ngx_http_xslt_sax_processing_instruction;
435 sax->isStandalone = ngx_http_xslt_sax_is_standalone;
436 sax->hasInternalSubset = ngx_http_xslt_sax_has_internal_subset;
437 sax->hasExternalSubset = ngx_http_xslt_sax_has_external_subset;
440 sax->error = ngx_http_xslt_sax_error;
441 sax->fatalError = ngx_http_xslt_sax_error;
443 ctxt->userData = ctx;
445 ctxt->replaceEntities = 1;
446 ctxt->loadsubset = 1;
452 err = xmlParseChunk(ctx->ctxt, (char *) b->pos,
453 (int) (b->last - b->pos), b->last_buf);
460 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
461 "xmlParseChunk() failed, error:%d", err);
468 ngx_http_xslt_sax_start_document(void *data)
470 ngx_http_xslt_filter_ctx_t *ctx = data;
472 ctx->sax->startDocument(ctx->ctxt);
477 ngx_http_xslt_sax_end_document(void *data)
479 ngx_http_xslt_filter_ctx_t *ctx = data;
481 ctx->sax->endDocument(ctx->ctxt);
486 ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
487 const xmlChar *externalId, const xmlChar *systemId)
489 ngx_http_xslt_filter_ctx_t *ctx = data;
491 ctx->sax->internalSubset(ctx->ctxt, name, externalId, systemId);
496 ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
497 const xmlChar *externalId, const xmlChar *systemId)
499 ngx_http_xslt_filter_ctx_t *ctx = data;
503 ngx_http_request_t *r;
504 ngx_http_xslt_filter_loc_conf_t *conf;
508 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
510 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
511 "xslt filter extSubset: \"%s\" \"%s\" \"%s\"",
512 name ? name : (xmlChar *) "",
513 externalId ? externalId : (xmlChar *) "",
514 systemId ? systemId : (xmlChar *) "");
516 doc = ctx->ctxt->myDoc;
518 #if (NGX_HTTP_XSLT_REUSE_DTD)
524 dtd = xmlCopyDtd(conf->dtd);
526 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
527 "xmlCopyDtd() failed");
531 if (doc->children == NULL) {
532 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
535 xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
540 doc->extSubset = dtd;
545 ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, int type,
546 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
548 ngx_http_xslt_filter_ctx_t *ctx = data;
550 ctx->sax->entityDecl(ctx->ctxt, name, type, publicId, systemId, content);
555 ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
556 const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
557 xmlEnumerationPtr tree)
559 ngx_http_xslt_filter_ctx_t *ctx = data;
561 ctx->sax->attributeDecl(ctx->ctxt, elem, fullname, type, def, defaultValue,
567 ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, int type,
568 xmlElementContentPtr content)
570 ngx_http_xslt_filter_ctx_t *ctx = data;
572 ctx->sax->elementDecl(ctx->ctxt, name, type, content);
577 ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
578 const xmlChar *publicId, const xmlChar *systemId)
580 ngx_http_xslt_filter_ctx_t *ctx = data;
582 ctx->sax->notationDecl(ctx->ctxt, name, publicId, systemId);
587 ngx_http_xslt_sax_unparsed_entity_decl(void *data, const xmlChar *name,
588 const xmlChar *publicId, const xmlChar *systemId,
589 const xmlChar *notationName)
591 ngx_http_xslt_filter_ctx_t *ctx = data;
593 ctx->sax->unparsedEntityDecl(ctx->ctxt, name, publicId, systemId,
599 ngx_http_xslt_sax_start_element(void *data, const xmlChar *localname,
600 const xmlChar *prefix, const xmlChar *URI, int nb_namespaces,
601 const xmlChar **namespaces, int nb_attributes, int nb_defaulted,
602 const xmlChar **attributes)
604 ngx_http_xslt_filter_ctx_t *ctx = data;
606 ctx->sax->startElementNs(ctx->ctxt, localname, prefix, URI, nb_namespaces,
607 namespaces, nb_attributes, nb_defaulted, attributes);
612 ngx_http_xslt_sax_end_element(void *data,
613 const xmlChar * localname ATTRIBUTE_UNUSED,
614 const xmlChar * prefix ATTRIBUTE_UNUSED,
615 const xmlChar * URI ATTRIBUTE_UNUSED)
617 ngx_http_xslt_filter_ctx_t *ctx = data;
619 ctx->sax->endElementNs(ctx->ctxt, localname, prefix, URI);
624 ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len)
626 ngx_http_xslt_filter_ctx_t *ctx = data;
628 ctx->sax->characters(ctx->ctxt, p, len);
633 ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, int len)
635 ngx_http_xslt_filter_ctx_t *ctx = data;
637 ctx->sax->cdataBlock(ctx->ctxt, p, len);
642 ngx_http_xslt_sax_get_entity(void *data, const xmlChar *name)
644 ngx_http_xslt_filter_ctx_t *ctx = data;
646 return ctx->sax->getEntity(ctx->ctxt, name);
651 ngx_http_xslt_sax_get_parameter_entity(void *data, const xmlChar *name)
653 ngx_http_xslt_filter_ctx_t *ctx = data;
655 return ctx->sax->getParameterEntity(ctx->ctxt, name);
659 static xmlParserInputPtr
660 ngx_http_xslt_sax_resolve_entity(void *data, const xmlChar *publicId,
661 const xmlChar *systemId)
663 ngx_http_xslt_filter_ctx_t *ctx = data;
665 return ctx->sax->resolveEntity(ctx->ctxt, publicId, systemId);
670 ngx_http_xslt_sax_reference(void *data, const xmlChar *name)
672 ngx_http_xslt_filter_ctx_t *ctx = data;
674 ctx->sax->reference(ctx->ctxt, name);
679 ngx_http_xslt_sax_comment(void *data, const xmlChar *value)
681 ngx_http_xslt_filter_ctx_t *ctx = data;
683 ctx->sax->comment(ctx->ctxt, value);
688 ngx_http_xslt_sax_processing_instruction(void *data, const xmlChar *target,
689 const xmlChar *pidata)
691 ngx_http_xslt_filter_ctx_t *ctx = data;
693 ctx->sax->processingInstruction(ctx->ctxt, target, pidata);
698 ngx_http_xslt_sax_is_standalone(void *data)
700 ngx_http_xslt_filter_ctx_t *ctx = data;
702 return ctx->sax->isStandalone(ctx->ctxt);
707 ngx_http_xslt_sax_has_internal_subset(void *data)
709 ngx_http_xslt_filter_ctx_t *ctx = data;
711 return ctx->sax->hasInternalSubset(ctx->ctxt);
716 ngx_http_xslt_sax_has_external_subset(void *data)
718 ngx_http_xslt_filter_ctx_t *ctx = data;
720 return ctx->sax->hasExternalSubset(ctx->ctxt);
724 static void ngx_cdecl
725 ngx_http_xslt_sax_error(void *data, const char *msg, ...)
727 ngx_http_xslt_filter_ctx_t *ctx = data;
731 u_char buf[NGX_MAX_ERROR_STR];
736 n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args);
739 while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ }
741 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
742 "libxml2 error: \"%*s\"", n, buf);
747 ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
748 ngx_http_xslt_filter_ctx_t *ctx)
750 int len, rc, doc_type;
751 u_char *type, *encoding;
756 ngx_http_xslt_sheet_t *sheet;
757 ngx_http_xslt_filter_loc_conf_t *conf;
759 conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
760 sheet = conf->sheets.elts;
763 /* preallocate array for 4 params */
765 if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *))
772 for (i = 0; i < conf->sheets.nelts; i++) {
774 if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) {
779 res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts);
784 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
785 "xsltApplyStylesheet() failed");
791 /* reset array elements */
792 ctx->params.nelts = 0;
795 /* there must be at least one stylesheet */
798 type = ngx_http_xslt_content_type(sheet[i - 1].stylesheet);
804 encoding = ngx_http_xslt_encoding(sheet[i - 1].stylesheet);
805 doc_type = doc->type;
807 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
808 "xslt filter type: %d t:%s e:%s",
809 doc_type, type ? type : (u_char *) "(null)",
810 encoding ? encoding : (u_char *) "(null)");
812 rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet);
817 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
818 "xsltSaveResultToString() failed");
823 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
824 "xsltSaveResultToString() returned zero-length result");
828 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
840 r->headers_out.charset.len = ngx_strlen(encoding);
841 r->headers_out.charset.data = encoding;
849 len = ngx_strlen(type);
851 r->headers_out.content_type_len = len;
852 r->headers_out.content_type.len = len;
853 r->headers_out.content_type.data = type;
855 } else if (doc_type == XML_HTML_DOCUMENT_NODE) {
857 r->headers_out.content_type_len = sizeof("text/html") - 1;
858 r->headers_out.content_type.len = sizeof("text/html") - 1;
859 r->headers_out.content_type.data = (u_char *) "text/html";
867 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
870 u_char *p, *last, *value, *dst, *src, **s;
874 ngx_http_xslt_param_t *param;
876 param = params->elts;
878 for (i = 0; i < params->nelts; i++) {
880 if (ngx_http_script_run(r, &string, param[i].lengths->elts, 1,
881 param[i].values->elts)
887 last = string.data + string.len - 1;
890 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
891 "xslt filter param: \"%s\"", string.data);
898 p = (u_char *) ngx_strchr(p, '=');
900 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
901 "invalid libxslt parameter \"%s\"", value);
906 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
907 "xslt filter param name: \"%s\"", value);
909 s = ngx_array_push(&ctx->params);
917 p = (u_char *) ngx_strchr(p, ':');
927 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
928 "xslt filter param value: \"%s\"", value);
933 ngx_unescape_uri(&dst, &src, len, 0);
937 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
938 "xslt filter param unescaped: \"%s\"", value);
940 s = ngx_array_push(&ctx->params);
949 s = ngx_array_push(&ctx->params);
961 ngx_http_xslt_content_type(xsltStylesheetPtr s)
969 for (s = s->imports; s; s = s->next) {
971 type = ngx_http_xslt_content_type(s);
983 ngx_http_xslt_encoding(xsltStylesheetPtr s)
991 for (s = s->imports; s; s = s->next) {
993 encoding = ngx_http_xslt_encoding(s);
1005 ngx_http_xslt_cleanup(void *data)
1012 ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1014 ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
1018 ngx_pool_cleanup_t *cln;
1019 ngx_http_xslt_file_t *file;
1020 ngx_http_xslt_filter_main_conf_t *xmcf;
1023 return "is duplicate";
1026 value = cf->args->elts;
1028 xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
1030 file = xmcf->dtd_files.elts;
1031 for (i = 0; i < xmcf->dtd_files.nelts; i++) {
1032 if (ngx_strcmp(file[i].name, &value[1].data) == 0) {
1033 xlcf->dtd = file[i].data;
1038 cln = ngx_pool_cleanup_add(cf->pool, 0);
1040 return NGX_CONF_ERROR;
1043 xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data);
1045 if (xlcf->dtd == NULL) {
1046 ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed");
1047 return NGX_CONF_ERROR;
1050 cln->handler = ngx_http_xslt_cleanup_dtd;
1051 cln->data = xlcf->dtd;
1053 file = ngx_array_push(&xmcf->dtd_files);
1055 return NGX_CONF_ERROR;
1058 file->name = value[1].data;
1059 file->data = xlcf->dtd;
1067 ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1069 ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
1073 ngx_pool_cleanup_t *cln;
1074 ngx_http_xslt_file_t *file;
1075 ngx_http_xslt_sheet_t *sheet;
1076 ngx_http_xslt_param_t *param;
1077 ngx_http_script_compile_t sc;
1078 ngx_http_xslt_filter_main_conf_t *xmcf;
1080 value = cf->args->elts;
1082 if (xlcf->sheets.elts == NULL) {
1083 if (ngx_array_init(&xlcf->sheets, cf->pool, 1,
1084 sizeof(ngx_http_xslt_sheet_t))
1087 return NGX_CONF_ERROR;
1091 sheet = ngx_array_push(&xlcf->sheets);
1092 if (sheet == NULL) {
1093 return NGX_CONF_ERROR;
1096 ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t));
1098 if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
1099 return NGX_CONF_ERROR;
1102 xmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_xslt_filter_module);
1104 file = xmcf->sheet_files.elts;
1105 for (i = 0; i < xmcf->sheet_files.nelts; i++) {
1106 if (ngx_strcmp(file[i].name, &value[1].data) == 0) {
1107 sheet->stylesheet = file[i].data;
1112 cln = ngx_pool_cleanup_add(cf->pool, 0);
1114 return NGX_CONF_ERROR;
1117 sheet->stylesheet = xsltParseStylesheetFile(value[1].data);
1118 if (sheet->stylesheet == NULL) {
1119 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
1120 "xsltParseStylesheetFile(\"%s\") failed",
1122 return NGX_CONF_ERROR;
1125 cln->handler = ngx_http_xslt_cleanup_stylesheet;
1126 cln->data = sheet->stylesheet;
1128 file = ngx_array_push(&xmcf->sheet_files);
1130 return NGX_CONF_ERROR;
1133 file->name = value[1].data;
1134 file->data = sheet->stylesheet;
1138 n = cf->args->nelts;
1144 if (ngx_array_init(&sheet->params, cf->pool, n - 2,
1145 sizeof(ngx_http_xslt_param_t))
1148 return NGX_CONF_ERROR;
1151 for (i = 2; i < n; i++) {
1153 param = ngx_array_push(&sheet->params);
1154 if (param == NULL) {
1155 return NGX_CONF_ERROR;
1158 param->lengths = NULL;
1159 param->values = NULL;
1161 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1164 sc.source = &value[i];
1165 sc.lengths = ¶m->lengths;
1166 sc.values = ¶m->values;
1167 sc.variables = ngx_http_script_variables_count(&value[i]);
1168 sc.complete_lengths = 1;
1169 sc.complete_values = 1;
1171 if (ngx_http_script_compile(&sc) != NGX_OK) {
1172 return NGX_CONF_ERROR;
1181 ngx_http_xslt_cleanup_dtd(void *data)
1188 ngx_http_xslt_cleanup_stylesheet(void *data)
1190 xsltFreeStylesheet(data);
1195 ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf)
1197 ngx_http_xslt_filter_main_conf_t *conf;
1199 conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t));
1201 return NGX_CONF_ERROR;
1204 if (ngx_array_init(&conf->dtd_files, cf->pool, 1,
1205 sizeof(ngx_http_xslt_file_t))
1211 if (ngx_array_init(&conf->sheet_files, cf->pool, 1,
1212 sizeof(ngx_http_xslt_file_t))
1223 ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
1225 ngx_http_xslt_filter_loc_conf_t *conf;
1227 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t));
1229 return NGX_CONF_ERROR;
1233 * set by ngx_pcalloc():
1236 * conf->sheets = { NULL };
1237 * conf->types = { NULL };
1238 * conf->types_keys = NULL;
1246 ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1248 ngx_http_xslt_filter_loc_conf_t *prev = parent;
1249 ngx_http_xslt_filter_loc_conf_t *conf = child;
1251 if (conf->dtd == NULL) {
1252 conf->dtd = prev->dtd;
1255 if (conf->sheets.nelts == 0) {
1256 conf->sheets = prev->sheets;
1259 if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
1260 prev->types_keys, &prev->types,
1261 ngx_http_xslt_default_types)
1264 return NGX_CONF_ERROR;
1272 ngx_http_xslt_filter_init(ngx_conf_t *cf)
1276 #if (NGX_HAVE_EXSLT)
1280 ngx_http_next_header_filter = ngx_http_top_header_filter;
1281 ngx_http_top_header_filter = ngx_http_xslt_header_filter;
1283 ngx_http_next_body_filter = ngx_http_top_body_filter;
1284 ngx_http_top_body_filter = ngx_http_xslt_body_filter;
1291 ngx_http_xslt_filter_exit(ngx_cycle_t *cycle)
1293 xsltCleanupGlobals();