[PATCH] add xslt_stylesheet_param directive

Maxim Dounin mdounin at mdounin.ru
Fri Mar 2 18:52:36 UTC 2012


Hello!

On Sun, Feb 26, 2012 at 04:15:33PM +0100, SamB wrote:

> Hi,
> 
>   sorry for late response,  had no spare time for this. Here is new patch,
> please review it.
>   I've modified the string_param-enabled - it seems to better fit my
> usage...

Please check the attached patch.  It cleans up some style issues 
and slightly changes parameter processing to be more uniform with 
parameters from xslt_stylesheet directives.

There is also a tiny patch included which fixes long-standing 
off-by-one bug in parsing parameters from xslt_stylesheet 
directives.

Tests are here:
http://mdounin.ru/hg/nginx-tests/rev/6bac00bba8d4

Maxim Dounin
-------------- next part --------------
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1330697803 -14400
# Node ID 4df0e70d82dd2555b2aa076197947f744c4aea44
# Parent  88e257b4bd3d61e30d1421ab6f2e417a8baedb96
Fixed off-by-one in xslt parameter parsing.

The problem was introduced in 0.7.44 (r2589) during conversion to complex
values.  Previously string.len included space for terminating NUL, but
with complex values it doesn't.

diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -585,7 +585,7 @@ ngx_http_xslt_params(ngx_http_request_t 
                        "xslt filter param: \"%s\"", string.data);
 
         p = string.data;
-        last = string.data + string.len - 1;
+        last = string.data + string.len;
 
         while (p && *p) {
 
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1330707634 -14400
# Node ID ceb911a15613cf81f6a3669c8d39aef596ad36e7
# Parent  4df0e70d82dd2555b2aa076197947f744c4aea44
Added xslt_param and xslt_string_param directives.

Based on patch by Samuel Behan.

diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -14,6 +14,7 @@
 #include <libxslt/xslt.h>
 #include <libxslt/xsltInternals.h>
 #include <libxslt/transform.h>
+#include <libxslt/variables.h>
 #include <libxslt/xsltutils.h>
 
 #if (NGX_HAVE_EXSLT)
@@ -27,38 +28,47 @@
 
 
 typedef struct {
-    u_char              *name;
-    void                *data;
+    u_char                    *name;
+    void                      *data;
 } ngx_http_xslt_file_t;
 
 
 typedef struct {
-    ngx_array_t          dtd_files;    /* ngx_http_xslt_file_t */
-    ngx_array_t          sheet_files;  /* ngx_http_xslt_file_t */
+    ngx_array_t                dtd_files;    /* ngx_http_xslt_file_t */
+    ngx_array_t                sheet_files;  /* ngx_http_xslt_file_t */
 } ngx_http_xslt_filter_main_conf_t;
 
 
 typedef struct {
-    xsltStylesheetPtr    stylesheet;
-    ngx_array_t          params;       /* ngx_http_complex_value_t */
+    u_char                    *name;
+    ngx_http_complex_value_t   value;
+    ngx_uint_t                 quote;        /* unsigned  quote:1; */
+} ngx_http_xslt_param_t;
+
+
+typedef struct {
+    xsltStylesheetPtr          stylesheet;
+    ngx_array_t                params;       /* ngx_http_xslt_param_t */
 } ngx_http_xslt_sheet_t;
 
 
 typedef struct {
-    xmlDtdPtr            dtd;
-    ngx_array_t          sheets;       /* ngx_http_xslt_sheet_t */
-    ngx_hash_t           types;
-    ngx_array_t         *types_keys;
+    xmlDtdPtr                  dtd;
+    ngx_array_t                sheets;       /* ngx_http_xslt_sheet_t */
+    ngx_hash_t                 types;
+    ngx_array_t               *types_keys;
+    ngx_array_t               *params;       /* ngx_http_xslt_param_t */
 } ngx_http_xslt_filter_loc_conf_t;
 
 
 typedef struct {
-    xmlDocPtr            doc;
-    xmlParserCtxtPtr     ctxt;
-    ngx_http_request_t  *request;
-    ngx_array_t          params;
+    xmlDocPtr                  doc;
+    xmlParserCtxtPtr           ctxt;
+    xsltTransformContextPtr    transform;
+    ngx_http_request_t        *request;
+    ngx_array_t                params;
 
-    ngx_uint_t           done;         /* unsigned  done:1; */
+    ngx_uint_t                 done;         /* unsigned  done:1; */
 } ngx_http_xslt_filter_ctx_t;
 
 
@@ -76,7 +86,7 @@ static void ngx_cdecl ngx_http_xslt_sax_
 static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
     ngx_http_xslt_filter_ctx_t *ctx);
 static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
-    ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params);
+    ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final);
 static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
 static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
 static void ngx_http_xslt_cleanup(void *data);
@@ -85,6 +95,8 @@ static char *ngx_http_xslt_entities(ngx_
     void *conf);
 static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static void ngx_http_xslt_cleanup_dtd(void *data);
 static void ngx_http_xslt_cleanup_stylesheet(void *data);
 static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
@@ -117,6 +129,20 @@ static ngx_command_t  ngx_http_xslt_filt
       0,
       NULL },
 
