20
20
import java .io .IOException ;
21
21
import java .io .InputStream ;
22
22
import java .io .Serializable ;
23
- import java .nio .charset .Charset ;
24
- import java .nio .charset .StandardCharsets ;
23
+ import java .io .UnsupportedEncodingException ;
25
24
import java .nio .file .Files ;
26
25
import java .util .ArrayList ;
27
26
import java .util .Collection ;
31
30
import java .util .LinkedHashSet ;
32
31
import java .util .Map ;
33
32
import java .util .Set ;
33
+ import javax .mail .internet .MimeUtility ;
34
34
import javax .servlet .http .HttpServletRequest ;
35
35
import javax .servlet .http .Part ;
36
36
37
+ import org .springframework .http .ContentDisposition ;
37
38
import org .springframework .http .HttpHeaders ;
38
39
import org .springframework .lang .Nullable ;
39
40
import org .springframework .util .FileCopyUtils ;
54
55
*/
55
56
public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest {
56
57
57
- private static final String CONTENT_DISPOSITION = "content-disposition" ;
58
-
59
- private static final String FILENAME_KEY = "filename=" ;
60
-
61
- private static final String FILENAME_WITH_CHARSET_KEY = "filename*=" ;
62
-
63
-
64
58
@ Nullable
65
59
private Set <String > multipartParameterNames ;
66
60
@@ -96,12 +90,13 @@ private void parseRequest(HttpServletRequest request) {
96
90
this .multipartParameterNames = new LinkedHashSet <>(parts .size ());
97
91
MultiValueMap <String , MultipartFile > files = new LinkedMultiValueMap <>(parts .size ());
98
92
for (Part part : parts ) {
99
- String disposition = part .getHeader (CONTENT_DISPOSITION );
100
- String filename = extractFilename (disposition );
101
- if (filename == null ) {
102
- filename = extractFilenameWithCharset (disposition );
103
- }
93
+ String headerValue = part .getHeader (HttpHeaders .CONTENT_DISPOSITION );
94
+ ContentDisposition disposition = ContentDisposition .parse (headerValue );
95
+ String filename = disposition .getFilename ();
104
96
if (filename != null ) {
97
+ if (filename .startsWith ("=?" ) && filename .endsWith ("?=" )) {
98
+ filename = MimeDelegate .decode (filename );
99
+ }
105
100
files .add (part .getName (), new StandardMultipartFile (part , filename ));
106
101
}
107
102
else {
@@ -123,62 +118,6 @@ protected void handleParseFailure(Throwable ex) {
123
118
throw new MultipartException ("Failed to parse multipart servlet request" , ex );
124
119
}
125
120
126
- @ Nullable
127
- private String extractFilename (String contentDisposition , String key ) {
128
- int startIndex = contentDisposition .indexOf (key );
129
- if (startIndex == -1 ) {
130
- return null ;
131
- }
132
- String filename = contentDisposition .substring (startIndex + key .length ());
133
- if (filename .startsWith ("\" " )) {
134
- int endIndex = filename .indexOf ("\" " , 1 );
135
- if (endIndex != -1 ) {
136
- return filename .substring (1 , endIndex );
137
- }
138
- }
139
- else {
140
- int endIndex = filename .indexOf (";" );
141
- if (endIndex != -1 ) {
142
- return filename .substring (0 , endIndex );
143
- }
144
- }
145
- return filename ;
146
- }
147
-
148
- @ Nullable
149
- private String extractFilename (String contentDisposition ) {
150
- return extractFilename (contentDisposition , FILENAME_KEY );
151
- }
152
-
153
- @ Nullable
154
- private String extractFilenameWithCharset (String contentDisposition ) {
155
- String filename = extractFilename (contentDisposition , FILENAME_WITH_CHARSET_KEY );
156
- if (filename == null ) {
157
- return null ;
158
- }
159
- int index = filename .indexOf ("'" );
160
- if (index != -1 ) {
161
- Charset charset = null ;
162
- try {
163
- charset = Charset .forName (filename .substring (0 , index ));
164
- }
165
- catch (IllegalArgumentException ex ) {
166
- // ignore
167
- }
168
- filename = filename .substring (index + 1 );
169
- // Skip language information..
170
- index = filename .indexOf ("'" );
171
- if (index != -1 ) {
172
- filename = filename .substring (index + 1 );
173
- }
174
- if (charset != null ) {
175
- filename = new String (filename .getBytes (StandardCharsets .US_ASCII ), charset );
176
- }
177
- }
178
- return filename ;
179
- }
180
-
181
-
182
121
@ Override
183
122
protected void initializeMultipart () {
184
123
parseRequest (getRequest ());
@@ -322,4 +261,20 @@ public void transferTo(File dest) throws IOException, IllegalStateException {
322
261
}
323
262
}
324
263
264
+
265
+ /**
266
+ * Inner class to avoid a hard dependency on the JavaMail API.
267
+ */
268
+ private static class MimeDelegate {
269
+
270
+ public static String decode (String value ) {
271
+ try {
272
+ return MimeUtility .decodeText (value );
273
+ }
274
+ catch (UnsupportedEncodingException ex ) {
275
+ throw new IllegalStateException (ex );
276
+ }
277
+ }
278
+ }
279
+
325
280
}
0 commit comments