Added xslt_param and xslt_string_param directives.
Based on patch by Samuel Behan.
Maxim Dounin
10 years ago
13 | 13 | #include <libxslt/xslt.h> |
14 | 14 | #include <libxslt/xsltInternals.h> |
15 | 15 | #include <libxslt/transform.h> |
16 | #include <libxslt/variables.h> | |
16 | 17 | #include <libxslt/xsltutils.h> |
17 | 18 | |
18 | 19 | #if (NGX_HAVE_EXSLT) |
26 | 27 | |
27 | 28 | |
28 | 29 | typedef struct { |
29 | u_char *name; | |
30 | void *data; | |
30 | u_char *name; | |
31 | void *data; | |
31 | 32 | } ngx_http_xslt_file_t; |
32 | 33 | |
33 | 34 | |
34 | 35 | typedef struct { |
35 | ngx_array_t dtd_files; /* ngx_http_xslt_file_t */ | |
36 | ngx_array_t sheet_files; /* ngx_http_xslt_file_t */ | |
36 | ngx_array_t dtd_files; /* ngx_http_xslt_file_t */ | |
37 | ngx_array_t sheet_files; /* ngx_http_xslt_file_t */ | |
37 | 38 | } ngx_http_xslt_filter_main_conf_t; |
38 | 39 | |
39 | 40 | |
40 | 41 | typedef struct { |
41 | xsltStylesheetPtr stylesheet; | |
42 | ngx_array_t params; /* ngx_http_complex_value_t */ | |
42 | u_char *name; | |
43 | ngx_http_complex_value_t value; | |
44 | ngx_uint_t quote; /* unsigned quote:1; */ | |
45 | } ngx_http_xslt_param_t; | |
46 | ||
47 | ||
48 | typedef struct { | |
49 | xsltStylesheetPtr stylesheet; | |
50 | ngx_array_t params; /* ngx_http_xslt_param_t */ | |
43 | 51 | } ngx_http_xslt_sheet_t; |
44 | 52 | |
45 | 53 | |
46 | 54 | typedef struct { |
47 | xmlDtdPtr dtd; | |
48 | ngx_array_t sheets; /* ngx_http_xslt_sheet_t */ | |
49 | ngx_hash_t types; | |
50 | ngx_array_t *types_keys; | |
55 | xmlDtdPtr dtd; | |
56 | ngx_array_t sheets; /* ngx_http_xslt_sheet_t */ | |
57 | ngx_hash_t types; | |
58 | ngx_array_t *types_keys; | |
59 | ngx_array_t *params; /* ngx_http_xslt_param_t */ | |
51 | 60 | } ngx_http_xslt_filter_loc_conf_t; |
52 | 61 | |
53 | 62 | |
54 | 63 | typedef struct { |
55 | xmlDocPtr doc; | |
56 | xmlParserCtxtPtr ctxt; | |
57 | ngx_http_request_t *request; | |
58 | ngx_array_t params; | |
59 | ||
60 | ngx_uint_t done; /* unsigned done:1; */ | |
64 | xmlDocPtr doc; | |
65 | xmlParserCtxtPtr ctxt; | |
66 | xsltTransformContextPtr transform; | |
67 | ngx_http_request_t *request; | |
68 | ngx_array_t params; | |
69 | ||
70 | ngx_uint_t done; /* unsigned done:1; */ | |
61 | 71 | } ngx_http_xslt_filter_ctx_t; |
62 | 72 | |
63 | 73 | |
75 | 85 | static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r, |
76 | 86 | ngx_http_xslt_filter_ctx_t *ctx); |
77 | 87 | static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, |
78 | ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params); | |
88 | ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final); | |
79 | 89 | static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s); |
80 | 90 | static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s); |
81 | 91 | static void ngx_http_xslt_cleanup(void *data); |
83 | 93 | static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, |
84 | 94 | void *conf); |
85 | 95 | static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, |
96 | void *conf); | |
97 | static char *ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, | |
86 | 98 | void *conf); |
87 | 99 | static void ngx_http_xslt_cleanup_dtd(void *data); |
88 | 100 | static void ngx_http_xslt_cleanup_stylesheet(void *data); |
115 | 127 | NGX_HTTP_LOC_CONF_OFFSET, |
116 | 128 | 0, |
117 | 129 | NULL }, |
130 | ||
131 | { ngx_string("xslt_param"), | |
132 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
133 | ngx_http_xslt_param, | |
134 | NGX_HTTP_LOC_CONF_OFFSET, | |
135 | 0, | |
136 | NULL }, | |
137 | ||
138 | { ngx_string("xslt_string_param"), | |
139 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
140 | ngx_http_xslt_param, | |
141 | NGX_HTTP_LOC_CONF_OFFSET, | |
142 | 0, | |
143 | (void *) 1 }, | |
118 | 144 | |
119 | 145 | { ngx_string("xslt_types"), |
120 | 146 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, |
468 | 494 | |
469 | 495 | for (i = 0; i < conf->sheets.nelts; i++) { |
470 | 496 | |
471 | 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) { | |
472 | 499 | xmlFreeDoc(doc); |
473 | 500 | return NULL; |
474 | 501 | } |
475 | 502 | |
476 | res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts); | |
477 | ||
503 | if (conf->params | |
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); | |
478 | 522 | xmlFreeDoc(doc); |
479 | 523 | |
480 | 524 | if (res == NULL) { |
564 | 608 | |
565 | 609 | static ngx_int_t |
566 | 610 | ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, |
567 | ngx_array_t *params) | |
568 | { | |
569 | u_char *p, *last, *value, *dst, *src, **s; | |
570 | size_t len; | |
571 | ngx_uint_t i; | |
572 | ngx_str_t string; | |
573 | ngx_http_complex_value_t *param; | |
611 | ngx_array_t *params, ngx_uint_t final) | |
612 | { | |
613 | u_char *p, *last, *value, *dst, *src, **s; | |
614 | size_t len; | |
615 | ngx_uint_t i; | |
616 | ngx_str_t string; | |
617 | ngx_http_xslt_param_t *param; | |
574 | 618 | |
575 | 619 | param = params->elts; |
576 | 620 | |
577 | 621 | for (i = 0; i < params->nelts; i++) { |
578 | 622 | |
579 | if (ngx_http_complex_value(r, ¶m[i], &string) != NGX_OK) { | |
623 | if (ngx_http_complex_value(r, ¶m[i].value, &string) != NGX_OK) { | |
580 | 624 | return NGX_ERROR; |
581 | 625 | } |
582 | 626 | |
583 | 627 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
584 | 628 | "xslt filter param: \"%s\"", string.data); |
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 | */ | |
585 | 670 | |
586 | 671 | p = string.data; |
587 | 672 | last = string.data + string.len; |
640 | 725 | } |
641 | 726 | } |
642 | 727 | |
643 | s = ngx_array_push(&ctx->params); | |
644 | if (s == NULL) { | |
645 | return NGX_ERROR; | |
646 | } | |
647 | ||
648 | *s = NULL; | |
728 | if (final) { | |
729 | s = ngx_array_push(&ctx->params); | |
730 | if (s == NULL) { | |
731 | return NGX_ERROR; | |
732 | } | |
733 | ||
734 | *s = NULL; | |
735 | } | |
649 | 736 | |
650 | 737 | return NGX_OK; |
651 | 738 | } |
767 | 854 | ngx_pool_cleanup_t *cln; |
768 | 855 | ngx_http_xslt_file_t *file; |
769 | 856 | ngx_http_xslt_sheet_t *sheet; |
770 | ngx_http_complex_value_t *param; | |
857 | ngx_http_xslt_param_t *param; | |
771 | 858 | ngx_http_compile_complex_value_t ccv; |
772 | 859 | ngx_http_xslt_filter_main_conf_t *xmcf; |
773 | 860 | |
836 | 923 | } |
837 | 924 | |
838 | 925 | if (ngx_array_init(&sheet->params, cf->pool, n - 2, |
839 | sizeof(ngx_http_complex_value_t)) | |
926 | sizeof(ngx_http_xslt_param_t)) | |
840 | 927 | != NGX_OK) |
841 | 928 | { |
842 | 929 | return NGX_CONF_ERROR; |
849 | 936 | return NGX_CONF_ERROR; |
850 | 937 | } |
851 | 938 | |
939 | ngx_memzero(param, sizeof(ngx_http_xslt_param_t)); | |
852 | 940 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
853 | 941 | |
854 | 942 | ccv.cf = cf; |
855 | 943 | ccv.value = &value[i]; |
856 | ccv.complex_value = param; | |
944 | ccv.complex_value = ¶m->value; | |
857 | 945 | ccv.zero = 1; |
858 | 946 | |
859 | 947 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { |
860 | 948 | return NGX_CONF_ERROR; |
861 | 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 = ¶m->value; | |
988 | ccv.zero = 1; | |
989 | ||
990 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { | |
991 | return NGX_CONF_ERROR; | |
862 | 992 | } |
863 | 993 | |
864 | 994 | return NGX_CONF_OK; |
924 | 1054 | * conf->sheets = { NULL }; |
925 | 1055 | * conf->types = { NULL }; |
926 | 1056 | * conf->types_keys = NULL; |
1057 | * conf->params = NULL; | |
927 | 1058 | */ |
928 | 1059 | |
929 | 1060 | return conf; |
942 | 1073 | |
943 | 1074 | if (conf->sheets.nelts == 0) { |
944 | 1075 | conf->sheets = prev->sheets; |
1076 | } | |
1077 | ||
1078 | if (conf->params == NULL) { | |
1079 | conf->params = prev->params; | |
945 | 1080 | } |
946 | 1081 | |
947 | 1082 | if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, |