From b7ca34d0e8d9e1f82e888b0e0f6fdfc0fe941573 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 21 Jan 2021 12:36:05 +0800 Subject: [PATCH] fix UrlBuilder bug --- CHANGELOG.md | 4 +- .../src/main/java/cn/hutool/cache/Cache.java | 20 ++++---- .../cn/hutool/core/net/url/UrlBuilder.java | 4 +- .../java/cn/hutool/core/net/url/UrlQuery.java | 50 +++++++++++++++---- .../java/cn/hutool/core/util/URLUtil.java | 4 +- .../cn/hutool/core/net/UrlBuilderTest.java | 18 +++++++ 6 files changed, 74 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cda018245..062c36e99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.5.8 (2021-01-20) +# 5.5.8 (2021-01-21) ### 新特性 * 【extra 】 增加自动装配SpringUtil类(pr#1366@Github) @@ -14,6 +14,8 @@ ### Bug修复 * 【core 】 修复FileUtil.move以及PathUtil.copy等无法自动创建父目录的问题(issue#I2CKTI@Gitee) * 【core 】 修复Console.input读取不全问题(pr#263@Gitee) +* 【core 】 修复URLUtil.encodeAll未检查空指针问题(issue#I2CNPS@Gitee) +* 【core 】 修复UrlBuilder.of的query中含有?丢失问题(issue#I2CNPS@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-cache/src/main/java/cn/hutool/cache/Cache.java b/hutool-cache/src/main/java/cn/hutool/cache/Cache.java index 5a1b77475..d349ab76f 100644 --- a/hutool-cache/src/main/java/cn/hutool/cache/Cache.java +++ b/hutool-cache/src/main/java/cn/hutool/cache/Cache.java @@ -16,16 +16,16 @@ import java.util.Iterator; public interface Cache extends Iterable, Serializable { /** - * 返回缓存容量,0表示无大小限制 + * 返回缓存容量,{@code 0}表示无大小限制 * - * @return 返回缓存容量,0表示无大小限制 + * @return 返回缓存容量,{@code 0}表示无大小限制 */ int capacity(); /** - * 缓存失效时长, 0 表示没有设置,单位毫秒 + * 缓存失效时长, {@code 0} 表示没有设置,单位毫秒 * - * @return 缓存失效时长, 0 表示没有设置,单位毫秒 + * @return 缓存失效时长, {@code 0} 表示没有设置,单位毫秒 */ long timeout(); @@ -49,9 +49,9 @@ public interface Cache extends Iterable, Serializable { void put(K key, V object, long timeout); /** - * 从缓存中获得对象,当对象不在缓存中或已经过期返回null + * 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null} *

- * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回null,否则返回值。 + * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。 *

* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。 * @@ -66,7 +66,7 @@ public interface Cache extends Iterable, Serializable { /** * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 *

- * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回null,否则返回值。 + * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。 *

* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。 * @@ -81,7 +81,7 @@ public interface Cache extends Iterable, Serializable { /** * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 *

- * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回null,否则返回值。 + * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。 *

* 每次调用此方法会刷新最后访问时间,也就是说会重新计算超时时间。 * @@ -93,9 +93,9 @@ public interface Cache extends Iterable, Serializable { V get(K key, boolean isUpdateLastAccess, Func0 supplier); /** - * 从缓存中获得对象,当对象不在缓存中或已经过期返回null + * 从缓存中获得对象,当对象不在缓存中或已经过期返回{@code null} *

- * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回null,否则返回值。 + * 调用此方法时,会检查上次调用时间,如果与当前时间差值大于超时时间返回{@code null},否则返回值。 * * @param key 键 * @param isUpdateLastAccess 是否更新最后访问时间,即重新计算超时时间。 diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java index d3859ee97..6da825fd7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlBuilder.java @@ -135,7 +135,7 @@ public final class UrlBuilder implements Serializable { * @return UrlBuilder */ public static UrlBuilder of(String scheme, String host, int port, String path, String query, String fragment, Charset charset) { - return of(scheme, host, port, UrlPath.of(path, charset), UrlQuery.of(query, charset), fragment, charset); + return of(scheme, host, port, UrlPath.of(path, charset), UrlQuery.of(query, charset, false), fragment, charset); } /** @@ -504,4 +504,4 @@ public final class UrlBuilder implements Serializable { return build(); } -} \ No newline at end of file +} diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java index 92fed51f5..232981999 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/url/UrlQuery.java @@ -29,7 +29,7 @@ public class UrlQuery { * 构建UrlQuery * * @param queryMap 初始化的查询键值对 - * @return {@link UrlQuery} + * @return UrlQuery */ public static UrlQuery of(Map queryMap) { return new UrlQuery(queryMap); @@ -40,11 +40,24 @@ public class UrlQuery { * * @param queryStr 初始化的查询字符串 * @param charset decode用的编码,null表示不做decode - * @return {@link UrlQuery} + * @return UrlQuery */ public static UrlQuery of(String queryStr, Charset charset) { + return of(queryStr, charset, true); + } + + /** + * 构建UrlQuery + * + * @param queryStr 初始化的查询字符串 + * @param charset decode用的编码,null表示不做decode + * @param autoRemovePath 是否自动去除path部分,{@code true}则自动去除第一个?前的内容 + * @return UrlQuery + * @since 5.5.8 + */ + public static UrlQuery of(String queryStr, Charset charset, boolean autoRemovePath) { final UrlQuery urlQuery = new UrlQuery(); - urlQuery.parse(queryStr, charset); + urlQuery.parse(queryStr, charset, autoRemovePath); return urlQuery; } @@ -102,16 +115,31 @@ public class UrlQuery { * @return this */ public UrlQuery parse(String queryStr, Charset charset) { + return parse(queryStr, charset, true); + } + + /** + * 解析URL中的查询字符串 + * + * @param queryStr 查询字符串,类似于key1=v1&key2=&key3=v3 + * @param charset decode编码,null表示不做decode + * @param autoRemovePath 是否自动去除path部分,{@code true}则自动去除第一个?前的内容 + * @return this + * @since 5.5.8 + */ + public UrlQuery parse(String queryStr, Charset charset, boolean autoRemovePath) { if (StrUtil.isBlank(queryStr)) { return this; } - // 去掉Path部分 - int pathEndPos = queryStr.indexOf('?'); - if (pathEndPos > -1) { - queryStr = StrUtil.subSuf(queryStr, pathEndPos + 1); - if (StrUtil.isBlank(queryStr)) { - return this; + if (autoRemovePath) { + // 去掉Path部分 + int pathEndPos = queryStr.indexOf('?'); + if (pathEndPos > -1) { + queryStr = StrUtil.subSuf(queryStr, pathEndPos + 1); + if (StrUtil.isBlank(queryStr)) { + return this; + } } } @@ -135,9 +163,9 @@ public class UrlQuery { case '&'://键值对之间的分界符 addParam(name, queryStr.substring(pos, i), charset); name = null; - if (i+4 < len && "amp;".equals(queryStr.substring(i + 1, i + 5))) { + if (i + 4 < len && "amp;".equals(queryStr.substring(i + 1, i + 5))) { // issue#850@Github,"&"转义为"&" - i+=4; + i += 4; } // 开始位置从分节符后开始 pos = i + 1; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java index 982bf33ea..780c2f710 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java @@ -332,7 +332,7 @@ public class URLUtil { * @throws UtilException UnsupportedEncodingException */ public static String encodeAll(String url, Charset charset) throws UtilException { - if (null == charset) { + if (null == charset || StrUtil.isEmpty(url)) { return url; } @@ -870,4 +870,4 @@ public class URLUtil { return builder.toString(); } -} \ No newline at end of file +} diff --git a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java index 8768d5e0d..78307e15a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/UrlBuilderTest.java @@ -6,6 +6,10 @@ import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; + public class UrlBuilderTest { @Test @@ -217,4 +221,18 @@ public class UrlBuilderTest { final UrlBuilder urlBuilder = UrlBuilder.ofHttp("https://hutool.cn//file/test.jpg", CharsetUtil.CHARSET_UTF_8); Assert.assertEquals("https://hutool.cn//file/test.jpg", urlBuilder.toString()); } + + @Test + public void toURITest() throws URISyntaxException { + String webUrl = "http://exmple.com/patha/pathb?a=123"; // 报错数据 + final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8); + Assert.assertEquals(new URI(webUrl), urlBuilder.toURI()); + } + + @Test + public void testEncodeInQuery() { + String webUrl = "http://exmple.com/patha/pathb?a=123&b=4?6&c=789"; // b=4?6 参数中有未编码的? + final UrlBuilder urlBuilder = UrlBuilder.of(webUrl, StandardCharsets.UTF_8); + Assert.assertEquals("a=123&b=4%3F6&c=789", urlBuilder.getQueryStr()); + } }