Mercurial > hg > nginx
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, ¶m[i], &string) != NGX_OK) { | 624 if (ngx_http_complex_value(r, ¶m[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 = ¶m->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 = ¶m->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) |