323 lines
14 KiB
Diff
323 lines
14 KiB
Diff
From 9b8cf1746bb004050b02a30bf0222479fbe405c2 Mon Sep 17 00:00:00 2001
|
|
From: Ruediger Pluem <rpluem@apache.org>
|
|
Date: Fri, 31 Mar 2023 10:33:47 PM GMT+0800
|
|
Subject: [PATCH] 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
|
|
|
|
Conflict:NA
|
|
Reference:https://github.com/apache/httpd/commit/9b8cf1746bb004050b02a30bf0222479fbe405c2
|
|
|
|
---
|
|
include/ap_mmn.h | 3 ++-
|
|
modules/http2/mod_proxy_http2.c | 7 ++++--
|
|
modules/proxy/mod_proxy.h | 6 +++++
|
|
modules/proxy/mod_proxy_ajp.c | 7 ++++--
|
|
modules/proxy/mod_proxy_balancer.c | 7 ++++--
|
|
modules/proxy/mod_proxy_fcgi.c | 7 ++++--
|
|
modules/proxy/mod_proxy_ftp.c | 5 +++-
|
|
modules/proxy/mod_proxy_http.c | 7 ++++--
|
|
modules/proxy/mod_proxy_scgi.c | 6 +++--
|
|
modules/proxy/mod_proxy_uwsgi.c | 7 ++++--
|
|
modules/proxy/mod_proxy_wstunnel.c | 7 ++++--
|
|
modules/proxy/proxy_util.c | 39 ++++++++++++++++++++++++++----
|
|
12 files changed, 85 insertions(+), 23 deletions(-)
|
|
|
|
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
|
|
index a6d47a2..dd469f3 100644
|
|
--- a/include/ap_mmn.h
|
|
+++ b/include/ap_mmn.h
|
|
@@ -582,6 +582,7 @@
|
|
* 20120211.118 (2.4.51-dev) Add ap_unescape_url_ex() and deprecate
|
|
* AP_NORMALIZE_DROP_PARAMETERS
|
|
* 20120211.121 (2.4.51-dev) Add ap_post_read_request()
|
|
+ * 20120211.122 (2.4.51-dev) Add ap_proxy_canonenc_ex
|
|
*
|
|
*/
|
|
|
|
@@ -590,7 +591,7 @@
|
|
#ifndef MODULE_MAGIC_NUMBER_MAJOR
|
|
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
|
|
#endif
|
|
-#define MODULE_MAGIC_NUMBER_MINOR 118 /* 0...n */
|
|
+#define MODULE_MAGIC_NUMBER_MINOR 122 /* 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 9b741e1..77e2641 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 47899d7..ce8183a 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, EOT
|
|
} hcmethod_t;
|
|
@@ -669,6 +673,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 731e4ed..747f928 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 719a99e..de31749 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 a89b9a9..a422b4e 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 a559528..e40d17c 100644
|
|
--- a/modules/proxy/mod_proxy_ftp.c
|
|
+++ b/modules/proxy/mod_proxy_ftp.c
|
|
@@ -294,6 +294,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) {
|
|
@@ -332,7 +334,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 4d0f8de..fca8d5d 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 493757d..5444a5c 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 71c6ebb..771fcea 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 3f8de25..a44bb44 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 669b672..2dee743 100644
|
|
--- a/modules/proxy/proxy_util.c
|
|
+++ b/modules/proxy/proxy_util.c
|
|
@@ -205,14 +205,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
|
|
@@ -261,7 +263,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;
|
|
}
|
|
@@ -272,7 +275,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)) {
|
|
@@ -287,6 +300,22 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
|
|
return y;
|
|
}
|
|
|
|
+/*
|
|
+ * 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 /
|
|
--
|
|
2.27.0
|
|
|