+    { ngx_string("xslt_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_http_xslt_param,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("xslt_string_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_http_xslt_param,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      (void *) 1 },
+
     { ngx_string("xslt_types"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_types_slot,
@@ -469,13 +495,31 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
 
     for (i = 0; i < conf->sheets.nelts; i++) {
 
-        if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) {
+        ctx->transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
+        if (ctx->transform == NULL) {
             xmlFreeDoc(doc);
             return NULL;
         }
 
-        res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts);
+        if (conf->params
+            && ngx_http_xslt_params(r, ctx, conf->params, 0) != NGX_OK)
+        {
+            xsltFreeTransformContext(ctx->transform);
+            xmlFreeDoc(doc);
+            return NULL;
+        }
 
+        if (ngx_http_xslt_params(r, ctx, &sheet[i].params, 1) != NGX_OK) {
+            xsltFreeTransformContext(ctx->transform);
+            xmlFreeDoc(doc);
+            return NULL;
+        }
+
+        res = xsltApplyStylesheetUser(sheet[i].stylesheet, doc,
+                                      ctx->params.elts, NULL, NULL,
+                                      ctx->transform);
+
+        xsltFreeTransformContext(ctx->transform);
         xmlFreeDoc(doc);
 
         if (res == NULL) {
@@ -565,25 +609,66 @@ ngx_http_xslt_apply_stylesheet(ngx_http_
 
 static ngx_int_t
 ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
-    ngx_array_t *params)
+    ngx_array_t *params, ngx_uint_t final)
 {
-    u_char                    *p, *last, *value, *dst, *src, **s;
-    size_t                     len;
-    ngx_uint_t                 i;
-    ngx_str_t                  string;
-    ngx_http_complex_value_t  *param;
+    u_char                 *p, *last, *value, *dst, *src, **s;
+    size_t                  len;
+    ngx_uint_t              i;
+    ngx_str_t               string;
+    ngx_http_xslt_param_t  *param;
 
     param = params->elts;
 
     for (i = 0; i < params->nelts; i++) {
 
-        if (ngx_http_complex_value(r, &param[i], &string) != NGX_OK) {
+        if (ngx_http_complex_value(r, &param[i].value, &string) != NGX_OK) {
             return NGX_ERROR;
         }
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "xslt filter param: \"%s\"", string.data);
 
+        if (param[i].name) {
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "xslt filter param name: \"%s\"", param[i].name);
+
+            if (param[i].quote) {
+                if (xsltQuoteOneUserParam(ctx->transform, param[i].name,
+                                          string.data)
+                    != 0)
+                {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
+                                param[i].name, string.data);
+                    return NGX_ERROR;
+                }
+
+                continue;
+            }
+
+            s = ngx_array_push(&ctx->params);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = param[i].name;
+
+            s = ngx_array_push(&ctx->params);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = string.data;
+
+            continue;
+        }
+
+        /*
+         * parse param1=value1:param2=value2 syntax as used by parameters
+         * specified in xslt_stylesheet directives
+         */
+
         p = string.data;
         last = string.data + string.len;
 
@@ -641,13 +726,15 @@ ngx_http_xslt_params(ngx_http_request_t 
         }
     }
 
-    s = ngx_array_push(&ctx->params);
-    if (s == NULL) {
-        return NGX_ERROR;
+    if (final) {
+        s = ngx_array_push(&ctx->params);
+        if (s == NULL) {
+            return NGX_ERROR;
+        }
+
+        *s = NULL;
     }
 
-    *s = NULL;
-
     return NGX_OK;
 }
 
@@ -768,7 +855,7 @@ ngx_http_xslt_stylesheet(ngx_conf_t *cf,
     ngx_pool_cleanup_t                *cln;
     ngx_http_xslt_file_t              *file;
     ngx_http_xslt_sheet_t             *sheet;
-    ngx_http_complex_value_t          *param;
+    ngx_http_xslt_param_t             *param;
     ngx_http_compile_complex_value_t   ccv;
     ngx_http_xslt_filter_main_conf_t  *xmcf;
 
@@ -837,7 +924,7 @@ found:
     }
 
     if (ngx_array_init(&sheet->params, cf->pool, n - 2,
-                       sizeof(ngx_http_complex_value_t))
+                       sizeof(ngx_http_xslt_param_t))
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -850,11 +937,12 @@ found:
             return NGX_CONF_ERROR;
         }
 
+        ngx_memzero(param, sizeof(ngx_http_xslt_param_t));
         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
 
         ccv.cf = cf;
         ccv.value = &value[i];
-        ccv.complex_value = param;
+        ccv.complex_value = &param->value;
         ccv.zero = 1;
 
         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
@@ -866,6 +954,48 @@ found:
 }
 
 
+static char *
+ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_xslt_filter_loc_conf_t  *xlcf = conf;
+
+    ngx_http_xslt_param_t            *param;
+    ngx_http_compile_complex_value_t  ccv;
+    ngx_str_t                        *value;
+
+    value = cf->args->elts;
+
+    if (xlcf->params == NULL) {
+        xlcf->params = ngx_array_create(cf->pool, 2,
+                                        sizeof(ngx_http_xslt_param_t));
+        if (xlcf->params == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    param = ngx_array_push(xlcf->params);
+    if (param == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    param->name = value[1].data;
+    param->quote = (cmd->post == NULL) ? 0 : 1;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[2];
+    ccv.complex_value = &param->value;
+    ccv.zero = 1;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 static void
 ngx_http_xslt_cleanup_dtd(void *data)
 {
@@ -925,6 +1055,7 @@ ngx_http_xslt_filter_create_conf(ngx_con
      *     conf->sheets = { NULL };
      *     conf->types = { NULL };
      *     conf->types_keys = NULL;
+     *     conf->params = NULL;
      */
 
     return conf;
@@ -945,6 +1076,10 @@ ngx_http_xslt_filter_merge_conf(ngx_conf
         conf->sheets = prev->sheets;
     }
 
+    if (conf->params == NULL) {
+        conf->params = prev->params;
+    }
+
     if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                              &prev->types_keys, &prev->types,
                              ngx_http_xslt_default_types)


More information about the nginx-devel mailing list