diff options
author | Ruediger Pluem <rpluem@apache.org> | 2023-03-31 14:33:00 +0000 |
---|---|---|
committer | Ruediger Pluem <rpluem@apache.org> | 2023-03-31 14:33:00 +0000 |
commit | 9b8cf1746bb004050b02a30bf0222479fbe405c2 (patch) | |
tree | 2e26c51335792dff81d5cb009de7f2c83d844928 | |
parent | 386a268201e9424fb3e4be62fe5ff42b441a5760 (diff) | |
download | httpd-9b8cf1746bb004050b02a30bf0222479fbe405c2.tar.gz |
Merge r1908341, r1908628, r1908629 from trunk:
Do not double encode encoded slashes
In case that AllowEncodedSlashes is set to NoDecode do not double encode
encoded slashes in the URL sent by the reverse proxy to the backend.
* include/ap_mmn.h: Document the addition of ap_proxy_canonenc_ex to the API.
* modules/proxy/mod_proxy.h: Declare ap_proxy_canonenc_ex and define flag
values.
* modules/proxy/proxy_util.c: Implement ap_proxy_canonenc_ex by modifying
ap_proxy_canonenc accordingly and reimplement ap_proxy_canonenc to
use ap_proxy_canonenc_ex with the appropriate flag.
* modules/http2/mod_proxy_http2.c, modules/proxy/mod_proxy_*.c: Set the
correct flag based on the AllowEncodedSlashes configuration and use
ap_proxy_canonenc_ex instead of ap_proxy_canonenc.
* Whitespace fixes. No functional change.
* Fix typo
Reviewed by: rpluem, ylavic, covener
Github: closes #351
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908864 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | STATUS | 12 | ||||
-rw-r--r-- | include/ap_mmn.h | 4 | ||||
-rw-r--r-- | modules/http2/mod_proxy_http2.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.h | 6 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ajp.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_balancer.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_fcgi.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ftp.c | 5 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_http.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_scgi.c | 6 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_uwsgi.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_wstunnel.c | 7 | ||||
-rw-r--r-- | modules/proxy/proxy_util.c | 39 |
14 files changed, 89 insertions, 36 deletions
@@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.57 + *) mod_proxy: In case that AllowEncodedSlashes is set to NoDecode do not + double encode encoded slashes in the URL sent by the reverse proxy to the + backend. [Ruediger Pluem] + *) mod_http2: fixed a crash during connection termination. See PR 66539. [Stefan Eissing] @@ -151,18 +151,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_proxy: In case that AllowEncodedSlashes is set to NoDecode do not - double encode encoded slashes in the URL sent by the reverse proxy to the - backend. - Trunk version of patch: - https://svn.apache.org/r1908341 - https://svn.apache.org/r1908628 - https://svn.apache.org/r1908629 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/351.diff - Can be applied via apply_backport_pr.sh 351 - +1: rpluem, ylavic, covener - *) mod_proxy: Check before forwarding that a nocanon path has not been rewritten with spaces during processing. trunk patch: https://svn.apache.org/r1908827 diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 402c23a3a8..ace7c43ed9 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -594,7 +594,7 @@ * 20120211.124 (2.4.51-dev) Add name_ex to struct proxy_worker_shared * 20120211.125 (2.4.55-dev) Export mod_http2.h as public header * 20120211.126 (2.4.55-dev) Add additional hcmethod_t enums and PROXY_WORKER_IS_ERROR - * + * 20120211.127 (2.4.56-dev) Add ap_proxy_canonenc_ex */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -602,7 +602,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 126 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 127 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c index f1c1bb92f4..8af0a34165 100644 --- a/modules/http2/mod_proxy_http2.c +++ b/modules/http2/mod_proxy_http2.c @@ -159,8 +159,11 @@ static int proxy_http2_canon(request_rec *r, char *url) search = r->args; } else { - path = ap_proxy_canonenc(r->pool, url, (int)strlen(url), - enc_path, 0, r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, (int)strlen(url), + enc_path, flags, r->proxyreq); search = r->args; } if (search && *ap_scan_vchar_obstext(search)) { diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 5c08e99c9e..c51145e012 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -76,6 +76,10 @@ enum enctype { enc_path, enc_search, enc_user, enc_fpath, enc_parm }; +/* Flags for ap_proxy_canonenc_ex */ +#define PROXY_CANONENC_FORCEDEC 0x01 +#define PROXY_CANONENC_NOENCODEDSLASHENCODING 0x02 + typedef enum { NONE, TCP, OPTIONS, HEAD, GET, CPING, PROVIDER, OPTIONS11, HEAD11, GET11, EOT } hcmethod_t; @@ -676,6 +680,8 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src, apr_size_t dlen); PROXY_DECLARE(int) ap_proxy_hex2c(const char *x); PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x); +PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, enum enctype t, + int flags, int proxyreq); PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t, int forcedec, int proxyreq); PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index a177b5f1f8..f5b25662e1 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -70,8 +70,11 @@ static int proxy_ajp_canon(request_rec *r, char *url) search = r->args; } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); search = r->args; } if (search && *ap_scan_vchar_obstext(search)) { diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 63c1d24c02..a3db6dcd9d 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -107,8 +107,11 @@ static int proxy_balancer_canon(request_rec *r, char *url) search = r->args; } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); search = r->args; } if (search && *ap_scan_vchar_obstext(search)) { diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index a89b9a9c7b..a422b4e20c 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -97,8 +97,11 @@ static int proxy_fcgi_canon(request_rec *r, char *url) path = url; /* this is the raw/encoded path */ } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); } if (path == NULL) return HTTP_BAD_REQUEST; diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index 3237a2ba85..a3fb10a92c 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -289,6 +289,8 @@ static int proxy_ftp_canon(request_rec *r, char *url) apr_pool_t *p = r->pool; const char *err; apr_port_t port, def_port; + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; /* */ if (ap_cstr_casecmpn(url, "ftp:", 4) == 0) { @@ -327,7 +329,8 @@ static int proxy_ftp_canon(request_rec *r, char *url) else parms = ""; - path = ap_proxy_canonenc(p, url, strlen(url), enc_path, 0, r->proxyreq); + path = ap_proxy_canonenc_ex(p, url, strlen(url), enc_path, flags, + r->proxyreq); if (path == NULL) return HTTP_BAD_REQUEST; if (!ftp_check_string(path)) diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index a4c0484004..657f098069 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -126,8 +126,11 @@ static int proxy_http_canon(request_rec *r, char *url) search = r->args; } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), - enc_path, 0, r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, + flags, r->proxyreq); search = r->args; } if (search && *ap_scan_vchar_obstext(search)) { diff --git a/modules/proxy/mod_proxy_scgi.c b/modules/proxy/mod_proxy_scgi.c index 493757d3c9..5444a5c427 100644 --- a/modules/proxy/mod_proxy_scgi.c +++ b/modules/proxy/mod_proxy_scgi.c @@ -179,6 +179,8 @@ static int scgi_canon(request_rec *r, char *url) char *host, sport[sizeof(":65535")]; const char *err, *path; apr_port_t port, def_port; + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; if (ap_cstr_casecmpn(url, SCHEME "://", sizeof(SCHEME) + 2)) { return DECLINED; @@ -205,8 +207,8 @@ static int scgi_canon(request_rec *r, char *url) host = apr_pstrcat(r->pool, "[", host, "]", NULL); } - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); if (!path) { return HTTP_BAD_REQUEST; } diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c index 9dc446d3eb..3bb1f62bea 100644 --- a/modules/proxy/mod_proxy_uwsgi.c +++ b/modules/proxy/mod_proxy_uwsgi.c @@ -89,8 +89,11 @@ static int uwsgi_canon(request_rec *r, char *url) path = url; /* this is the raw/encoded path */ } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); } if (!path) { return HTTP_BAD_REQUEST; diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index 86c1b9ccae..012dd0a772 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -115,8 +115,11 @@ static int proxy_wstunnel_canon(request_rec *r, char *url) search = r->args; } else { - path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, - r->proxyreq); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); + int flags = d->allow_encoded_slashes && !d->decode_encoded_slashes ? PROXY_CANONENC_NOENCODEDSLASHENCODING : 0; + + path = ap_proxy_canonenc_ex(r->pool, url, strlen(url), enc_path, flags, + r->proxyreq); search = r->args; } if (search && *ap_scan_vchar_obstext(search)) { diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 992dba8fae..caafde0b76 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -200,14 +200,16 @@ PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x) * and encodes those which must be encoded, and does not touch * those which must not be touched. */ -PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, - enum enctype t, int forcedec, - int proxyreq) +PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, const char *x, int len, + enum enctype t, int flags, + int proxyreq) { int i, j, ch; char *y; char *allowed; /* characters which should not be encoded */ char *reserved; /* characters which much not be en/de-coded */ + int forcedec = flags & PROXY_CANONENC_FORCEDEC; + int noencslashesenc = flags & PROXY_CANONENC_NOENCODEDSLASHENCODING; /* * N.B. in addition to :@&=, this allows ';' in an http path @@ -256,7 +258,8 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, * decode it if not already done. do not decode reverse proxied URLs * unless specifically forced */ - if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') { + if ((forcedec || noencslashesenc + || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') { if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) { return NULL; } @@ -267,7 +270,17 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, y[j] = x[i]; continue; } - i += 2; + if (noencslashesenc && !forcedec && (proxyreq == PROXYREQ_REVERSE)) { + /* + * In the reverse proxy case when we only want to keep encoded + * slashes untouched revert back to '%' which will cause + * '%' to be encoded in the following. + */ + ch = '%'; + } + else { + i += 2; + } } /* recode it, if necessary */ if (!apr_isalnum(ch) && !strchr(allowed, ch)) { @@ -283,6 +296,22 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, } /* + * Convert a URL-encoded string to canonical form. + * It decodes characters which need not be encoded, + * and encodes those which must be encoded, and does not touch + * those which must not be touched. + */ +PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, + enum enctype t, int forcedec, + int proxyreq) +{ + int flags; + + flags = forcedec ? PROXY_CANONENC_FORCEDEC : 0; + return ap_proxy_canonenc_ex(p, x, len, t, flags, proxyreq); +} + +/* * Parses network-location. * urlp on input the URL; on output the path, after the leading / * user NULL if no user/password permitted |