]> granicus.if.org Git - apache/commitdiff
Merge r1628919, r1628950 from trunk:
authorJim Jagielski <jim@apache.org>
Mon, 27 Oct 2014 12:43:46 +0000 (12:43 +0000)
committerJim Jagielski <jim@apache.org>
Mon, 27 Oct 2014 12:43:46 +0000 (12:43 +0000)
mod_substitute: Make maximum line length configurable.

Add docs for new directive SubstituteMaxLineLength
in mod_substitute.

Submitted by: rjung
Reviewed/backported by: jim

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1634523 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
docs/manual/mod/mod_substitute.xml
modules/filters/mod_substitute.c

diff --git a/CHANGES b/CHANGES
index a9250e06762bb813d68e4ad512f950476c70214f..aaf79ae4feec882041af78ad64b7b5a989bbaaad 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 
 Changes with Apache 2.4.11
 
+  *) mod_substitute: Make maximum line length configurable.  [Rainer Jung]
+
   *) mod_substitute: Fix line length limitation in case of regexp plus flatten.
      [Rainer Jung]
   
diff --git a/STATUS b/STATUS
index 8f947edca90b0720bb3bee36a275526c8b2442ec..35b236b8ddeb7d4ba19213445edb615aa211f2cc 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -102,12 +102,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-   * mod_substitute: Make maximum line length configurable.
-     trunk patch: http://svn.apache.org/r1628919
-                  http://svn.apache.org/r1628950 (docs, adjust "compatibility")
-     2.4.x patch: trunk works modulo CHANGES and compatibility
-     +1: rjung, covener, jim
-
    * mod_substitute: Restrict configuration in .htaccess to
      FileInfo as documented.
      trunk patch: http://svn.apache.org/r1628924
index 3c275decad598cced30adfa75bd590db7915dacb..51c6530119696291af863a2184c2d83a392b049b 100644 (file)
@@ -130,4 +130,37 @@ Substitute "s|http://internal.blog.example.com/|http://www.example.com/blog/|i"
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SubstituteMaxLineLength</name>
+<description>Set the maximum line size</description>
+<syntax>SubstituteMaxLineLength <var>bytes</var>(b|B|k|K|m|M|g|G)</syntax>
+<default>SubstituteMaxLineLength 1m</default>
+<contextlist><context>directory</context>
+<context>.htaccess</context></contextlist>
+<override>FileInfo</override>
+<compatibility>Available in httpd 2.5-dev and later</compatibility>
+
+<usage>
+    <p>The maximum line size handled by <module>mod_substitute</module>
+    is limited to restrict memory use. The limit can be configured
+    using <directive>SubstituteMaxLineLength</directive>.
+    The value can be given as the number of bytes and can be suffixed
+    with a single letter <code>b</code>, <code>B</code>, <code>k</code>,
+    <code>K</code>, <code>m</code>, <code>M</code>, <code>g</code>,
+    <code>G</code> to provide the size in bytes, kilobytes, megabytes
+    or gigabytes respectively.</p>
+
+    <example><title>Example</title>
+    <highlight language="config">
+&lt;Location /&gt;
+    AddOutputFilterByType SUBSTITUTE text/html
+    SubstituteMaxLineLength 10m
+    Substitute s/foo/bar/ni
+&lt;/Location&gt;
+        </highlight>
+    </example>
+
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index 0a8037b5e9b6b89b75c06e27e8a7895f9a10e201..9cebb916305708756e3b303b524e7cdc660c7ec3 100644 (file)
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
 
+/*
+ * We want to limit the memory usage in a way that is predictable.
+ * Therefore we limit the resulting length of the line.
+ * This is the default value.
+ */
+#define AP_SUBST_MAX_LINE_LENGTH (128*MAX_STRING_LEN)
+
 static const char substitute_filter_name[] = "SUBSTITUTE";
 
 module AP_MODULE_DECLARE_DATA substitute_module;
@@ -48,6 +55,8 @@ typedef struct subst_pattern_t {
 
 typedef struct {
     apr_array_header_t *patterns;
+    apr_size_t max_line_length;
+    int max_line_length_set;
 } subst_dir_conf;
 
 typedef struct {
@@ -64,6 +73,7 @@ static void *create_substitute_dcfg(apr_pool_t *p, char *d)
     (subst_dir_conf *) apr_pcalloc(p, sizeof(subst_dir_conf));
 
     dcfg->patterns = apr_array_make(p, 10, sizeof(subst_pattern_t));
+    dcfg->max_line_length = AP_SUBST_MAX_LINE_LENGTH;
     return dcfg;
 }
 
@@ -76,15 +86,14 @@ static void *merge_substitute_dcfg(apr_pool_t *p, void *basev, void *overv)
 
     a->patterns = apr_array_append(p, over->patterns,
                                                   base->patterns);
+    a->max_line_length = over->max_line_length_set ?
+                         over->max_line_length : base->max_line_length;
+    a->max_line_length_set = over->max_line_length_set ?
+                             over->max_line_length_set : base->max_line_length_set;
     return a;
 }
 
 #define AP_MAX_BUCKETS 1000
-/*
- * We want to limit the memory usage in a way that is predictable. Therefore
- * we limit the resulting length of the line to this value.
- */
-#define AP_SUBST_MAX_LINE_LENGTH (128*MAX_STRING_LEN)
 
 #define SEDRMPATBCKT(b, offset, tmp_b, patlen) do {  \
     apr_bucket_split(b, offset);                     \
