From dca342c28f23328317e0d2e9f6aa8d0d954fdcfa Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 15 Aug 2024 18:26:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DgetFileNameFromDisposition?= =?UTF-8?q?=E4=B8=8D=E7=AC=A6=E5=90=88=E8=A7=84=E8=8C=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/http/meta/HttpHeaderUtil.java | 34 +++++++++-- .../hutool/http/meta/HttpHeaderUtilTest.java | 56 +++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 hutool-http/src/test/java/org/dromara/hutool/http/meta/HttpHeaderUtilTest.java diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/meta/HttpHeaderUtil.java b/hutool-http/src/main/java/org/dromara/hutool/http/meta/HttpHeaderUtil.java index 1d136575e..647d68acd 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/meta/HttpHeaderUtil.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/meta/HttpHeaderUtil.java @@ -20,13 +20,15 @@ import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.map.CaseInsensitiveMap; import org.dromara.hutool.core.regex.ReUtil; import org.dromara.hutool.core.text.StrUtil; +import org.dromara.hutool.core.text.split.SplitUtil; import org.dromara.hutool.core.util.ObjUtil; import java.util.List; import java.util.Map; /** - * HTTP头相关方法 + * HTTP头相关方法
+ * 相关规范见:https://www.rfc-editor.org/rfc/rfc5987 * * @author Looly * @since 6.0.0 @@ -67,7 +69,6 @@ public class HttpHeaderUtil { final List dispositions = headerList(headers, HeaderName.CONTENT_DISPOSITION.getValue()); String fileName = null; if (CollUtil.isNotEmpty(dispositions)) { - // filename* 采用了 RFC 5987 中规定的编码方式,优先读取 fileName = getFileNameFromDispositions(dispositions, StrUtil.addSuffixIfNot(paramName, "*")); if ((!StrUtil.endWith(fileName, "*")) && StrUtil.isBlank(fileName)) { @@ -86,13 +87,38 @@ public class HttpHeaderUtil { * @return 文件名,empty表示无 */ private static String getFileNameFromDispositions(final List dispositions, String paramName) { + // 正则转义 + paramName = StrUtil.replace(paramName, "*", "\\*"); String fileName = null; for (final String disposition : dispositions) { - fileName = ReUtil.getGroup1(paramName + "=\"(.*?)\"", disposition); + fileName = ReUtil.getGroup1(paramName + "=([^;]+)", disposition); if (StrUtil.isNotBlank(fileName)) { break; } } - return fileName; + return getRfc5987Value(fileName); + } + + /** + * 获取rfc5987标准的值,标准见:https://www.rfc-editor.org/rfc/rfc5987#section-3.2.1
+ * 包括: + * + *
    + *
  • Non-extended:无双引号包裹的值
  • + *
  • Non-extended:双引号包裹的值
  • + *
  • Extended notation:编码'语言'值
  • + *
+ * + * @param value 值 + * @return 结果值 + */ + private static String getRfc5987Value(final String value){ + final List split = SplitUtil.split(value, "'"); + if(3 == split.size()){ + return split.get(2); + } + + // 普通值 + return StrUtil.unWrap(value, '"'); } } diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/meta/HttpHeaderUtilTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/meta/HttpHeaderUtilTest.java new file mode 100644 index 000000000..df29ebfda --- /dev/null +++ b/hutool-http/src/test/java/org/dromara/hutool/http/meta/HttpHeaderUtilTest.java @@ -0,0 +1,56 @@ +package org.dromara.hutool.http.meta; + +import org.dromara.hutool.core.collection.ListUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HttpHeaderUtilTest { + @Test + void getFileNameFromDispositionTest() { + final Map> headers = new HashMap<>(); + headers.put(HeaderName.CONTENT_DISPOSITION.getValue(), + ListUtil.of("attachment; filename*=utf-8''%E6%B5%8B%E8%AF%95.xlsx; filename=\"æµ\u008Bè¯\u0095.xlsx\"")); + final String fileNameFromDisposition = HttpHeaderUtil.getFileNameFromDisposition(headers, null); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95.xlsx", fileNameFromDisposition); + } + + @Test + void getFileNameFromDispositionTest2() { + final Map> headers = new HashMap<>(); + headers.put(HeaderName.CONTENT_DISPOSITION.getValue(), + ListUtil.of("attachment; filename*=utf-8''%E6%B5%8B%E8%AF%95.xlsx")); + final String fileNameFromDisposition = HttpHeaderUtil.getFileNameFromDisposition(headers, null); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95.xlsx", fileNameFromDisposition); + } + + @Test + void getFileNameFromDispositionTest3() { + final Map> headers = new HashMap<>(); + headers.put(HeaderName.CONTENT_DISPOSITION.getValue(), + ListUtil.of("attachment; filename*=\"%E6%B5%8B%E8%AF%95.xlsx\"")); + final String fileNameFromDisposition = HttpHeaderUtil.getFileNameFromDisposition(headers, null); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95.xlsx", fileNameFromDisposition); + } + + @Test + void getFileNameFromDispositionTest4() { + final Map> headers = new HashMap<>(); + headers.put(HeaderName.CONTENT_DISPOSITION.getValue(), + ListUtil.of("attachment; filename=\"%E6%B5%8B%E8%AF%95.xlsx\"")); + final String fileNameFromDisposition = HttpHeaderUtil.getFileNameFromDisposition(headers, null); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95.xlsx", fileNameFromDisposition); + } + + @Test + void getFileNameFromDispositionTest5() { + final Map> headers = new HashMap<>(); + headers.put(HeaderName.CONTENT_DISPOSITION.getValue(), + ListUtil.of("attachment; filename=%E6%B5%8B%E8%AF%95.xlsx")); + final String fileNameFromDisposition = HttpHeaderUtil.getFileNameFromDisposition(headers, null); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95.xlsx", fileNameFromDisposition); + } +}