You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@apache.org on 2017/12/31 16:09:45 UTC
svn commit: r1819739 - in /httpd/httpd/trunk: CHANGES
docs/manual/mod/mod_substitute.xml modules/filters/mod_substitute.c
Author: covener
Date: Sun Dec 31 16:09:44 2017
New Revision: 1819739
URL: http://svn.apache.org/viewvc?rev=1819739&view=rev
Log:
mod_substitute: allow opt-in to expressions in substitution value
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/docs/manual/mod/mod_substitute.xml
httpd/httpd/trunk/modules/filters/mod_substitute.c
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1819739&r1=1819738&r2=1819739&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sun Dec 31 16:09:44 2017
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.1
+ *) mod_susbtitute: Allow expressions in the subtitution, prefixed with expr=
+ [Eric Covener]
+
*) mod_md: fixed mem pool usage for auto-added server names. Added
error logging of exact ACME response when challenges failed.
[Stefan Eissing]
Modified: httpd/httpd/trunk/docs/manual/mod/mod_substitute.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_substitute.xml?rev=1819739&r1=1819738&r2=1819739&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_substitute.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_substitute.xml Sun Dec 31 16:09:44 2017
@@ -41,6 +41,7 @@
<contextlist><context>directory</context>
<context>.htaccess</context></contextlist>
<override>FileInfo</override>
+<compatibility>"expr=" substitution values were added in 2.5.1</compatibility>
<usage>
<p>The <directive>Substitute</directive> directive specifies a
@@ -69,8 +70,11 @@
or regex of a subsequent one.</dd>
</dl>
- <p>The <var>substitution</var> is may contain literal text and regular
- expression backreferences</p>
+ <p>The <var>substitution</var> may contain literal text and regular
+ expression backreferences. If the substitution begins with the text
+ <code>expr=</code> it is intepreted as an <a href="../expr.html">
+ expression</a> which allows access to environment variables and
+ header values. </p>
<example><title>Example</title>
<highlight language="config">
@@ -111,6 +115,26 @@
</highlight>
</example>
+ <p> When using an <a href="../expr.html">expression</a> for the
+ <var>substitution</var>, regular expression backreferences must be
+ backslash ('\') escaped as illustrated in the example below:</p>
+ <example><title>Expression Example</title>
+ <highlight language="config">
+<Location "/">
+ AddOutputFilterByType SUBSTITUTE text/html
+ Substitute "s/example.com/expr=%{HTTP:HOST}/i"
+ Substitute "s/Hello, (\S+)/expr=Hello from %{REQUEST_URI}, \$1,/i"
+</Location>
+ </highlight>
+ </example>
+
+ <note type="warning"><title>Expressions and caching</title>
+ <p>Caution must be exercised when performing substitutions that reference
+ HTTP request headers. Because this module operates after response headers
+ have been sent, the <a href="../expr.html">expression parser</a> cannot add
+ referenced HTTP request headers to the outgoing Vary header. </p>
+ </note>
+
<p>A common use scenario for <code>mod_substitute</code> is the
situation in which a front-end server proxies requests to a back-end
server which returns HTML with hard-coded embedded URLs that refer
Modified: httpd/httpd/trunk/modules/filters/mod_substitute.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_substitute.c?rev=1819739&r1=1819738&r2=1819739&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/filters/mod_substitute.c (original)
+++ httpd/httpd/trunk/modules/filters/mod_substitute.c Sun Dec 31 16:09:44 2017
@@ -30,6 +30,7 @@
#include "util_varbuf.h"
#include "apr_buckets.h"
#include "http_request.h"
+#include "ap_expr.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -52,6 +53,7 @@ typedef struct subst_pattern_t {
apr_size_t patlen;
int flatten;
const char *from;
+ ap_expr_info_t* expr_replacement;
} subst_pattern_t;
typedef struct {
@@ -69,6 +71,11 @@ typedef struct {
apr_pool_t *tpool;
} substitute_module_ctx;
+typedef struct {
+ const char **expcache;
+ int *expcache_len;
+} subst_req_t;
+
static void *create_substitute_dcfg(apr_pool_t *p, char *d)
{
subst_dir_conf *dcfg =
@@ -137,11 +144,14 @@ static apr_status_t do_pattmatch(ap_filt
struct ap_varbuf vb;
apr_bucket *b;
apr_bucket *tmp_b;
+ subst_pattern_t *script;
subst_dir_conf *cfg =
(subst_dir_conf *) ap_get_module_config(f->r->per_dir_config,
&substitute_module);
- subst_pattern_t *script;
+ subst_req_t *rconf =
+ (subst_req_t*) ap_get_module_config(f->r->request_config,
+ &substitute_module);
APR_BRIGADE_INSERT_TAIL(mybb, inb);
ap_varbuf_init(pool, &vb, 0);
@@ -155,6 +165,16 @@ static apr_status_t do_pattmatch(ap_filt
force_quick = 1;
}
for (i = 0; i < cfg->patterns->nelts; i++) {
+ const char *replacement = script->replacement;
+ apr_size_t replen = script->replen;
+ if (script->expr_replacement) {
+ if (!rconf) {
+ rconf = apr_pcalloc(f->r->pool, sizeof(*rconf));
+ rconf->expcache = apr_pcalloc(f->r->pool, sizeof(const char*) * cfg->patterns->nelts);
+ rconf->expcache_len = apr_pcalloc(f->r->pool, sizeof(int) * cfg->patterns->nelts);
+ ap_set_module_config(f->r->request_config, &substitute_module, rconf);
+ }
+ }
for (b = APR_BRIGADE_FIRST(mybb);
b != APR_BRIGADE_SENTINEL(mybb);
b = APR_BUCKET_NEXT(b)) {
@@ -187,12 +207,26 @@ static apr_status_t do_pattmatch(ap_filt
* line length reaches 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)))
{
+
+ if (!have_match && script->expr_replacement) {
+ if (!rconf->expcache[i]) {
+ const char *err = NULL;
+ rconf->expcache[i] = ap_expr_str_exec(f->r, script->expr_replacement, &err);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "error evaluating expression: %s", err);
+ return APR_EINVAL;
+ }
+ rconf->expcache_len[i] = strlen(rconf->expcache[i]);
+ }
+ replacement = rconf->expcache[i];
+ replen = rconf->expcache_len[i];
+ }
+
ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, f->r,
"Matching found, result: '%s'",
- script->replacement);
+ replacement);
have_match = 1;
/* get offset into buff for pattern */
len = (apr_size_t) (repl - buff);
@@ -205,10 +239,10 @@ static apr_status_t do_pattmatch(ap_filt
* are constanting allocing space and copying
* strings.
*/
- if (vb.strlen + len + repl_len > cfg->max_line_length)
+ if (vb.strlen + len + replen > cfg->max_line_length)
return APR_ENOMEM;
ap_varbuf_strmemcat(&vb, buff, len);
- ap_varbuf_strmemcat(&vb, script->replacement, repl_len);
+ ap_varbuf_strmemcat(&vb, replacement, replen);
}
else {
/*
@@ -217,9 +251,9 @@ static apr_status_t do_pattmatch(ap_filt
* Check if we still have space for this string and
* the replacement string.
*/
- if (space_left < len + repl_len)
+ if (space_left < len + replen)
return APR_ENOMEM;
- space_left -= len + repl_len;
+ space_left -= len + replen;
/*
* We now split off the string before the match
* as its own bucket, then isolate the matched
@@ -230,8 +264,8 @@ static apr_status_t do_pattmatch(ap_filt
* Finally, we create a bucket that contains the
* replacement...
*/
- tmp_b = apr_bucket_transient_create(script->replacement,
- script->replen,
+ tmp_b = apr_bucket_transient_create(replacement,
+ replen,
f->r->connection->bucket_alloc);
/* ... and insert it */
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
@@ -282,6 +316,20 @@ static apr_status_t do_pattmatch(ap_filt
while (!ap_regexec_len(script->regexp, pos, left,
AP_MAX_REG_MATCH, regm, 0)) {
apr_status_t rv;
+ if (!have_match && script->expr_replacement) {
+ if (!rconf->expcache[i]) {
+ const char *err = NULL;
+ rconf->expcache[i] = ap_expr_str_exec(f->r, script->expr_replacement, &err);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "error evaluating expression: %s", err);
+ return APR_EGENERAL;
+ }
+ rconf->expcache_len[i] = strlen(rconf->expcache[i]);
+ }
+ replacement = rconf->expcache[i];
+ replen = rconf->expcache_len[i];
+ }
+
ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, f->r,
"Matching found");
have_match = 1;
@@ -296,7 +344,7 @@ static apr_status_t do_pattmatch(ap_filt
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,
+ rv = ap_varbuf_regsub(&vb, replacement, pos,
AP_MAX_REG_MATCH, regm,
cfg->max_line_length - vb.strlen);
if (rv != APR_SUCCESS)
@@ -311,7 +359,7 @@ static apr_status_t do_pattmatch(ap_filt
return APR_ENOMEM;
space_left -= regm[0].rm_so;
rv = ap_pregsub_ex(pool, &repl,
- script->replacement, pos,
+ replacement, pos,
AP_MAX_REG_MATCH, regm,
space_left);
if (rv != APR_SUCCESS)
@@ -692,6 +740,18 @@ static const char *set_pattern(cmd_parms
nscript->replacement = to;
nscript->replen = strlen(to);
+
+ if (!strncasecmp(to, "expr=", 5)) {
+ const char *err;
+ nscript->expr_replacement = ap_expr_parse_cmd(cmd, to+5,
+ AP_EXPR_FLAG_STRING_RESULT,
+ &err, NULL);
+ if (err) {
+ return apr_pstrcat(cmd->pool,
+ "Can't parse value expression : ", err, NULL);
+ }
+ }
+
nscript->flatten = flatten;
return NULL;