@@ -143,9 +152,9 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb,
                     const char *repl;
                     /*
                      * space_left counts how many bytes we have left until the
-                     * line length reaches AP_SUBST_MAX_LINE_LENGTH.
+                     * line length reaches max_line_length.
                      */
-                    apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH;
+                    apr_size_t space_left = cfg->max_line_length;
                     apr_size_t repl_len = strlen(script->replacement);
                     while ((repl = apr_strmatch(script->pattern, buff, bytes)))
                     {
@@ -161,7 +170,7 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb,
                              * are constanting allocing space and copying
                              * strings.
                              */
-                            if (vb.strlen + len + repl_len > AP_SUBST_MAX_LINE_LENGTH)
+                            if (vb.strlen + len + repl_len > cfg->max_line_length)
                                 return APR_ENOMEM;
                             ap_varbuf_strmemcat(&vb, buff, len);
                             ap_varbuf_strmemcat(&vb, script->replacement, repl_len);
@@ -228,21 +237,21 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb,
                     int left = bytes;
                     const char *pos = buff;
                     char *repl;
-                    apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH;
+                    apr_size_t space_left = cfg->max_line_length;
                     while (!ap_regexec_len(script->regexp, pos, left,
                                        AP_MAX_REG_MATCH, regm, 0)) {
                         apr_status_t rv;
                         have_match = 1;
                         if (script->flatten && !force_quick) {
                             /* copy bytes before the match */
-                            if (vb.strlen + regm[0].rm_so >= AP_SUBST_MAX_LINE_LENGTH)
+                            if (vb.strlen + regm[0].rm_so >= cfg->max_line_length)
                                 return APR_ENOMEM;
                             if (regm[0].rm_so > 0)
                                 ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so);
                             /* add replacement string, last argument is unsigned! */
                             rv = ap_varbuf_regsub(&vb, script->replacement, pos,
                                                   AP_MAX_REG_MATCH, regm,
-                                                  AP_SUBST_MAX_LINE_LENGTH - vb.strlen);
+                                                  cfg->max_line_length - vb.strlen);
                             if (rv != APR_SUCCESS)
                                 return rv;
                         }
@@ -311,6 +320,9 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
     apr_bucket *tmp_b;
     apr_bucket_brigade *tmp_bb = NULL;
     apr_status_t rv;
+    subst_dir_conf *cfg =
+    (subst_dir_conf *) ap_get_module_config(f->r->per_dir_config,
+                                             &substitute_module);
 
     substitute_module_ctx *ctx = f->ctx;
 
@@ -383,7 +395,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                                           &fbytes, ctx->tpool);
                 if (rv != APR_SUCCESS)
                     goto err;
-                if (fbytes > AP_SUBST_MAX_LINE_LENGTH) {
+                if (fbytes > cfg->max_line_length) {
                     rv = APR_ENOMEM;
                     goto err;
                 }
@@ -449,7 +461,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                                                       &fbytes, ctx->tpool);
                             if (rv != APR_SUCCESS)
                                 goto err;
-                            if (fbytes > AP_SUBST_MAX_LINE_LENGTH) {
+                            if (fbytes > cfg->max_line_length) {
                                 /* Avoid pflattening further lines, we will
                                  * abort later on anyway.
                                  */
@@ -629,6 +641,44 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line)
     return NULL;
 }
 
+#define KBYTE         1024
+#define MBYTE         1048576
+#define GBYTE         1073741824
+
+static const char *set_max_line_length(cmd_parms *cmd, void *cfg, const char *arg)
+{
+    subst_dir_conf *dcfg = (subst_dir_conf *)cfg;
+    apr_off_t max;
+    char *end;
+    apr_status_t rv;
+
+    rv = apr_strtoff(&max, arg, &end, 10);
+    if (rv == APR_SUCCESS) {
+        if ((*end == 'K' || *end == 'k') && !end[1]) {
+            max *= KBYTE;
+        }
+        else if ((*end == 'M' || *end == 'm') && !end[1]) {
+            max *= MBYTE;
+        }
+        else if ((*end == 'G' || *end == 'g') && !end[1]) {
+            max *= GBYTE;
+        }
+        else if (*end && /* neither empty nor [Bb] */
+                 ((*end != 'B' && *end != 'b') || end[1])) {
+            rv = APR_EGENERAL;
+        }
+    }
+
+    if (rv != APR_SUCCESS || max < 0)
+    {
+        return "SubstituteMaxLineLength must be a non-negative integer optionally "
+               "suffixed with 'k', 'm' or 'g'.";
+    }
+    dcfg->max_line_length = (apr_size_t)max;
+    dcfg->max_line_length_set = 1;
+    return NULL;
+}
+
 #define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
 static void register_hooks(apr_pool_t *pool)
 {
@@ -639,6 +689,8 @@ static void register_hooks(apr_pool_t *pool)
 static const command_rec substitute_cmds[] = {
     AP_INIT_TAKE1("Substitute", set_pattern, NULL, OR_ALL,
                   "Pattern to filter the response content (s/foo/bar/[inf])"),
+    AP_INIT_TAKE1("SubstituteMaxLineLength", set_max_line_length, NULL, OR_ALL,
+                  "Maximum line length"),
     {NULL}
 };