1
0
mirror of https://gitee.com/dromara/hutool.git synced 2025-04-05 17:37:59 +08:00

fix plus encode bug

This commit is contained in:
Looly 2021-04-08 18:12:10 +08:00
parent 6b0b729c68
commit 1edbc0de80
11 changed files with 151 additions and 18 deletions
CHANGELOG.md
hutool-core/src
hutool-http/src/main/java/cn/hutool/http

View File

@ -22,6 +22,7 @@
* 【core 】 修复Validator.isUrl()传空返回trueissue#I3ETTY@Gitee
* 【db 】 修复数据库driver根据url的判断识别错误问题issue#I3EWBI@Gitee
* 【json 】 修复JSONStrFormatter换行多余空行问题issue#I3FA8B@Gitee
* 【core 】 修复UrlPath中的+被转义为空格%20的问题issue#1501@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -23,24 +23,84 @@ public class URLDecoder implements Serializable {
private static final byte ESCAPE_CHAR = '%';
/**
* 解码不对+解码
* <pre>
* 1. %20转换为空格 ;
* 2. "%xy"转换为文本形式,xy是两位16进制的数值;
* 3. 跳过不符合规范的%形式直接输出
* </pre>
*
* @param str 包含URL编码后的字符串
* @param charset 编码
* @return 解码后的字符串
*/
public static String decodeForPath(String str, Charset charset) {
return decode(str, charset, false);
}
/**
* 解码
* <pre>
* 1. +%20转换为空格 ;
* 2. "%xy"转换为文本形式,xy是两位16进制的数值;
* 3. 跳过不符合规范的%形式直接输出
* </pre>
*
* @param str 包含URL编码后的字符串
* @param charset 编码
* @return 解码后的字符串
*/
public static String decode(String str, Charset charset) {
return StrUtil.str(decode(StrUtil.bytes(str, charset)), charset);
return decode(str, charset, true);
}
/**
* 解码
* <pre>
* 1. %20转换为空格 ;
* 2. "%xy"转换为文本形式,xy是两位16进制的数值;
* 3. 跳过不符合规范的%形式直接输出
* </pre>
*
* @param str 包含URL编码后的字符串
* @param isPlusToSpace 是否+转换为空格
* @param charset 编码
* @return 解码后的字符串
*/
public static String decode(String str, Charset charset, boolean isPlusToSpace) {
return StrUtil.str(decode(StrUtil.bytes(str, charset), isPlusToSpace), charset);
}
/**
* 解码
* <pre>
* 1. +%20转换为空格 ;
* 2. "%xy"转换为文本形式,xy是两位16进制的数值;
* 3. 跳过不符合规范的%形式直接输出
* </pre>
*
* @param bytes url编码的bytes
* @return 解码后的bytes
*/
public static byte[] decode(byte[] bytes) {
return decode(bytes, true);
}
/**
* 解码
* <pre>
* 1. %20转换为空格 ;
* 2. "%xy"转换为文本形式,xy是两位16进制的数值;
* 3. 跳过不符合规范的%形式直接输出
* </pre>
*
* @param bytes url编码的bytes
* @param isPlusToSpace 是否+转换为空格
* @return 解码后的bytes
* @since 5.6.3
*/
public static byte[] decode(byte[] bytes, boolean isPlusToSpace) {
if (bytes == null) {
return null;
}
@ -49,7 +109,7 @@ public class URLDecoder implements Serializable {
for (int i = 0; i < bytes.length; i++) {
b = bytes[i];
if (b == '+') {
buffer.write(CharUtil.SPACE);
buffer.write(isPlusToSpace ? CharUtil.SPACE : b);
} else if (b == ESCAPE_CHAR) {
if (i + 1 < bytes.length) {
final int u = CharUtil.digit16(bytes[i + 1]);

View File

@ -82,6 +82,17 @@ public final class UrlBuilder implements Serializable {
return ofHttp(httpUrl, null);
}
/**
* 使用URL字符串构建UrlBuilder当传入的URL没有协议时按照http协议对待编码默认使用UTF-8
*
* @param httpUrl URL字符串
* @return UrlBuilder
* @since 5.6.3
*/
public static UrlBuilder ofHttp(String httpUrl) {
return ofHttp(httpUrl, CharsetUtil.CHARSET_UTF_8);
}
/**
* 使用URL字符串构建UrlBuilder当传入的URL没有协议时按照http协议对待
*
@ -99,6 +110,16 @@ public final class UrlBuilder implements Serializable {
return of(httpUrl, charset);
}
/**
* 使用URL字符串构建UrlBuilder默认使用UTF-8编码
*
* @param url URL字符串
* @return UrlBuilder
*/
public static UrlBuilder of(String url) {
return of(url, CharsetUtil.CHARSET_UTF_8);
}
/**
* 使用URL字符串构建UrlBuilder
*

View File

@ -2,6 +2,7 @@ package cn.hutool.core.net.url;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
@ -97,8 +98,6 @@ public class UrlPath {
* @return this
*/
public UrlPath parse(String path, Charset charset) {
UrlPath urlPath = new UrlPath();
if (StrUtil.isNotEmpty(path)) {
// 原URL中以/结尾则这个规则需保留issue#I1G44J@Gitee
if(StrUtil.endWith(path, CharUtil.SLASH)){
@ -108,11 +107,11 @@ public class UrlPath {
path = fixPath(path);
final List<String> split = StrUtil.split(path, '/');
for (String seg : split) {
addInternal(URLUtil.decode(seg, charset), false);
addInternal(URLDecoder.decodeForPath(seg, charset), false);
}
}
return urlPath;
return this;
}
/**

View File

@ -134,7 +134,7 @@ public class URLUtil {
* @return URL
* @since 5.5.2
*/
public static URI getStringURI(CharSequence content){
public static URI getStringURI(CharSequence content) {
final String contentStr = StrUtil.addPrefixIfNot(content, "string:///");
return URI.create(contentStr);
}
@ -467,6 +467,23 @@ public class URLUtil {
return URLDecoder.decode(content, charset);
}
/**
* 解码application/x-www-form-urlencoded字符<br>
* %开头的16进制表示的内容解码
*
* @param content 被解码内容
* @param charset 编码null表示不解码
* @param isPlusToSpace 是否+转换为空格
* @return 编码后的字符
* @since 5.6.3
*/
public static String decode(String content, Charset charset, boolean isPlusToSpace) {
if (null == charset) {
return content;
}
return URLDecoder.decode(content, charset, isPlusToSpace);
}
/**
* 解码application/x-www-form-urlencoded字符<br>
* %开头的16进制表示的内容解码
@ -705,7 +722,7 @@ public class URLUtil {
*
* @param url URL字符串
* @param isEncodePath 是否对URL中path部分的中文和特殊字符做转义不包括 http:, /和域名部分
* @param replaceSlash 是否替换url body中的 //
* @param replaceSlash 是否替换url body中的 //
* @return 标准化后的URL字符串
* @since 5.5.5
*/

View File

@ -0,0 +1,17 @@
package cn.hutool.core.net;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
public class URLEncoderTest {
@Test
public void encodeTest(){
String encode = URLEncoder.DEFAULT.encode("+", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("+", encode);
encode = URLEncoder.DEFAULT.encode(" ", CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("%20", encode);
}
}

View File

@ -18,6 +18,13 @@ public class UrlBuilderTest {
Assert.assertEquals("http://www.hutool.cn/", buildUrl);
}
@Test
public void buildTest2() {
// path中的+不做处理
String buildUrl = UrlBuilder.ofHttp("http://www.hutool.cn/+8618888888888", CharsetUtil.CHARSET_UTF_8).build();
Assert.assertEquals("http://www.hutool.cn/+8618888888888", buildUrl);
}
@Test
public void testHost() {
String buildUrl = UrlBuilder.create()

View File

@ -0,0 +1,12 @@
package cn.hutool.core.net;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
public class UrlDecoderTest {
@Test
public void decodeForPathTest(){
Assert.assertEquals("+", URLDecoder.decodeForPath("+", CharsetUtil.CHARSET_UTF_8));
}
}

View File

@ -9,7 +9,7 @@ import java.net.URL;
/**
* URLUtil单元测试
*
*
* @author looly
*
*/
@ -26,24 +26,24 @@ public class URLUtilTest {
normalize = URLUtil.normalize(url);
Assert.assertEquals("http://www.hutool.cn//aaa/bbb", normalize);
}
@Test
public void normalizeTest2() {
String url = "http://www.hutool.cn//aaa/\\bbb?a=1&b=2";
String normalize = URLUtil.normalize(url);
Assert.assertEquals("http://www.hutool.cn//aaa//bbb?a=1&b=2", normalize);
url = "www.hutool.cn//aaa/bbb?a=1&b=2";
normalize = URLUtil.normalize(url);
Assert.assertEquals("http://www.hutool.cn//aaa/bbb?a=1&b=2", normalize);
}
@Test
public void normalizeTest3() {
String url = "http://www.hutool.cn//aaa/\\bbb?a=1&b=2";
String normalize = URLUtil.normalize(url, true);
Assert.assertEquals("http://www.hutool.cn//aaa//bbb?a=1&b=2", normalize);
url = "www.hutool.cn//aaa/bbb?a=1&b=2";
normalize = URLUtil.normalize(url, true);
Assert.assertEquals("http://www.hutool.cn//aaa/bbb?a=1&b=2", normalize);
@ -59,7 +59,7 @@ public class URLUtilTest {
String normalize = URLUtil.normalize("http://[fe80::8f8:2022:a603:d180]:9439", true);
Assert.assertEquals(url, normalize);
}
@Test
public void formatTest() {
String url = "//www.hutool.cn//aaa/\\bbb?a=1&b=2";
@ -81,7 +81,7 @@ public class URLUtilTest {
String encode = URLUtil.encode(body);
Assert.assertEquals("366466%20-%20%E5%89%AF%E6%9C%AC.jpg", encode);
Assert.assertEquals(body, URLUtil.decode(encode));
String encode2 = URLUtil.encodeQuery(body);
Assert.assertEquals("366466+-+%E5%89%AF%E6%9C%AC.jpg", encode2);
}

View File

@ -77,7 +77,7 @@ public enum ContentType {
}
/**
* 是否为默认Content-Type默认包括<code>null</code>和application/x-www-form-urlencoded
* 是否为默认Content-Type默认包括{@code null}和application/x-www-form-urlencoded
*
* @param contentType 内容类型
* @return 是否为默认Content-Type

View File

@ -12,7 +12,6 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.body.MultipartBody;
@ -157,7 +156,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @param url URL
*/
public HttpRequest(String url) {
this(UrlBuilder.ofHttp(url, CharsetUtil.CHARSET_UTF_8));
this(UrlBuilder.ofHttp(url));
}
/**