From d3b5c42255adf28a289184b5f8cd403a38e4cf33 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Tue, 3 Dec 2024 10:59:50 +0100 Subject: [PATCH] LDEV-3349 always encode a + in a url path --- .../main/java/lucee/commons/net/HTTPUtil.java | 115 +++++++++--------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/lucee/commons/net/HTTPUtil.java b/core/src/main/java/lucee/commons/net/HTTPUtil.java index e1692b003e..87a3366af0 100755 --- a/core/src/main/java/lucee/commons/net/HTTPUtil.java +++ b/core/src/main/java/lucee/commons/net/HTTPUtil.java @@ -164,34 +164,7 @@ public static URL encodeURL(URL url, int port, boolean encodeOnlyWhenNecessary) if (port <= 0) port = url.getPort(); // decode path - if (!StringUtil.isEmpty(path)) { - int sqIndex = path.indexOf(';'); - String q = null; - if (sqIndex != -1) { - q = path.substring(sqIndex + 1); - path = path.substring(0, sqIndex); - } - - StringBuilder res = new StringBuilder(); - - StringList list = ListUtil.toListTrim(path, '/'); - String str; - - while (list.hasNext()) { - str = list.next(); - // str=URLDecoder.decode(str); - - if (StringUtil.isEmpty(str)) continue; - res.append("/"); - res.append(escapeQSValue(str, encodeOnlyWhenNecessary)); - } - if (StringUtil.endsWith(path, '/')) res.append('/'); - path = res.toString(); - - if (sqIndex != -1) { - path += decodeQuery(q, ';'); - } - } + path = decodePath(path, encodeOnlyWhenNecessary); // decode query query = decodeQuery(query, '?'); @@ -203,7 +176,7 @@ public static URL encodeURL(URL url, int port, boolean encodeOnlyWhenNecessary) file += "#" + escapeQSValue(ref, encodeOnlyWhenNecessary); } - // user/pasword + // user/password if (!StringUtil.isEmpty(user)) { int index = user.indexOf(':'); if (index != -1) { @@ -223,6 +196,39 @@ public static URL encodeURL(URL url, int port, boolean encodeOnlyWhenNecessary) } + private static String decodePath(String path, boolean encodeOnlyWhenNecessary) { + // decode path + if (!StringUtil.isEmpty(path)) { + int sqIndex = path.indexOf(';'); + String q = null; + if (sqIndex != -1) { + q = path.substring(sqIndex + 1); + path = path.substring(0, sqIndex); + } + + StringBuilder res = new StringBuilder(); + + StringList list = ListUtil.toListTrim(path, '/'); + String str; + + while (list.hasNext()) { + str = list.next(); + // str=URLDecoder.decode(str); + + if (StringUtil.isEmpty(str)) continue; + res.append("/"); + res.append(escapePathValue(str, encodeOnlyWhenNecessary)); + } + if (StringUtil.endsWith(path, '/')) res.append('/'); + path = res.toString(); + + if (sqIndex != -1) { + path += decodeQuery(q, ';'); + } + } + return path; + } + private static String decodeQuery(String query, char startDelimiter) { if (!StringUtil.isEmpty(query)) { StringBuilder res = new StringBuilder(); @@ -268,35 +274,7 @@ public static URI toURI(String strUrl, int port) throws URISyntaxException { if (port <= 0) port = uri.getPort(); // decode path - if (!StringUtil.isEmpty(path)) { - - int sqIndex = path.indexOf(';'); - String q = null; - if (sqIndex != -1) { - q = path.substring(sqIndex + 1); - path = path.substring(0, sqIndex); - } - - StringBuilder res = new StringBuilder(); - - StringList list = ListUtil.toListTrim(path, '/'); - String str; - - while (list.hasNext()) { - str = list.next(); - // str=URLDecoder.decode(str); - - if (StringUtil.isEmpty(str)) continue; - res.append("/"); - res.append(escapeQSValue(str, true)); - } - if (StringUtil.endsWith(path, '/')) res.append('/'); - path = res.toString(); - - if (sqIndex != -1) { - path += decodeQuery(q, ';'); - } - } + path = decodePath(path, true); // decode query query = decodeQuery(query, '?'); @@ -306,7 +284,7 @@ public static URI toURI(String strUrl, int port) throws URISyntaxException { fragment = escapeQSValue(fragment, true); } - // user/pasword + // user/password if (!StringUtil.isEmpty(userInfo)) { int index = userInfo.indexOf(':'); if (index != -1) { @@ -380,6 +358,25 @@ public static String escapeQSValue(String str, boolean encodeOnlyWhenNecessary) return URLEncoder.encode(str); } + public static String escapePathValue(String str, boolean encodeOnlyWhenNecessary) { + if (encodeOnlyWhenNecessary){ + boolean hasPlus = str.indexOf('+') != -1; + // in a path, space should be encoded as %20, URLEncoder.encode does this + if (!hasPlus && !ReqRspUtil.needEncoding(str, false)) return str; + return StringUtil.replace(str, "+", "%20", false); + } + + PageContextImpl pc = (PageContextImpl) ThreadLocalPageContext.get(); + if (pc != null) { + try { + return URLEncoder.encode(str, pc.getWebCharset()); + } + catch (UnsupportedEncodingException e) { + } + } + return URLEncoder.encode(str); + } + public static URL removeUnecessaryPort(URL url) { int port = url.getPort(); if (port == 80 && url.getProtocol().equalsIgnoreCase("http")) port = -1;