From 07bb1ed6dc5dbf61c5d21c7235db908616653a0b Mon Sep 17 00:00:00 2001 From: Yusuke Yamamoto Date: Thu, 28 Jan 2021 11:48:22 +0900 Subject: [PATCH] Decode BASE64 encoded Content-Disposition filename --- .../springframework/http/ContentDisposition.java | 13 ++++++++++++- .../http/ContentDispositionTests.java | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java index ce75abdc096..1028c19fd2b 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -22,7 +22,10 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.util.ArrayList; +import java.util.Base64; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -320,6 +323,7 @@ public static ContentDisposition empty() { return new ContentDisposition("", null, null, null, null, null, null, null); } + private final static Pattern BASE64_ENCODED_PATTERN = Pattern.compile("=\\?([0-9a-zA-Z-_]+)\\?B\\?([+/0-9a-zA-Z]+=*)\\?="); /** * Parse a {@literal Content-Disposition} header value as defined in RFC 2183. * @param contentDisposition the {@literal Content-Disposition} header value @@ -362,7 +366,14 @@ else if (attribute.equals("filename*") ) { } } else if (attribute.equals("filename") && (filename == null)) { - filename = value; + final Matcher matcher = BASE64_ENCODED_PATTERN.matcher(value); + if (matcher.find()) { + String charsetName = matcher.group(1); + String encoded = matcher.group(2); + filename = new String(Base64.getDecoder().decode(encoded), Charset.forName(charsetName)); + } else { + filename = value; + } } else if (attribute.equals("size") ) { size = Long.parseLong(value); diff --git a/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java b/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java index 00b49d2fc0a..50c0d06f982 100644 --- a/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java +++ b/spring-web/src/test/java/org/springframework/http/ContentDispositionTests.java @@ -80,6 +80,18 @@ void parseEncodedFilenameWithPaddedCharset() { .build()); } + @Test + void parseBase64EncodedUTF8Filename() { + assertThat(parse("attachment; filename=\"=?UTF-8?B?5pel5pys6KqeLmNzdg==?=\"").getFilename()) + .isEqualTo("日本語.csv"); + } + + @Test + void parseBase64EncodedShiftJISFilename() { + assertThat(parse("attachment; filename=\"=?SHIFT_JIS?B?k/qWe4zqLmNzdg==?=\"").getFilename()) + .isEqualTo("日本語.csv"); + } + @Test void parseEncodedFilenameWithoutCharset() { assertThat(parse("form-data; name=\"name\"; filename*=test.txt"))