getFileNameFromDisposition更加规范,从多个头的值中获取,且filename*优先级更高

This commit is contained in:
Looly 2024-05-20 09:27:10 +08:00
parent 9e1beae3eb
commit 228785b1b2
3 changed files with 48 additions and 10 deletions

View File

@ -2,7 +2,7 @@
# 🚀Changelog
-------------------------------------------------------------------------------------------------------------
# 5.8.28(2024-05-17)
# 5.8.28(2024-05-20)
### 🐣新特性
* 【core 】 修正XmlUtil的omitXmlDeclaration描述注释issue#I9CPC7@Gitee
@ -22,6 +22,7 @@
* 【core 】 增加IdConstants提高Snowflake初始化性能issue#3581@Github
* 【core 】 优化 CharSequenceUtil工具类 startWithAny()、startWithAnyIgnoreCase() 参数命名错误问题pr#1219@Gitee
* 【core 】 ListUtil.setOrPadding增加重载可选限制index大小issue#3586@Github
* 【http 】 getFileNameFromDisposition更加规范从多个头的值中获取`filename*`优先级更高pr#3590@Gitee
### 🐞Bug修复
* 【http 】 修复HttpUtil.urlWithFormUrlEncoded方法重复编码问题issue#3536@Github

View File

@ -319,10 +319,10 @@ public class ModifierUtil {
//-------------------------------------------------------------------------------------------------------- Private method start
/**
* 多个修饰符做操作表示同时存在多个修饰符
* 多个修饰符做操作表示同时存在多个修饰符
*
* @param modifierTypes 修饰符列表元素不能为空
* @return 之后的修饰符
* @return 之后的修饰符
*/
private static int modifiersToInt(ModifierType... modifierTypes) {
int modifier = modifierTypes[0].getValue();

View File

@ -1,5 +1,6 @@
package cn.hutool.http;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.FileUtil;
@ -467,25 +468,61 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
/**
* 从Content-Disposition头中获取文件名
* @param paramName 文件参数名
*
* @return 文件名empty表示无
*/
public String getFileNameFromDisposition() {
return getFileNameFromDisposition(null);
}
/**
* 从Content-Disposition头中获取文件名以参数名为`filename`为例规则为
* <ul>
* <li>首先按照RFC5987规范检查`filename*`参数对应的值`filename*="example.txt"`则获取`example.txt`</li>
* <li>如果找不到`filename*`参数则检查`filename`参数对应的值`filename="example.txt"`则获取`example.txt`</li>
* </ul>
* 按照规范`Content-Disposition`可能返回多个此处遍历所有返回头并且`filename*`始终优先获取即使`filename`存在并更靠前<br>
* 参考https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Disposition
*
* @param paramName 文件参数名如果为{@code null}则使用默认的`filename`
* @return 文件名empty表示无
*/
public String getFileNameFromDisposition(String paramName) {
paramName = ObjUtil.defaultIfNull(paramName, "filename");
final List<String> dispositions = headerList(Header.CONTENT_DISPOSITION.name());
String fileName = null;
final String disposition = header(Header.CONTENT_DISPOSITION);
if (StrUtil.isNotBlank(disposition)) {
fileName = ReUtil.get(paramName+"=\"(.*?)\"", disposition, 1);
if (StrUtil.isBlank(fileName)) {
fileName = StrUtil.subAfter(disposition, paramName + "=", true);
if (CollUtil.isNotEmpty(dispositions)) {
// filename* 采用了 RFC 5987 中规定的编码方式优先读取
fileName = getFileNameFromDispositions(dispositions, StrUtil.addSuffixIfNot(paramName, "*"));
if ((!StrUtil.endWith(fileName, "*")) && StrUtil.isBlank(fileName)) {
fileName = getFileNameFromDispositions(dispositions, paramName);
}
}
return fileName;
}
// ---------------------------------------------------------------- Private method start
/**
* 从Content-Disposition头中获取文件名
*
* @param dispositions Content-Disposition头列表
* @param paramName 文件参数名
* @return 文件名empty表示无
*/
private static String getFileNameFromDispositions(final List<String> dispositions, String paramName) {
String fileName = null;
for (String disposition : dispositions) {
fileName = ReUtil.getGroup1(paramName + "=\"(.*?)\"", disposition);
if (StrUtil.isNotBlank(fileName)) {
break;
}
}
return fileName;
}
/**
* 初始化Http响应并在报错时关闭连接<br>
* 初始化包括
@ -632,7 +669,7 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
} catch (IORuntimeException e) {
//noinspection StatementWithEmptyBody
if (isIgnoreEOFError
&& (e.getCause() instanceof EOFException || StrUtil.containsIgnoreCase(e.getMessage(), "Premature EOF"))) {
&& (e.getCause() instanceof EOFException || StrUtil.containsIgnoreCase(e.getMessage(), "Premature EOF"))) {
// 忽略读取HTTP流中的EOF错误
} else {
throw e;