comparison src/http/modules/ngx_http_xslt_filter_module.c @ 668:9fbf3ad94cbf NGINX_1_1_18

nginx 1.1.18 *) Change: keepalive connections are no longer disabled for Safari by default. *) Feature: the $connection_requests variable. *) Feature: $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd and $tcpinfo_rcv_space variables. *) Feature: the "worker_cpu_affinity" directive now works on FreeBSD. *) Feature: the "xslt_param" and "xslt_string_param" directives. Thanks to Samuel Behan. *) Bugfix: in configure tests. Thanks to Piotr Sikora. *) Bugfix: in the ngx_http_xslt_filter_module. *) Bugfix: nginx could not be built on Debian GNU/Hurd.
author Igor Sysoev <http://sysoev.ru>
date Wed, 28 Mar 2012 00:00:00 +0400
parents d0f7a625f27c
children bfa81a0490a2
comparison
equal deleted inserted replaced
667:e0eabdb2bad1 668:9fbf3ad94cbf
12 #include <libxml/parser.h> 12 #include <libxml/parser.h>
13 #include <libxml/tree.h> 13 #include <libxml/tree.h>
14 #include <libxslt/xslt.h> 14 #include <libxslt/xslt.h>
15 #include <libxslt/xsltInternals.h> 15 #include <libxslt/xsltInternals.h>
16 #include <libxslt/transform.h> 16 #include <libxslt/transform.h>
17 #include <libxslt/variables.h>
17 #include <libxslt/xsltutils.h> 18 #include <libxslt/xsltutils.h>
18 19
19 #if (NGX_HAVE_EXSLT) 20 #if (NGX_HAVE_EXSLT)
20 #include <libexslt/exslt.h> 21 #include <libexslt/exslt.h>
21 #endif 22 #endif
25 #define NGX_HTTP_XSLT_REUSE_DTD 1 26 #define NGX_HTTP_XSLT_REUSE_DTD 1
26 #endif 27 #endif
27 28
28 29
29 typedef struct { 30 typedef struct {
30 u_char *name; 31 u_char *name;
31 void *data; 32 void *data;
32 } ngx_http_xslt_file_t; 33 } ngx_http_xslt_file_t;
33 34
34 35
35 typedef struct { 36 typedef struct {
36 ngx_array_t dtd_files; /* ngx_http_xslt_file_t */ 37 ngx_array_t dtd_files; /* ngx_http_xslt_file_t */
37 ngx_array_t sheet_files; /* ngx_http_xslt_file_t */ 38 ngx_array_t sheet_files; /* ngx_http_xslt_file_t */
38 } ngx_http_xslt_filter_main_conf_t; 39 } ngx_http_xslt_filter_main_conf_t;
39 40
40 41
41 typedef struct { 42 typedef struct {
42 xsltStylesheetPtr stylesheet; 43 u_char *name;
43 ngx_array_t params; /* ngx_http_complex_value_t */ 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 */
44 } ngx_http_xslt_sheet_t; 52 } ngx_http_xslt_sheet_t;
45 53
46 54
47 typedef struct { 55 typedef struct {
48 xmlDtdPtr dtd; 56 xmlDtdPtr dtd;
49 ngx_array_t sheets; /* ngx_http_xslt_sheet_t */ 57 ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
50 ngx_hash_t types; 58 ngx_hash_t types;
51 ngx_array_t *types_keys; 59 ngx_array_t *types_keys;
60 ngx_array_t *params; /* ngx_http_xslt_param_t */
52 } ngx_http_xslt_filter_loc_conf_t; 61 } ngx_http_xslt_filter_loc_conf_t;
53 62
54 63
55 typedef struct { 64 typedef struct {
56 xmlDocPtr doc; 65 xmlDocPtr doc;
57 xmlParserCtxtPtr ctxt; 66 xmlParserCtxtPtr ctxt;
58 ngx_http_request_t *request; 67 xsltTransformContextPtr transform;
59 ngx_array_t params; 68 ngx_http_request_t *request;
60 69 ngx_array_t params;
61 ngx_uint_t done; /* unsigned done:1; */ 70
71 ngx_uint_t done; /* unsigned done:1; */
62 } ngx_http_xslt_filter_ctx_t; 72 } ngx_http_xslt_filter_ctx_t;
63 73
64 74
65 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, 75 static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
66 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); 76 ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
74 84
75 85
76 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, 86 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
77 ngx_http_xslt_filter_ctx_t *ctx); 87 ngx_http_xslt_filter_ctx_t *ctx);
78 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, 88 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
79 ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params); 89 ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final);
80 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s); 90 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
81 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s); 91 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
82 static void ngx_http_xslt_cleanup(void *data); 92 static void ngx_http_xslt_cleanup(void *data);
83 93
84 static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, 94 static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
85 void *conf); 95 void *conf);
86 static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, 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,
87 void *conf); 99 void *conf);
88 static void ngx_http_xslt_cleanup_dtd(void *data); 100 static void ngx_http_xslt_cleanup_dtd(void *data);
89 static void ngx_http_xslt_cleanup_stylesheet(void *data); 101 static void ngx_http_xslt_cleanup_stylesheet(void *data);
90 static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf); 102 static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
91 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf); 103 static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
114 NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 126 NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
115 ngx_http_xslt_stylesheet, 127 ngx_http_xslt_stylesheet,
116 NGX_HTTP_LOC_CONF_OFFSET, 128 NGX_HTTP_LOC_CONF_OFFSET,
117 0, 129 0,
118 NULL }, 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 },
119 145
120 { ngx_string("xslt_types"), 146 { ngx_string("xslt_types"),
121 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 147 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
122 ngx_http_types_slot, 148 ngx_http_types_slot,
123 NGX_HTTP_LOC_CONF_OFFSET, 149 NGX_HTTP_LOC_CONF_OFFSET,
334 if (ctxt == NULL) { 360 if (ctxt == NULL) {
335 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 361 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
336 "xmlCreatePushParserCtxt() failed"); 362 "xmlCreatePushParserCtxt() failed");
337 return NGX_ERROR; 363 return NGX_ERROR;
338 } 364 }
365 xmlCtxtUseOptions(ctxt, XML_PARSE_NOENT|XML_PARSE_DTDLOAD
366 |XML_PARSE_NOWARNING);
339 367
340 ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset; 368 ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
341 ctxt->sax->setDocumentLocator = NULL; 369 ctxt->sax->setDocumentLocator = NULL;
342 ctxt->sax->warning = NULL;
343 ctxt->sax->error = ngx_http_xslt_sax_error; 370 ctxt->sax->error = ngx_http_xslt_sax_error;
344 ctxt->sax->fatalError = ngx_http_xslt_sax_error; 371 ctxt->sax->fatalError = ngx_http_xslt_sax_error;
345 ctxt->sax->_private = ctx; 372 ctxt->sax->_private = ctx;
346 ctxt->replaceEntities = 1;
347 ctxt->loadsubset = 1;
348 373
349 ctx->ctxt = ctxt; 374 ctx->ctxt = ctxt;
350 ctx->request = r; 375 ctx->request = r;
351 } 376 }
352 377
467 return NULL; 492 return NULL;
468 } 493 }
469 494
470 for (i = 0; i < conf->sheets.nelts; i++) { 495 for (i = 0; i < conf->sheets.nelts; i++) {
471 496
472 if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) { 497 ctx->transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
498 if (ctx->transform == NULL) {
473 xmlFreeDoc(doc); 499 xmlFreeDoc(doc);
474 return NULL; 500 return NULL;
475 } 501 }
476 502
477 res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts); 503 if (conf->params
478 504 && ngx_http_xslt_params(r, ctx, conf->params, 0) != NGX_OK)
505 {
506 xsltFreeTransformContext(ctx->transform);
507 xmlFreeDoc(doc);
508 return NULL;
509 }
510
511 if (ngx_http_xslt_params(r, ctx, &sheet[i].params, 1) != NGX_OK) {
512 xsltFreeTransformContext(ctx->transform);
513 xmlFreeDoc(doc);
514 return NULL;
515 }
516
517 res = xsltApplyStylesheetUser(sheet[i].stylesheet, doc,
518 ctx->params.elts, NULL, NULL,
519 ctx->transform);
520
521 xsltFreeTransformContext(ctx->transform);
479 xmlFreeDoc(doc); 522 xmlFreeDoc(doc);
480 523
481 if (res == NULL) { 524 if (res == NULL) {
482 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 525 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
483 "xsltApplyStylesheet() failed"); 526 "xsltApplyStylesheet() failed");
563 } 606 }
564 607
565 608
566 static ngx_int_t 609 static ngx_int_t
567 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, 610 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
568 ngx_array_t *params) 611 ngx_array_t *params, ngx_uint_t final)
569 { 612 {
570 u_char *p, *last, *value, *dst, *src, **s; 613 u_char *p, *last, *value, *dst, *src, **s;
571 size_t len; 614 size_t len;
572 ngx_uint_t i; 615 ngx_uint_t i;
573 ngx_str_t string; 616 ngx_str_t string;
574 ngx_http_complex_value_t *param; 617 ngx_http_xslt_param_t *param;
575 618
576 param = params->elts; 619 param = params->elts;
577 620
578 for (i = 0; i < params->nelts; i++) { 621 for (i = 0; i < params->nelts; i++) {
579 622
580 if (ngx_http_complex_value(r, &param[i], &string) != NGX_OK) { 623 if (ngx_http_complex_value(r, &param[i].value, &string) != NGX_OK) {
581 return NGX_ERROR; 624 return NGX_ERROR;
582 } 625 }
583 626
584 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 627 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
585 "xslt filter param: \"%s\"", string.data); 628 "xslt filter param: \"%s\"", string.data);
586 629
630 if (param[i].name) {
631
632 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
633 "xslt filter param name: \"%s\"", param[i].name);
634
635 if (param[i].quote) {
636 if (xsltQuoteOneUserParam(ctx->transform, param[i].name,
637 string.data)
638 != 0)
639 {
640 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
641 "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
642 param[i].name, string.data);
643 return NGX_ERROR;
644 }
645
646 continue;
647 }
648
649 s = ngx_array_push(&ctx->params);
650 if (s == NULL) {
651 return NGX_ERROR;
652 }
653
654 *s = param[i].name;
655
656 s = ngx_array_push(&ctx->params);
657 if (s == NULL) {
658 return NGX_ERROR;
659 }
660
661 *s = string.data;
662
663 continue;
664 }
665
666 /*
667 * parse param1=value1:param2=value2 syntax as used by parameters
668 * specified in xslt_stylesheet directives
669 */
670
587 p = string.data; 671 p = string.data;
588 last = string.data + string.len - 1; 672 last = string.data + string.len;
589 673
590 while (p && *p) { 674 while (p && *p) {
591 675
592 value = p; 676 value = p;
593 p = (u_char *) ngx_strchr(p, '='); 677 p = (u_char *) ngx_strchr(p, '=');
639 723
640 *s = value; 724 *s = value;
641 } 725 }
642 } 726 }
643 727
644 s = ngx_array_push(&ctx->params); 728 if (final) {
645 if (s == NULL) { 729 s = ngx_array_push(&ctx->params);
646 return NGX_ERROR; 730 if (s == NULL) {
647 } 731 return NGX_ERROR;
648 732 }
649 *s = NULL; 733
734 *s = NULL;
735 }
650 736
651 return NGX_OK; 737 return NGX_OK;
652 } 738 }
653 739
654 740
766 ngx_str_t *value; 852 ngx_str_t *value;
767 ngx_uint_t i, n; 853 ngx_uint_t i, n;
768 ngx_pool_cleanup_t *cln; 854 ngx_pool_cleanup_t *cln;
769 ngx_http_xslt_file_t *file; 855 ngx_http_xslt_file_t *file;
770 ngx_http_xslt_sheet_t *sheet; 856 ngx_http_xslt_sheet_t *sheet;
771 ngx_http_complex_value_t *param; 857 ngx_http_xslt_param_t *param;
772 ngx_http_compile_complex_value_t ccv; 858 ngx_http_compile_complex_value_t ccv;
773 ngx_http_xslt_filter_main_conf_t *xmcf; 859 ngx_http_xslt_filter_main_conf_t *xmcf;
774 860
775 value = cf->args->elts; 861 value = cf->args->elts;
776 862
835 if (n == 2) { 921 if (n == 2) {
836 return NGX_CONF_OK; 922 return NGX_CONF_OK;
837 } 923 }
838 924
839 if (ngx_array_init(&sheet->params, cf->pool, n - 2, 925 if (ngx_array_init(&sheet->params, cf->pool, n - 2,
840 sizeof(ngx_http_complex_value_t)) 926 sizeof(ngx_http_xslt_param_t))
841 != NGX_OK) 927 != NGX_OK)
842 { 928 {
843 return NGX_CONF_ERROR; 929 return NGX_CONF_ERROR;
844 } 930 }
845 931
848 param = ngx_array_push(&sheet->params); 934 param = ngx_array_push(&sheet->params);
849 if (param == NULL) { 935 if (param == NULL) {
850 return NGX_CONF_ERROR; 936 return NGX_CONF_ERROR;
851 } 937 }
852 938
939 ngx_memzero(param, sizeof(ngx_http_xslt_param_t));
853 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 940 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
854 941
855 ccv.cf = cf; 942 ccv.cf = cf;
856 ccv.value = &value[i]; 943 ccv.value = &value[i];
857 ccv.complex_value = param; 944 ccv.complex_value = &param->value;
858 ccv.zero = 1; 945 ccv.zero = 1;
859 946
860 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 947 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
861 return NGX_CONF_ERROR; 948 return NGX_CONF_ERROR;
862 } 949 }
950 }
951
952 return NGX_CONF_OK;
953 }
954
955
956 static char *
957 ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
958 {
959 ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
960
961 ngx_http_xslt_param_t *param;
962 ngx_http_compile_complex_value_t ccv;
963 ngx_str_t *value;
964
965 value = cf->args->elts;
966
967 if (xlcf->params == NULL) {
968 xlcf->params = ngx_array_create(cf->pool, 2,
969 sizeof(ngx_http_xslt_param_t));
970 if (xlcf->params == NULL) {
971 return NGX_CONF_ERROR;
972 }
973 }
974
975 param = ngx_array_push(xlcf->params);
976 if (param == NULL) {
977 return NGX_CONF_ERROR;
978 }
979
980 param->name = value[1].data;
981 param->quote = (cmd->post == NULL) ? 0 : 1;
982
983 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
984
985 ccv.cf = cf;
986 ccv.value = &value[2];
987 ccv.complex_value = &param->value;
988 ccv.zero = 1;
989
990 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
991 return NGX_CONF_ERROR;
863 } 992 }
864 993
865 return NGX_CONF_OK; 994 return NGX_CONF_OK;
866 } 995 }
867 996
923 * 1052 *
924 * conf->dtd = NULL; 1053 * conf->dtd = NULL;
925 * conf->sheets = { NULL }; 1054 * conf->sheets = { NULL };
926 * conf->types = { NULL }; 1055 * conf->types = { NULL };
927 * conf->types_keys = NULL; 1056 * conf->types_keys = NULL;
1057 * conf->params = NULL;
928 */ 1058 */
929 1059
930 return conf; 1060 return conf;
931 } 1061 }
932 1062
941 conf->dtd = prev->dtd; 1071 conf->dtd = prev->dtd;
942 } 1072 }
943 1073
944 if (conf->sheets.nelts == 0) { 1074 if (conf->sheets.nelts == 0) {
945 conf->sheets = prev->sheets; 1075 conf->sheets = prev->sheets;
1076 }
1077
1078 if (conf->params == NULL) {
1079 conf->params = prev->params;
946 } 1080 }
947 1081
948 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, 1082 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
949 &prev->types_keys, &prev->types, 1083 &prev->types_keys, &prev->types,
950 ngx_http_xslt_default_types) 1084 ngx_http_xslt_default_types)