3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
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>
21 #include <libexslt/exslt.h>
25 #ifndef NGX_HTTP_XSLT_REUSE_DTD
26 #define NGX_HTTP_XSLT_REUSE_DTD 1
33 } ngx_http_xslt_file_t
;
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
;
44 ngx_http_complex_value_t value
;
45 ngx_uint_t quote
; /* unsigned quote:1; */
46 } ngx_http_xslt_param_t
;
50 xsltStylesheetPtr stylesheet
;
51 ngx_array_t params
; /* ngx_http_xslt_param_t */
52 } ngx_http_xslt_sheet_t
;
57 ngx_array_t sheets
; /* ngx_http_xslt_sheet_t */
59 ngx_array_t
*types_keys
;
60 ngx_array_t
*params
; /* ngx_http_xslt_param_t */
61 } ngx_http_xslt_filter_loc_conf_t
;
66 xmlParserCtxtPtr ctxt
;
67 xsltTransformContextPtr transform
;
68 ngx_http_request_t
*request
;
71 ngx_uint_t done
; /* unsigned done:1; */
72 } ngx_http_xslt_filter_ctx_t
;
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
);
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
, ...);
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
);
94 static char *ngx_http_xslt_entities(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
96 static char *ngx_http_xslt_stylesheet(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
98 static char *ngx_http_xslt_param(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
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
,
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
);
110 ngx_str_t ngx_http_xslt_default_types
[] = {
111 ngx_string("text/xml"),
116 static ngx_command_t ngx_http_xslt_filter_commands
[] = {
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
,
125 { ngx_string("xslt_stylesheet"),
126 NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
127 ngx_http_xslt_stylesheet
,
128 NGX_HTTP_LOC_CONF_OFFSET
,
132 { ngx_string("xslt_param"),
133 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE2
,
135 NGX_HTTP_LOC_CONF_OFFSET
,
139 { ngx_string("xslt_string_param"),
140 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE2
,
142 NGX_HTTP_LOC_CONF_OFFSET
,
146 { ngx_string("xslt_types"),
147 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
149 NGX_HTTP_LOC_CONF_OFFSET
,
150 offsetof(ngx_http_xslt_filter_loc_conf_t
, types_keys
),
151 &ngx_http_xslt_default_types
[0] },
157 static ngx_http_module_t ngx_http_xslt_filter_module_ctx
= {
158 NULL
, /* preconfiguration */
159 ngx_http_xslt_filter_init
, /* postconfiguration */
161 ngx_http_xslt_filter_create_main_conf
, /* create main configuration */
162 NULL
, /* init main configuration */
164 NULL
, /* create server configuration */
165 NULL
, /* merge server configuration */
167 ngx_http_xslt_filter_create_conf
, /* create location configuration */
168 ngx_http_xslt_filter_merge_conf
/* merge location configuration */
172 ngx_module_t ngx_http_xslt_filter_module
= {
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
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
;
193 ngx_http_xslt_header_filter(ngx_http_request_t
*r
)
195 ngx_http_xslt_filter_ctx_t
*ctx
;
196 ngx_http_xslt_filter_loc_conf_t
*conf
;
198 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
199 "xslt filter header");
201 if (r
->headers_out
.status
== NGX_HTTP_NOT_MODIFIED
) {
202 return ngx_http_next_header_filter(r
);
205 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
207 if (conf
->sheets
.nelts
== 0
208 || ngx_http_test_content_type(r
, &conf
->types
) == NULL
)
210 return ngx_http_next_header_filter(r
);
213 ctx
= ngx_http_get_module_ctx(r
, ngx_http_xslt_filter_module
);
216 return ngx_http_next_header_filter(r
);
219 ctx
= ngx_pcalloc(r
->pool
, sizeof(ngx_http_xslt_filter_ctx_t
));
224 ngx_http_set_ctx(r
, ctx
, ngx_http_xslt_filter_module
);
226 r
->main_filter_need_in_memory
= 1;
233 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
|| cl
->buf
->last_in_chain
) {
271 ctx
->doc
= ctx
->ctxt
->myDoc
;
273 #if (NGX_HTTP_XSLT_REUSE_DTD)
274 ctx
->doc
->extSubset
= NULL
;
277 wellFormed
= ctx
->ctxt
->wellFormed
;
279 xmlFreeParserCtxt(ctx
->ctxt
);
282 return ngx_http_xslt_send(r
, ctx
,
283 ngx_http_xslt_apply_stylesheet(r
, ctx
));
286 xmlFreeDoc(ctx
->doc
);
288 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
289 "not well formed XML document");
291 return ngx_http_xslt_send(r
, ctx
, NULL
);
300 ngx_http_xslt_send(ngx_http_request_t
*r
, ngx_http_xslt_filter_ctx_t
*ctx
,
305 ngx_pool_cleanup_t
*cln
;
310 return ngx_http_filter_finalize_request(r
, &ngx_http_xslt_filter_module
,
311 NGX_HTTP_INTERNAL_SERVER_ERROR
);
314 cln
= ngx_pool_cleanup_add(r
->pool
, 0);
318 return ngx_http_filter_finalize_request(r
, &ngx_http_xslt_filter_module
,
319 NGX_HTTP_INTERNAL_SERVER_ERROR
);
323 r
->headers_out
.content_length_n
= b
->last
- b
->pos
;
325 if (r
->headers_out
.content_length
) {
326 r
->headers_out
.content_length
->hash
= 0;
327 r
->headers_out
.content_length
= NULL
;
330 ngx_http_clear_last_modified(r
);
331 ngx_http_clear_etag(r
);
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_add_chunk(ngx_http_request_t
*r
, ngx_http_xslt_filter_ctx_t
*ctx
,
356 xmlParserCtxtPtr ctxt
;
358 if (ctx
->ctxt
== NULL
) {
360 ctxt
= xmlCreatePushParserCtxt(NULL
, NULL
, NULL
, 0, NULL
);
362 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
363 "xmlCreatePushParserCtxt() failed");
366 xmlCtxtUseOptions(ctxt
, XML_PARSE_NOENT
|XML_PARSE_DTDLOAD
367 |XML_PARSE_NOWARNING
);
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
;
379 err
= xmlParseChunk(ctx
->ctxt
, (char *) b
->pos
, (int) (b
->last
- b
->pos
),
380 (b
->last_buf
) || (b
->last_in_chain
));
387 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
388 "xmlParseChunk() failed, error:%d", err
);
395 ngx_http_xslt_sax_external_subset(void *data
, const xmlChar
*name
,
396 const xmlChar
*externalId
, const xmlChar
*systemId
)
398 xmlParserCtxtPtr ctxt
= data
;
402 ngx_http_request_t
*r
;
403 ngx_http_xslt_filter_ctx_t
*ctx
;
404 ngx_http_xslt_filter_loc_conf_t
*conf
;
406 ctx
= ctxt
->sax
->_private
;
409 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
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
*) "");
419 #if (NGX_HTTP_XSLT_REUSE_DTD)
425 dtd
= xmlCopyDtd(conf
->dtd
);
427 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
428 "xmlCopyDtd() failed");
432 if (doc
->children
== NULL
) {
433 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
436 xmlAddPrevSibling(doc
->children
, (xmlNodePtr
) dtd
);
441 doc
->extSubset
= dtd
;
445 static void ngx_cdecl
446 ngx_http_xslt_sax_error(void *data
, const char *msg
, ...)
448 xmlParserCtxtPtr ctxt
= data
;
452 ngx_http_xslt_filter_ctx_t
*ctx
;
453 u_char buf
[NGX_MAX_ERROR_STR
];
455 ctx
= ctxt
->sax
->_private
;
460 n
= (size_t) vsnprintf((char *) buf
, NGX_MAX_ERROR_STR
, msg
, args
);
463 while (--n
&& (buf
[n
] == CR
|| buf
[n
] == LF
)) { /* void */ }
465 ngx_log_error(NGX_LOG_ERR
, ctx
->request
->connection
->log
, 0,
466 "libxml2 error: \"%*s\"", n
+ 1, buf
);
471 ngx_http_xslt_apply_stylesheet(ngx_http_request_t
*r
,
472 ngx_http_xslt_filter_ctx_t
*ctx
)
474 int len
, rc
, doc_type
;
475 u_char
*type
, *encoding
;
480 ngx_http_xslt_sheet_t
*sheet
;
481 ngx_http_xslt_filter_loc_conf_t
*conf
;
483 conf
= ngx_http_get_module_loc_conf(r
, ngx_http_xslt_filter_module
);
484 sheet
= conf
->sheets
.elts
;
487 /* preallocate array for 4 params */
489 if (ngx_array_init(&ctx
->params
, r
->pool
, 4 * 2 + 1, sizeof(char *))
496 for (i
= 0; i
< conf
->sheets
.nelts
; i
++) {
498 ctx
->transform
= xsltNewTransformContext(sheet
[i
].stylesheet
, doc
);
499 if (ctx
->transform
== NULL
) {
505 && ngx_http_xslt_params(r
, ctx
, conf
->params
, 0) != NGX_OK
)
507 xsltFreeTransformContext(ctx
->transform
);
512 if (ngx_http_xslt_params(r
, ctx
, &sheet
[i
].params
, 1) != NGX_OK
) {
513 xsltFreeTransformContext(ctx
->transform
);
518 res
= xsltApplyStylesheetUser(sheet
[i
].stylesheet
, doc
,
519 ctx
->params
.elts
, NULL
, NULL
,
522 xsltFreeTransformContext(ctx
->transform
);
526 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
527 "xsltApplyStylesheet() failed");
533 /* reset array elements */
534 ctx
->params
.nelts
= 0;
537 /* there must be at least one stylesheet */
540 type
= ngx_http_xslt_content_type(sheet
[i
- 1].stylesheet
);
546 encoding
= ngx_http_xslt_encoding(sheet
[i
- 1].stylesheet
);
547 doc_type
= doc
->type
;
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)");
554 rc
= xsltSaveResultToString(&buf
, &len
, doc
, sheet
[i
- 1].stylesheet
);
559 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
560 "xsltSaveResultToString() failed");
565 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
566 "xsltSaveResultToString() returned zero-length result");
570 b
= ngx_pcalloc(r
->pool
, sizeof(ngx_buf_t
));
581 r
->headers_out
.charset
.len
= ngx_strlen(encoding
);
582 r
->headers_out
.charset
.data
= encoding
;
592 len
= ngx_strlen(type
);
594 r
->headers_out
.content_type_len
= len
;
595 r
->headers_out
.content_type
.len
= len
;
596 r
->headers_out
.content_type
.data
= type
;
598 } else if (doc_type
== XML_HTML_DOCUMENT_NODE
) {
600 r
->headers_out
.content_type_len
= sizeof("text/html") - 1;
601 ngx_str_set(&r
->headers_out
.content_type
, "text/html");
604 r
->headers_out
.content_type_lowcase
= NULL
;
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
)
614 u_char
*p
, *last
, *value
, *dst
, *src
, **s
;
618 ngx_http_xslt_param_t
*param
;
620 param
= params
->elts
;
622 for (i
= 0; i
< params
->nelts
; i
++) {
624 if (ngx_http_complex_value(r
, ¶m
[i
].value
, &string
) != NGX_OK
) {
628 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
629 "xslt filter param: \"%s\"", string
.data
);
633 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
634 "xslt filter param name: \"%s\"", param
[i
].name
);
636 if (param
[i
].quote
) {
637 if (xsltQuoteOneUserParam(ctx
->transform
, param
[i
].name
,
641 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
642 "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
643 param
[i
].name
, string
.data
);
650 s
= ngx_array_push(&ctx
->params
);
657 s
= ngx_array_push(&ctx
->params
);
668 * parse param1=value1:param2=value2 syntax as used by parameters
669 * specified in xslt_stylesheet directives
673 last
= string
.data
+ string
.len
;
678 p
= (u_char
*) ngx_strchr(p
, '=');
680 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
681 "invalid libxslt parameter \"%s\"", value
);
686 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
687 "xslt filter param name: \"%s\"", value
);
689 s
= ngx_array_push(&ctx
->params
);
697 p
= (u_char
*) ngx_strchr(p
, ':');
707 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
708 "xslt filter param value: \"%s\"", value
);
713 ngx_unescape_uri(&dst
, &src
, len
, 0);
717 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
718 "xslt filter param unescaped: \"%s\"", value
);
720 s
= ngx_array_push(&ctx
->params
);
730 s
= ngx_array_push(&ctx
->params
);
743 ngx_http_xslt_content_type(xsltStylesheetPtr s
)
751 for (s
= s
->imports
; s
; s
= s
->next
) {
753 type
= ngx_http_xslt_content_type(s
);
765 ngx_http_xslt_encoding(xsltStylesheetPtr s
)
773 for (s
= s
->imports
; s
; s
= s
->next
) {
775 encoding
= ngx_http_xslt_encoding(s
);
787 ngx_http_xslt_cleanup(void *data
)
794 ngx_http_xslt_entities(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
796 ngx_http_xslt_filter_loc_conf_t
*xlcf
= conf
;
800 ngx_pool_cleanup_t
*cln
;
801 ngx_http_xslt_file_t
*file
;
802 ngx_http_xslt_filter_main_conf_t
*xmcf
;
805 return "is duplicate";
808 value
= cf
->args
->elts
;
810 xmcf
= ngx_http_conf_get_module_main_conf(cf
, ngx_http_xslt_filter_module
);
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
;
820 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
822 return NGX_CONF_ERROR
;
825 xlcf
->dtd
= xmlParseDTD(NULL
, (xmlChar
*) value
[1].data
);
827 if (xlcf
->dtd
== NULL
) {
828 ngx_conf_log_error(NGX_LOG_ERR
, cf
, 0, "xmlParseDTD() failed");
829 return NGX_CONF_ERROR
;
832 cln
->handler
= ngx_http_xslt_cleanup_dtd
;
833 cln
->data
= xlcf
->dtd
;
835 file
= ngx_array_push(&xmcf
->dtd_files
);
837 return NGX_CONF_ERROR
;
840 file
->name
= value
[1].data
;
841 file
->data
= xlcf
->dtd
;
849 ngx_http_xslt_stylesheet(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
851 ngx_http_xslt_filter_loc_conf_t
*xlcf
= conf
;
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
;
862 value
= cf
->args
->elts
;
864 if (xlcf
->sheets
.elts
== NULL
) {
865 if (ngx_array_init(&xlcf
->sheets
, cf
->pool
, 1,
866 sizeof(ngx_http_xslt_sheet_t
))
869 return NGX_CONF_ERROR
;
873 sheet
= ngx_array_push(&xlcf
->sheets
);
875 return NGX_CONF_ERROR
;
878 ngx_memzero(sheet
, sizeof(ngx_http_xslt_sheet_t
));
880 if (ngx_conf_full_name(cf
->cycle
, &value
[1], 0) != NGX_OK
) {
881 return NGX_CONF_ERROR
;
884 xmcf
= ngx_http_conf_get_module_main_conf(cf
, ngx_http_xslt_filter_module
);
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
;
894 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
896 return NGX_CONF_ERROR
;
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",
904 return NGX_CONF_ERROR
;
907 cln
->handler
= ngx_http_xslt_cleanup_stylesheet
;
908 cln
->data
= sheet
->stylesheet
;
910 file
= ngx_array_push(&xmcf
->sheet_files
);
912 return NGX_CONF_ERROR
;
915 file
->name
= value
[1].data
;
916 file
->data
= sheet
->stylesheet
;
926 if (ngx_array_init(&sheet
->params
, cf
->pool
, n
- 2,
927 sizeof(ngx_http_xslt_param_t
))
930 return NGX_CONF_ERROR
;
933 for (i
= 2; i
< n
; i
++) {
935 param
= ngx_array_push(&sheet
->params
);
937 return NGX_CONF_ERROR
;
940 ngx_memzero(param
, sizeof(ngx_http_xslt_param_t
));
941 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
944 ccv
.value
= &value
[i
];
945 ccv
.complex_value
= ¶m
->value
;
948 if (ngx_http_compile_complex_value(&ccv
) != NGX_OK
) {
949 return NGX_CONF_ERROR
;
958 ngx_http_xslt_param(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
960 ngx_http_xslt_filter_loc_conf_t
*xlcf
= conf
;
962 ngx_http_xslt_param_t
*param
;
963 ngx_http_compile_complex_value_t ccv
;
966 value
= cf
->args
->elts
;
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
;
976 param
= ngx_array_push(xlcf
->params
);
978 return NGX_CONF_ERROR
;
981 param
->name
= value
[1].data
;
982 param
->quote
= (cmd
->post
== NULL
) ? 0 : 1;
984 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
987 ccv
.value
= &value
[2];
988 ccv
.complex_value
= ¶m
->value
;
991 if (ngx_http_compile_complex_value(&ccv
) != NGX_OK
) {
992 return NGX_CONF_ERROR
;
1000 ngx_http_xslt_cleanup_dtd(void *data
)
1007 ngx_http_xslt_cleanup_stylesheet(void *data
)
1009 xsltFreeStylesheet(data
);
1014 ngx_http_xslt_filter_create_main_conf(ngx_conf_t
*cf
)
1016 ngx_http_xslt_filter_main_conf_t
*conf
;
1018 conf
= ngx_palloc(cf
->pool
, sizeof(ngx_http_xslt_filter_main_conf_t
));
1023 if (ngx_array_init(&conf
->dtd_files
, cf
->pool
, 1,
1024 sizeof(ngx_http_xslt_file_t
))
1030 if (ngx_array_init(&conf
->sheet_files
, cf
->pool
, 1,
1031 sizeof(ngx_http_xslt_file_t
))
1042 ngx_http_xslt_filter_create_conf(ngx_conf_t
*cf
)
1044 ngx_http_xslt_filter_loc_conf_t
*conf
;
1046 conf
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_xslt_filter_loc_conf_t
));
1052 * set by ngx_pcalloc():
1055 * conf->sheets = { NULL };
1056 * conf->types = { NULL };
1057 * conf->types_keys = NULL;
1058 * conf->params = NULL;
1066 ngx_http_xslt_filter_merge_conf(ngx_conf_t
*cf
, void *parent
, void *child
)
1068 ngx_http_xslt_filter_loc_conf_t
*prev
= parent
;
1069 ngx_http_xslt_filter_loc_conf_t
*conf
= child
;
1071 if (conf
->dtd
== NULL
) {
1072 conf
->dtd
= prev
->dtd
;
1075 if (conf
->sheets
.nelts
== 0) {
1076 conf
->sheets
= prev
->sheets
;
1079 if (conf
->params
== NULL
) {
1080 conf
->params
= prev
->params
;
1083 if (ngx_http_merge_types(cf
, &conf
->types_keys
, &conf
->types
,
1084 &prev
->types_keys
, &prev
->types
,
1085 ngx_http_xslt_default_types
)
1088 return NGX_CONF_ERROR
;
1096 ngx_http_xslt_filter_init(ngx_conf_t
*cf
)
1100 #if (NGX_HAVE_EXSLT)
1104 ngx_http_next_header_filter
= ngx_http_top_header_filter
;
1105 ngx_http_top_header_filter
= ngx_http_xslt_header_filter
;
1107 ngx_http_next_body_filter
= ngx_http_top_body_filter
;
1108 ngx_http_top_body_filter
= ngx_http_xslt_body_filter
;
1115 ngx_http_xslt_filter_exit(ngx_cycle_t
*cycle
)
1117 xsltCleanupGlobals();