comparison src/http/modules/ngx_http_xslt_filter_module.c @ 4554:212a0251951b

Added xslt_param and xslt_string_param directives. Based on patch by Samuel Behan.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 22 Mar 2012 10:44:00 +0000
parents 3dd8a403faa1
children 1a11e4a8877a
comparison
equal deleted inserted replaced
4553:3dd8a403faa1 4554:212a0251951b
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,
467 return NULL; 493 return NULL;
468 } 494 }
469 495
470 for (i = 0; i < conf->sheets.nelts; i++) { 496 for (i = 0; i < conf->sheets.nelts; i++) {
471 497
472 if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) { 498 ctx->transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
499 if (ctx->transform == NULL) {
473 xmlFreeDoc(doc); 500 xmlFreeDoc(doc);
474 return NULL; 501 return NULL;
475 } 502 }
476 503
477 res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts); 504 if (conf->params
478 505 && ngx_http_xslt_params(r, ctx, conf->params, 0) != NGX_OK)
506 {
507 xsltFreeTransformContext(ctx->transform);
508 xmlFreeDoc(doc);
509 return NULL;
510 }
511
512 if (ngx_http_xslt_params(r, ctx, &sheet[i].params, 1) != NGX_OK) {
513 xsltFreeTransformContext(ctx->transform);
514 xmlFreeDoc(doc);
515 return NULL;
516 }
517
518 res = xsltApplyStylesheetUser(sheet[i].stylesheet, doc,
519 ctx->params.elts, NULL, NULL,
520 ctx->transform);
521
522 xsltFreeTransformContext(ctx->transform);
479 xmlFreeDoc(doc); 523 xmlFreeDoc(doc);
480 524
481 if (res == NULL) { 525 if (res == NULL) {
482 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 526 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
483 "xsltApplyStylesheet() failed"); 527 "xsltApplyStylesheet() failed");
563 } 607 }
564 608
565 609
566 static ngx_int_t 610 static ngx_int_t
567 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, 611 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
568 ngx_array_t *params) 612 ngx_array_t *params, ngx_uint_t final)
569 { 613 {
570 u_char *p, *last, *value, *dst, *src, **s; 614 u_char *p, *last, *value, *dst, *src, **s;
571 size_t len; 615 size_t len;
572 ngx_uint_t i; 616 ngx_uint_t i;
573 ngx_str_t string; 617 ngx_str_t string;
574 ngx_http_complex_value_t *param; 618 ngx_http_xslt_param_t *param;
575 619
576 param = params->elts; 620 param = params->elts;
577 621
578 for (i = 0; i < params->nelts; i++) { 622 for (i = 0; i < params->nelts; i++) {
579 623
580 if (ngx_http_complex_value(r, &param[i], &string) != NGX_OK) { 624 if (ngx_http_complex_value(r, &param[i].value, &string) != NGX_OK) {
581 return NGX_ERROR; 625 return NGX_ERROR;
582 } 626 }
583 627
584 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 628 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
585 "xslt filter param: \"%s\"", string.data); 629 "xslt filter param: \"%s\"", string.data);
630
631 if (param[i].name) {
632
633 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
634 "xslt filter param name: \"%s\"", param[i].name);
635
636 if (param[i].quote) {
637 if (xsltQuoteOneUserParam(ctx->transform, param[i].name,
638 string.data)
639 != 0)
640 {
641 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
642 "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
643 param[i].name, string.data);
644 return NGX_ERROR;
645 }
646
647 continue;
648 }
649
650 s = ngx_array_push(&ctx->params);
651 if (s == NULL) {
652 return NGX_ERROR;
653 }
654
655 *s = param[i].name;
656
657 s = ngx_array_push(&ctx->params);
658 if (s == NULL) {
659 return NGX_ERROR;
660 }
661
662 *s = string.data;
663
664 continue;
665 }
666
667 /*
668 * parse param1=value1:param2=value2 syntax as used by parameters
669 * specified in xslt_stylesheet directives
670 */
586 671
587 p = string.data; 672 p = string.data;
588 last = string.data + string.len; 673 last = string.data + string.len;
589 674
590 while (p && *p) { 675 while (p && *p) {
639 724
640 *s = value; 725 *s = value;
641 } 726 }
642 } 727 }
643 728
644 s = ngx_array_push(&ctx->params); 729 if (final) {
645 if (s == NULL) { 730 s = ngx_array_push(&ctx->params);
646 return NGX_ERROR; 731 if (s == NULL) {
647 } 732 return NGX_ERROR;
648 733 }
649 *s = NULL; 734
735 *s = NULL;
736 }
650 737
651 return NGX_OK; 738 return NGX_OK;
652 } 739 }
653 740
654 741
766 ngx_str_t *value; 853 ngx_str_t *value;
767 ngx_uint_t i, n; 854 ngx_uint_t i, n;
768 ngx_pool_cleanup_t *cln; 855 ngx_pool_cleanup_t *cln;
769 ngx_http_xslt_file_t *file; 856 ngx_http_xslt_file_t *file;
770 ngx_http_xslt_sheet_t *sheet; 857 ngx_http_xslt_sheet_t *sheet;
771 ngx_http_complex_value_t *param; 858 ngx_http_xslt_param_t *param;
772 ngx_http_compile_complex_value_t ccv; 859 ngx_http_compile_complex_value_t ccv;
773 ngx_http_xslt_filter_main_conf_t *xmcf; 860 ngx_http_xslt_filter_main_conf_t *xmcf;
774 861
775 value = cf->args->elts; 862 value = cf->args->elts;
776 863
835 if (n == 2) { 922 if (n == 2) {
836 return NGX_CONF_OK; 923 return NGX_CONF_OK;
837 } 924 }
838 925
839 if (ngx_array_init(&sheet->params, cf->pool, n - 2, 926 if (ngx_array_init(&sheet->params, cf->pool, n - 2,
840 sizeof(ngx_http_complex_value_t)) 927 sizeof(ngx_http_xslt_param_t))
841 != NGX_OK) 928 != NGX_OK)
842 { 929 {
843 return NGX_CONF_ERROR; 930 return NGX_CONF_ERROR;
844 } 931 }
845 932
848 param = ngx_array_push(&sheet->params); 935 param = ngx_array_push(&sheet->params);
849 if (param == NULL) { 936 if (param == NULL) {
850 return NGX_CONF_ERROR; 937 return NGX_CONF_ERROR;
851 } 938 }
852 939
940 ngx_memzero(param, sizeof(ngx_http_xslt_param_t));
853 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 941 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
854 942
855 ccv.cf = cf; 943 ccv.cf = cf;
856 ccv.value = &value[i]; 944 ccv.value = &value[i];
857 ccv.complex_value = param; 945 ccv.complex_value = &param->value;
858 ccv.zero = 1; 946 ccv.zero = 1;
859 947
860 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 948 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
861 return NGX_CONF_ERROR; 949 return NGX_CONF_ERROR;
862 } 950 }
951 }
952
953 return NGX_CONF_OK;
954 }
955
956
957 static char *
958 ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
959 {
960 ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
961
962 ngx_http_xslt_param_t *param;
963 ngx_http_compile_complex_value_t ccv;
964 ngx_str_t *value;
965
966 value = cf->args->elts;
967
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;
973 }
974 }
975
976 param = ngx_array_push(xlcf->params);
977 if (param == NULL) {
978 return NGX_CONF_ERROR;
979 }
980
981 param->name = value[1].data;
982 param->quote = (cmd->post == NULL) ? 0 : 1;
983
984 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
985
986 ccv.cf = cf;
987 ccv.value = &value[2];
988 ccv.complex_value = &param->value;
989 ccv.zero = 1;
990
991 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
992 return NGX_CONF_ERROR;
863 } 993 }
864 994
865 return NGX_CONF_OK; 995 return NGX_CONF_OK;
866 } 996 }
867 997
923 * 1053 *
924 * conf->dtd = NULL; 1054 * conf->dtd = NULL;
925 * conf->sheets = { NULL }; 1055 * conf->sheets = { NULL };
926 * conf->types = { NULL }; 1056 * conf->types = { NULL };
927 * conf->types_keys = NULL; 1057 * conf->types_keys = NULL;
1058 * conf->params = NULL;
928 */ 1059 */
929 1060
930 return conf; 1061 return conf;
931 } 1062 }
932 1063
941 conf->dtd = prev->dtd; 1072 conf->dtd = prev->dtd;
942 } 1073 }
943 1074
944 if (conf->sheets.nelts == 0) { 1075 if (conf->sheets.nelts == 0) {
945 conf->sheets = prev->sheets; 1076 conf->sheets = prev->sheets;
1077 }
1078
1079 if (conf->params == NULL) {
1080 conf->params = prev->params;
946 } 1081 }
947 1082
948 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, 1083 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
949 &prev->types_keys, &prev->types, 1084 &prev->types_keys, &prev->types,
950 ngx_http_xslt_default_types) 1085 ngx_http_xslt_default_types)