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 #ifndef NGX_HTTP_XSLT_REUSE_DTD
20 #define NGX_HTTP_XSLT_REUSE_DTD 1
27 } ngx_http_xslt_param_t
;
31 xsltStylesheetPtr stylesheet
;
32 ngx_array_t params
; /* ngx_http_xslt_param_t */
33 } ngx_http_xslt_sheet_t
;
38 ngx_array_t sheets
; /* ngx_http_xslt_sheet_t */
39 ngx_hash_t types_hash
;
41 } ngx_http_xslt_filter_conf_t
;
46 xmlParserCtxtPtr ctxt
;
48 ngx_http_request_t
*request
;
52 } ngx_http_xslt_filter_ctx_t
;
55 static ngx_int_t
ngx_http_xslt_send(ngx_http_request_t
*r
,
56 ngx_http_xslt_filter_ctx_t
*ctx
, ngx_buf_t
*b
);
57 static ngx_int_t
ngx_http_xslt_filter_internal_error(ngx_http_request_t
*r
);
58 static ngx_int_t
ngx_http_xslt_add_chunk(ngx_http_request_t
*r
,
59 ngx_http_xslt_filter_ctx_t
*ctx
, ngx_buf_t
*b
);
62 static void ngx_http_xslt_sax_start_document(void *data
);
63 static void ngx_http_xslt_sax_end_document(void *data
);
64 static void ngx_http_xslt_sax_internal_subset(void *data
, const xmlChar
*name
,
65 const xmlChar
*externalId
, const xmlChar
*systemId
);
66 static void ngx_http_xslt_sax_external_subset(void *data
, const xmlChar
*name
,
67 const xmlChar
*externalId
, const xmlChar
*systemId
);
68 static void ngx_http_xslt_sax_entity_decl(void *data
, const xmlChar
*name
,
69 int type
, const xmlChar
*publicId
, const xmlChar
*systemId
,
71 static void ngx_http_xslt_sax_attribute_decl(void *data
, const xmlChar
*elem
,
72 const xmlChar
*fullname
, int type
, int def
, const xmlChar
*defaultValue
,
73 xmlEnumerationPtr tree
);
74 static void ngx_http_xslt_sax_element_decl(void *data
, const xmlChar
* name
,
75 int type
, xmlElementContentPtr content
);
76 static void ngx_http_xslt_sax_notation_decl(void *data
, const xmlChar
*name
,
77 const xmlChar
*publicId
, const xmlChar
*systemId
);
78 static void ngx_http_xslt_sax_unparsed_entity_decl(void *data
,
79 const xmlChar
*name
, const xmlChar
*publicId
, const xmlChar
*systemId
,
80 const xmlChar
*notationName
);
81 static void ngx_http_xslt_sax_start_element(void *data
,
82 const xmlChar
*localname
, const xmlChar
*prefix
, const xmlChar
*URI
,
83 int nb_namespaces
, const xmlChar
**namespaces
, int nb_attributes
,
84 int nb_defaulted
, const xmlChar
**attributes
);
85 static void ngx_http_xslt_sax_end_element(void *data
,
86 const xmlChar
* localname ATTRIBUTE_UNUSED
,
87 const xmlChar
* prefix ATTRIBUTE_UNUSED
,
88 const xmlChar
* URI ATTRIBUTE_UNUSED
);
89 static void ngx_http_xslt_sax_characters(void *data
, const xmlChar
*p
, int len
);
90 static void ngx_http_xslt_sax_cdata_block(void *data
, const xmlChar
*p
,
92 static xmlEntityPtr
ngx_http_xslt_sax_get_entity(void *data
,
94 static xmlEntityPtr
ngx_http_xslt_sax_get_parameter_entity(void *data
,
96 static xmlParserInputPtr
ngx_http_xslt_sax_resolve_entity(void *data
,
97 const xmlChar
*publicId
, const xmlChar
*systemId
);
98 static void ngx_http_xslt_sax_reference(void *data
, const xmlChar
*name
);
99 static void ngx_http_xslt_sax_comment(void *data
, const xmlChar
*value
);
100 static void ngx_http_xslt_sax_processing_instruction(void *data
,
101 const xmlChar
*target
, const xmlChar
*pidata
);
102 static int ngx_http_xslt_sax_is_standalone(void *data
);
103 static int ngx_http_xslt_sax_has_internal_subset(void *data
);
104 static int ngx_http_xslt_sax_has_external_subset(void *data
);
105 static void ngx_cdecl
ngx_http_xslt_sax_error(void *data
, const char *msg
, ...);
108 static ngx_buf_t
*ngx_http_xslt_apply_stylesheet(ngx_http_request_t
*r
,
109 ngx_http_xslt_filter_ctx_t
*ctx
);
110 static ngx_int_t
ngx_http_xslt_params(ngx_http_request_t
*r
,
111 ngx_http_xslt_filter_ctx_t
*ctx
, ngx_array_t
*params
);
112 static void ngx_http_xslt_cleanup(void *data
);
114 static char *ngx_http_xslt_entities(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
116 static char *ngx_http_xslt_stylesheet(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
118 static void ngx_http_xslt_cleanup_stylesheet(void *data
);
119 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t
*cf
);
120 static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t
*cf
, void *parent
,
122 static ngx_int_t
ngx_http_xslt_filter_init(ngx_conf_t
*cf
);
125 ngx_str_t ngx_http_xslt_default_types
[] = {
126 ngx_string("text/xml"),
131 static ngx_command_t ngx_http_xslt_filter_commands
[] = {
133 { ngx_string("xml_entities"),
134 NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1
,
135 ngx_http_xslt_entities
,
136 NGX_HTTP_LOC_CONF_OFFSET
,
140 { ngx_string("xslt_stylesheet"),
141 NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF
|NGX_CONF_1MORE
,
142 ngx_http_xslt_stylesheet
,
143 NGX_HTTP_LOC_CONF_OFFSET
,
147 { ngx_string("xslt_types"),
148 NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF
|NGX_CONF_1MORE
,
150 NGX_HTTP_LOC_CONF_OFFSET
,
151 offsetof(ngx_http_xslt_filter_conf_t
, keys
),
152 &ngx_http_xslt_default_types
[0] },
158 static ngx_http_module_t ngx_http_xslt_filter_module_ctx
= {
159 NULL
, /* preconfiguration */
160 ngx_http_xslt_filter_init
, /* postconfiguration */
162 NULL
, /* create main configuration */
163 NULL
, /* init main configuration */
165 NULL
, /* create server configuration */
166 NULL
, /* merge server configuration */
168 ngx_http_xslt_filter_create_conf
, /* create location configuration */
169 ngx_http_xslt_filter_merge_conf
/* merge location configuration */
173 ngx_module_t ngx_http_xslt_filter_module
= {
175 &ngx_http_xslt_filter_module_ctx
, /* module context */
176 ngx_http_xslt_filter_commands
, /* module directives */
177 NGX_HTTP_MODULE
, /* module type */
178 NULL
, /* init master */
179 NULL
, /* init module */
180 NULL
, /* init process */
181 NULL
, /* init thread */
182 NULL
, /* exit thread */
183 NULL
, /* exit process */
184 NULL
, /* exit master */
185 NGX_MODULE_V1_PADDING
189 static ngx_http_output_header_filter_pt ngx_http_next_header_filter
;
190 static ngx_http_output_body_filter_pt ngx_http_next_body_filter
;
194 ngx_http_xslt_header_filter(ngx_http_request_t
*r
)
196 ngx_http_xslt_filter_ctx_t
*ctx
;
197 ngx_http_xslt_filter_conf_t
*conf
;
199 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
200 "xslt filter header");
202 if (r
->headers_out
.status
== NGX_HTTP_NOT_MODIFIED
) {
203 return ngx_http_next_header_filter(r
);
206 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
208 if (conf
->sheets
.nelts
== 0
209 || ngx_http_test_content_type(r
, &conf
->types_hash
) == NULL
)
211 return ngx_http_next_header_filter(r
);
214 ctx
= ngx_http_get_module_ctx(r
, ngx_http_xslt_filter_module
);
217 return ngx_http_next_header_filter(r
);
220 ctx
= ngx_pcalloc(r
->pool
, sizeof(ngx_http_xslt_filter_ctx_t
));
225 ngx_http_set_ctx(r
, ctx
, ngx_http_xslt_filter_module
);
227 r
->main_filter_need_in_memory
= 1;
234 ngx_http_xslt_body_filter(ngx_http_request_t
*r
, ngx_chain_t
*in
)
237 ngx_http_xslt_filter_ctx_t
*ctx
;
239 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
243 return ngx_http_next_body_filter(r
, in
);
246 ctx
= ngx_http_get_module_ctx(r
, ngx_http_xslt_filter_module
);
248 if (ctx
== NULL
|| ctx
->done
) {
249 return ngx_http_next_body_filter(r
, in
);
252 for (cl
= in
; cl
; cl
= cl
->next
) {
254 if (ngx_http_xslt_add_chunk(r
, ctx
, cl
->buf
) != NGX_OK
) {
256 if (ctx
->ctxt
->myDoc
){
258 #if (NGX_HTTP_XSLT_REUSE_DTD)
259 ctx
->ctxt
->myDoc
->extSubset
= NULL
;
261 xmlFreeDoc(ctx
->ctxt
->myDoc
);
264 xmlFreeParserCtxt(ctx
->ctxt
);
266 return ngx_http_xslt_send(r
, ctx
, NULL
);
269 if (cl
->buf
->last_buf
) {
271 ctx
->doc
= ctx
->ctxt
->myDoc
;
273 #if (NGX_HTTP_XSLT_REUSE_DTD)
274 ctx
->doc
->extSubset
= NULL
;
277 xmlFreeParserCtxt(ctx
->ctxt
);
279 if (ctx
->ctxt
->wellFormed
) {
280 return ngx_http_xslt_send(r
, ctx
,
281 ngx_http_xslt_apply_stylesheet(r
, ctx
));
284 xmlFreeDoc(ctx
->doc
);
286 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
287 "not well formed XML document");
289 return ngx_http_xslt_send(r
, ctx
, NULL
);
298 ngx_http_xslt_send(ngx_http_request_t
*r
, ngx_http_xslt_filter_ctx_t
*ctx
,
303 ngx_pool_cleanup_t
*cln
;
308 return ngx_http_xslt_filter_internal_error(r
);
311 cln
= ngx_pool_cleanup_add(r
->pool
, 0);
315 return ngx_http_special_response_handler(r
,
316 NGX_HTTP_INTERNAL_SERVER_ERROR
);
320 r
->headers_out
.content_type_len
= sizeof("text/html") - 1;
321 r
->headers_out
.content_type
.len
= sizeof("text/html") - 1;
322 r
->headers_out
.content_type
.data
= (u_char
*) "text/html";
325 r
->headers_out
.content_length_n
= b
->last
- b
->pos
;
327 if (r
->headers_out
.content_length
) {
328 r
->headers_out
.content_length
->hash
= 0;
329 r
->headers_out
.content_length
= NULL
;
334 rc
= ngx_http_next_header_filter(r
);
336 if (rc
== NGX_ERROR
|| rc
> NGX_OK
|| r
->header_only
) {
341 cln
->handler
= ngx_http_xslt_cleanup
;
347 return ngx_http_next_body_filter(r
, &out
);
352 ngx_http_xslt_filter_internal_error(ngx_http_request_t
*r
)
356 /* clear the modules contexts */
357 ngx_memzero(r
->ctx
, sizeof(void *) * ngx_http_max_module
);
359 rc
= ngx_http_special_response_handler(r
, NGX_HTTP_INTERNAL_SERVER_ERROR
);
361 /* NGX_ERROR resets any pending data */
363 return (rc
== NGX_OK
) ? NGX_ERROR
: rc
;
368 ngx_http_xslt_add_chunk(ngx_http_request_t
*r
, ngx_http_xslt_filter_ctx_t
*ctx
,
373 xmlParserCtxtPtr ctxt
;
375 if (ctx
->ctxt
== NULL
) {
377 ctxt
= xmlCreatePushParserCtxt(NULL
, NULL
, NULL
, 0, NULL
);
379 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
380 "xmlCreatePushParserCtxt() failed");
384 ctx
->sax
= ngx_palloc(r
->pool
, sizeof(xmlSAXHandler
));
385 if (ctx
->sax
== NULL
) {
391 ngx_memcpy(ctx
->sax
, sax
, sizeof(xmlSAXHandler
));
393 sax
->startDocument
= ngx_http_xslt_sax_start_document
;
394 sax
->endDocument
= ngx_http_xslt_sax_end_document
;
396 sax
->internalSubset
= ngx_http_xslt_sax_internal_subset
;
397 sax
->externalSubset
= ngx_http_xslt_sax_external_subset
;
398 sax
->entityDecl
= ngx_http_xslt_sax_entity_decl
;
399 sax
->attributeDecl
= ngx_http_xslt_sax_attribute_decl
;
400 sax
->elementDecl
= ngx_http_xslt_sax_element_decl
;
401 sax
->notationDecl
= ngx_http_xslt_sax_notation_decl
;
402 sax
->unparsedEntityDecl
= ngx_http_xslt_sax_unparsed_entity_decl
;
403 sax
->setDocumentLocator
= NULL
;
405 sax
->startElementNs
= ngx_http_xslt_sax_start_element
;
406 sax
->endElementNs
= ngx_http_xslt_sax_end_element
;
408 sax
->characters
= ngx_http_xslt_sax_characters
;
409 sax
->ignorableWhitespace
= ngx_http_xslt_sax_characters
;
410 sax
->cdataBlock
= ngx_http_xslt_sax_cdata_block
;
411 sax
->getEntity
= ngx_http_xslt_sax_get_entity
;
412 sax
->resolveEntity
= ngx_http_xslt_sax_resolve_entity
;
413 sax
->getParameterEntity
= ngx_http_xslt_sax_get_parameter_entity
;
414 sax
->reference
= ngx_http_xslt_sax_reference
;
415 sax
->comment
= ngx_http_xslt_sax_comment
;
416 sax
->processingInstruction
= ngx_http_xslt_sax_processing_instruction
;
418 sax
->isStandalone
= ngx_http_xslt_sax_is_standalone
;
419 sax
->hasInternalSubset
= ngx_http_xslt_sax_has_internal_subset
;
420 sax
->hasExternalSubset
= ngx_http_xslt_sax_has_external_subset
;
423 sax
->error
= ngx_http_xslt_sax_error
;
424 sax
->fatalError
= ngx_http_xslt_sax_error
;
426 ctxt
->userData
= ctx
;
428 ctxt
->replaceEntities
= 1;
429 ctxt
->loadsubset
= 1;
435 err
= xmlParseChunk(ctx
->ctxt
, (char *) b
->pos
,
436 (int) (b
->last
- b
->pos
), b
->last_buf
);
443 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
444 "xmlParseChunk() failed, error:%d", err
);
451 ngx_http_xslt_sax_start_document(void *data
)
453 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
455 ctx
->sax
->startDocument(ctx
->ctxt
);
460 ngx_http_xslt_sax_end_document(void *data
)
462 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
464 ctx
->sax
->endDocument(ctx
->ctxt
);
469 ngx_http_xslt_sax_internal_subset(void *data
, const xmlChar
*name
,
470 const xmlChar
*externalId
, const xmlChar
*systemId
)
472 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
474 ctx
->sax
->internalSubset(ctx
->ctxt
, name
, externalId
, systemId
);
479 ngx_http_xslt_sax_external_subset(void *data
, const xmlChar
*name
,
480 const xmlChar
*externalId
, const xmlChar
*systemId
)
482 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
486 ngx_http_request_t
*r
;
487 ngx_http_xslt_filter_conf_t
*conf
;
491 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
493 ngx_log_debug3(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
494 "xslt filter extSubset: \"%s\" \"%s\" \"%s\"",
495 name
? name
: (xmlChar
*) "",
496 externalId
? externalId
: (xmlChar
*) "",
497 systemId
? systemId
: (xmlChar
*) "");
499 doc
= ctx
->ctxt
->myDoc
;
501 #if (NGX_HTTP_XSLT_REUSE_DTD)
507 dtd
= xmlCopyDtd(conf
->dtd
);
509 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
510 "xmlCopyDtd() failed");
514 dtd
->name
= xmlStrdup(name
);
516 if (doc
->children
== NULL
) {
517 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
520 xmlAddPrevSibling(doc
->children
, (xmlNodePtr
) dtd
);
525 doc
->extSubset
= dtd
;
530 ngx_http_xslt_sax_entity_decl(void *data
, const xmlChar
*name
, int type
,
531 const xmlChar
*publicId
, const xmlChar
*systemId
, xmlChar
*content
)
533 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
535 ctx
->sax
->entityDecl(ctx
->ctxt
, name
, type
, publicId
, systemId
, content
);
540 ngx_http_xslt_sax_attribute_decl(void *data
, const xmlChar
*elem
,
541 const xmlChar
*fullname
, int type
, int def
, const xmlChar
*defaultValue
,
542 xmlEnumerationPtr tree
)
544 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
546 ctx
->sax
->attributeDecl(ctx
->ctxt
, elem
, fullname
, type
, def
, defaultValue
,
552 ngx_http_xslt_sax_element_decl(void *data
, const xmlChar
* name
, int type
,
553 xmlElementContentPtr content
)
555 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
557 ctx
->sax
->elementDecl(ctx
->ctxt
, name
, type
, content
);
562 ngx_http_xslt_sax_notation_decl(void *data
, const xmlChar
*name
,
563 const xmlChar
*publicId
, const xmlChar
*systemId
)
565 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
567 ctx
->sax
->notationDecl(ctx
->ctxt
, name
, publicId
, systemId
);
572 ngx_http_xslt_sax_unparsed_entity_decl(void *data
, const xmlChar
*name
,
573 const xmlChar
*publicId
, const xmlChar
*systemId
,
574 const xmlChar
*notationName
)
576 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
578 ctx
->sax
->unparsedEntityDecl(ctx
->ctxt
, name
, publicId
, systemId
,
584 ngx_http_xslt_sax_start_element(void *data
, const xmlChar
*localname
,
585 const xmlChar
*prefix
, const xmlChar
*URI
, int nb_namespaces
,
586 const xmlChar
**namespaces
, int nb_attributes
, int nb_defaulted
,
587 const xmlChar
**attributes
)
589 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
591 ctx
->sax
->startElementNs(ctx
->ctxt
, localname
, prefix
, URI
, nb_namespaces
,
592 namespaces
, nb_attributes
, nb_defaulted
, attributes
);
597 ngx_http_xslt_sax_end_element(void *data
,
598 const xmlChar
* localname ATTRIBUTE_UNUSED
,
599 const xmlChar
* prefix ATTRIBUTE_UNUSED
,
600 const xmlChar
* URI ATTRIBUTE_UNUSED
)
602 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
604 ctx
->sax
->endElementNs(ctx
->ctxt
, localname
, prefix
, URI
);
609 ngx_http_xslt_sax_characters(void *data
, const xmlChar
*p
, int len
)
611 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
613 ctx
->sax
->characters(ctx
->ctxt
, p
, len
);
618 ngx_http_xslt_sax_cdata_block(void *data
, const xmlChar
*p
, int len
)
620 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
622 ctx
->sax
->cdataBlock(ctx
->ctxt
, p
, len
);
627 ngx_http_xslt_sax_get_entity(void *data
, const xmlChar
*name
)
629 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
631 return ctx
->sax
->getEntity(ctx
->ctxt
, name
);
636 ngx_http_xslt_sax_get_parameter_entity(void *data
, const xmlChar
*name
)
638 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
640 return ctx
->sax
->getParameterEntity(ctx
->ctxt
, name
);
644 static xmlParserInputPtr
645 ngx_http_xslt_sax_resolve_entity(void *data
, const xmlChar
*publicId
,
646 const xmlChar
*systemId
)
648 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
650 return ctx
->sax
->resolveEntity(ctx
->ctxt
, publicId
, systemId
);
655 ngx_http_xslt_sax_reference(void *data
, const xmlChar
*name
)
657 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
659 ctx
->sax
->reference(ctx
->ctxt
, name
);
664 ngx_http_xslt_sax_comment(void *data
, const xmlChar
*value
)
666 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
668 ctx
->sax
->comment(ctx
->ctxt
, value
);
673 ngx_http_xslt_sax_processing_instruction(void *data
, const xmlChar
*target
,
674 const xmlChar
*pidata
)
676 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
678 ctx
->sax
->processingInstruction(ctx
->ctxt
, target
, pidata
);
683 ngx_http_xslt_sax_is_standalone(void *data
)
685 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
687 return ctx
->sax
->isStandalone(ctx
->ctxt
);
692 ngx_http_xslt_sax_has_internal_subset(void *data
)
694 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
696 return ctx
->sax
->hasInternalSubset(ctx
->ctxt
);
701 ngx_http_xslt_sax_has_external_subset(void *data
)
703 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
705 return ctx
->sax
->hasExternalSubset(ctx
->ctxt
);
709 static void ngx_cdecl
710 ngx_http_xslt_sax_error(void *data
, const char *msg
, ...)
712 ngx_http_xslt_filter_ctx_t
*ctx
= data
;
716 u_char buf
[NGX_MAX_ERROR_STR
];
721 n
= (size_t) vsnprintf((char *) buf
, NGX_MAX_ERROR_STR
, msg
, args
);
724 while (--n
&& (buf
[n
] == CR
|| buf
[n
] == LF
)) { /* void */ }
726 ngx_log_error(NGX_LOG_ERR
, ctx
->request
->connection
->log
, 0,
727 "libxml2 error: \"%*s\"", n
, buf
);
732 ngx_http_xslt_apply_stylesheet(ngx_http_request_t
*r
,
733 ngx_http_xslt_filter_ctx_t
*ctx
)
740 ngx_http_xslt_sheet_t
*sheet
;
741 ngx_http_xslt_filter_conf_t
*conf
;
743 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
744 sheet
= conf
->sheets
.elts
;
747 /* preallocate array for 4 params */
749 if (ngx_array_init(&ctx
->params
, r
->pool
, 4 * 2 + 1, sizeof(char *))
756 for (i
= 0; i
< conf
->sheets
.nelts
; i
++) {
758 if (ngx_http_xslt_params(r
, ctx
, &sheet
[i
].params
) != NGX_OK
) {
763 res
= xsltApplyStylesheet(sheet
[i
].stylesheet
, doc
, ctx
->params
.elts
);
768 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
769 "xsltApplyStylesheet() failed");
775 /* reset array elements */
776 ctx
->params
.nelts
= 0;
779 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
780 "xslt filter doc type: %d", doc
->type
);
782 ctx
->html
= (doc
->type
== XML_HTML_DOCUMENT_NODE
) ? 1 : 0;
784 rc
= xsltSaveResultToString(&buf
, &len
, doc
, sheet
[i
- 1].stylesheet
);
789 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
790 "xsltSaveResultToString() failed");
795 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
796 "xsltSaveResultToString() returned zero-length result");
800 b
= ngx_pcalloc(r
->pool
, sizeof(ngx_buf_t
));
816 ngx_http_xslt_params(ngx_http_request_t
*r
, ngx_http_xslt_filter_ctx_t
*ctx
,
819 u_char
*p
, *last
, *value
, *dst
, *src
, **s
;
823 ngx_http_xslt_param_t
*param
;
825 param
= params
->elts
;
827 for (i
= 0; i
< params
->nelts
; i
++) {
829 if (ngx_http_script_run(r
, &string
, param
[i
].lengths
->elts
, 1,
830 param
[i
].values
->elts
)
836 last
= string
.data
+ string
.len
- 1;
839 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
840 "xslt filter param: \"%s\"", string
.data
);
847 p
= (u_char
*) ngx_strchr(p
, '=');
849 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
850 "invalid libxslt parameter \"%s\"", value
);
855 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
856 "xslt filter param name: \"%s\"", value
);
858 s
= ngx_array_push(&ctx
->params
);
866 p
= (u_char
*) ngx_strchr(p
, ':');
876 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
877 "xslt filter param value: \"%s\"", value
);
882 ngx_unescape_uri(&dst
, &src
, len
, 0);
886 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
887 "xslt filter param unescaped: \"%s\"", value
);
889 s
= ngx_array_push(&ctx
->params
);
898 s
= ngx_array_push(&ctx
->params
);
910 ngx_http_xslt_cleanup(void *data
)
917 ngx_http_xslt_entities(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
919 ngx_http_xslt_filter_conf_t
*xlcf
= conf
;
924 return "is duplicate";
927 value
= cf
->args
->elts
;
929 xlcf
->dtd
= xmlParseDTD(NULL
, (xmlChar
*) value
[1].data
);
931 if (xlcf
->dtd
== NULL
) {
932 ngx_conf_log_error(NGX_LOG_ERR
, cf
, 0, "xmlParseDTD() failed");
933 return NGX_CONF_ERROR
;
942 ngx_http_xslt_stylesheet(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
944 ngx_http_xslt_filter_conf_t
*xlcf
= conf
;
948 ngx_pool_cleanup_t
*cln
;
949 ngx_http_xslt_sheet_t
*sheet
;
950 ngx_http_xslt_param_t
*param
;
951 ngx_http_script_compile_t sc
;
953 value
= cf
->args
->elts
;
955 if (xlcf
->sheets
.elts
== NULL
) {
956 if (ngx_array_init(&xlcf
->sheets
, cf
->pool
, 1,
957 sizeof(ngx_http_xslt_sheet_t
))
960 return NGX_CONF_ERROR
;
964 sheet
= ngx_array_push(&xlcf
->sheets
);
966 return NGX_CONF_ERROR
;
969 ngx_memzero(sheet
, sizeof(ngx_http_xslt_sheet_t
));
971 if (ngx_conf_full_name(cf
->cycle
, &value
[1], 0) != NGX_OK
) {
972 return NGX_CONF_ERROR
;
975 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
977 return NGX_CONF_ERROR
;
980 sheet
->stylesheet
= xsltParseStylesheetFile(value
[1].data
);
981 if (sheet
->stylesheet
== NULL
) {
982 ngx_conf_log_error(NGX_LOG_ERR
, cf
, 0,
983 "xsltParseStylesheetFile(\"%s\") failed",
985 return NGX_CONF_ERROR
;
988 cln
->handler
= ngx_http_xslt_cleanup_stylesheet
;
989 cln
->data
= sheet
->stylesheet
;
997 if (ngx_array_init(&sheet
->params
, cf
->pool
, n
- 2,
998 sizeof(ngx_http_xslt_param_t
))
1001 return NGX_CONF_ERROR
;
1004 for (i
= 2; i
< n
; i
++) {
1006 param
= ngx_array_push(&sheet
->params
);
1007 if (param
== NULL
) {
1008 return NGX_CONF_ERROR
;
1011 param
->lengths
= NULL
;
1012 param
->values
= NULL
;
1014 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
1017 sc
.source
= &value
[i
];
1018 sc
.lengths
= ¶m
->lengths
;
1019 sc
.values
= ¶m
->values
;
1020 sc
.variables
= ngx_http_script_variables_count(&value
[i
]);
1021 sc
.complete_lengths
= 1;
1022 sc
.complete_values
= 1;
1024 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
1025 return NGX_CONF_ERROR
;
1034 ngx_http_xslt_cleanup_stylesheet(void *data
)
1036 xsltStylesheetPtr stylesheet
= data
;
1038 xsltFreeStylesheet(stylesheet
);
1044 ngx_http_xslt_filter_create_conf(ngx_conf_t
*cf
)
1046 ngx_http_xslt_filter_conf_t
*conf
;
1048 conf
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_xslt_filter_conf_t
));
1050 return NGX_CONF_ERROR
;
1054 * set by ngx_pcalloc():
1065 ngx_http_xslt_filter_merge_conf(ngx_conf_t
*cf
, void *parent
, void *child
)
1067 ngx_http_xslt_filter_conf_t
*prev
= parent
;
1068 ngx_http_xslt_filter_conf_t
*conf
= child
;
1070 if (conf
->dtd
== NULL
) {
1071 conf
->dtd
= prev
->dtd
;
1074 if (conf
->sheets
.nelts
== 0) {
1075 conf
->sheets
= prev
->sheets
;
1078 if (ngx_http_merge_types(cf
, conf
->keys
, &conf
->types_hash
, prev
->keys
,
1079 &prev
->types_hash
, ngx_http_xslt_default_types
)
1082 return NGX_CONF_ERROR
;
1090 ngx_http_xslt_filter_init(ngx_conf_t
*cf
)
1094 ngx_http_next_header_filter
= ngx_http_top_header_filter
;
1095 ngx_http_top_header_filter
= ngx_http_xslt_header_filter
;
1097 ngx_http_next_body_filter
= ngx_http_top_body_filter
;
1098 ngx_http_top_body_filter
= ngx_http_xslt_body_filter
;
1105 ngx_http_xslt_filter_exit(ngx_cycle_t
*cycle
)
1107 xsltCleanupGlobals();