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
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, ...);
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);
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,
107 static void ngx_http_xslt_filter_exit(
ngx_cycle_t *cycle);
120 ngx_http_xslt_entities,
127 ngx_http_xslt_stylesheet,
151 &ngx_http_xslt_default_types[0] },
159 ngx_http_xslt_filter_init,
161 ngx_http_xslt_filter_create_main_conf,
167 ngx_http_xslt_filter_create_conf,
168 ngx_http_xslt_filter_merge_conf
174 &ngx_http_xslt_filter_module_ctx,
175 ngx_http_xslt_filter_commands,
182 ngx_http_xslt_filter_exit,
183 ngx_http_xslt_filter_exit,
199 "xslt filter header");
202 return ngx_http_next_header_filter(r);
210 return ngx_http_next_header_filter(r);
216 return ngx_http_next_header_filter(r);
243 return ngx_http_next_body_filter(r, in);
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);
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);
289 "not well formed XML document");
291 return ngx_http_xslt_send(r, ctx, NULL);
334 rc = ngx_http_next_header_filter(r);
341 cln->
handler = ngx_http_xslt_cleanup;
347 return ngx_http_next_body_filter(r, &out);
356 xmlParserCtxtPtr ctxt;
358 if (ctx->
ctxt == NULL) {
360 ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
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),
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;
406 ctx = ctxt->sax->_private;
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);
428 "xmlCopyDtd() failed");
432 if (doc->children == NULL) {
433 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
436 xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
441 doc->extSubset = dtd;
446 ngx_http_xslt_sax_error(
void *data,
const char *msg, ...)
448 xmlParserCtxtPtr ctxt = data;
455 ctx = ctxt->sax->_private;
463 while (--n && (buf[n] ==
CR || buf[n] ==
LF)) { }
466 "libxml2 error: \"%*s\"", n + 1, buf);
474 int len, rc, doc_type;
475 u_char *
type, *encoding;
489 if (ngx_array_init(&ctx->
params, r->
pool, 4 * 2 + 1,
sizeof(
char *))
498 ctx->
transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
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,
522 xsltFreeTransformContext(ctx->
transform);
527 "xsltApplyStylesheet() failed");
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;
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);
560 "xsltSaveResultToString() failed");
566 "xsltSaveResultToString() returned zero-length result");
598 }
else if (doc_type == XML_HTML_DOCUMENT_NODE) {
614 u_char *p, *last, *value, *dst, *src, **s;
620 param = params->
elts;
622 for (i = 0; i < params->
nelts; i++) {
629 "xslt filter param: \"%s\"",
string.
data);
634 "xslt filter param name: \"%s\"", param[i].
name);
636 if (param[i].quote) {
642 "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
643 param[i].
name,
string.data);
673 last =
string.data +
string.len;
681 "invalid libxslt parameter \"%s\"", value);
687 "xslt filter param name: \"%s\"", value);
708 "xslt filter param value: \"%s\"", value);
718 "xslt filter param unescaped: \"%s\"", value);
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)
805 return "is duplicate";
814 if (
ngx_strcmp(file[i].name, value[1].data) == 0) {
825 xlcf->
dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data);
827 if (xlcf->
dtd == NULL) {
832 cln->
handler = ngx_http_xslt_cleanup_dtd;
865 if (ngx_array_init(&xlcf->
sheets, cf->
pool, 1,
888 if (
ngx_strcmp(file[i].name, value[1].data) == 0) {
899 sheet->
stylesheet = xsltParseStylesheetFile(value[1].data);
902 "xsltParseStylesheetFile(\"%s\") failed",
907 cln->
handler = ngx_http_xslt_cleanup_stylesheet;
926 if (ngx_array_init(&sheet->
params, cf->
pool, n - 2,
933 for (i = 2; i < n; i++) {
968 if (xlcf->
params == NULL) {
971 if (xlcf->
params == NULL) {
982 param->
quote = (cmd->
post == NULL) ? 0 : 1;
987 ccv.
value = &value[2];
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)
1042 ngx_http_xslt_filter_create_conf(
ngx_conf_t *cf)
1066 ngx_http_xslt_filter_merge_conf(
ngx_conf_t *cf,
void *parent,
void *child)
1071 if (conf->
dtd == NULL) {
1079 if (conf->
params == NULL) {
1085 ngx_http_xslt_default_types)
1100 #if (NGX_HAVE_EXSLT)
1117 xsltCleanupGlobals();