如何从content-disposition读取编码的文件名

时间:2017-02-13 11:18:43

标签: java web-services https http-headers

我正在获取内容处置标头值,如下所示。

  

附件;文件名* = UTF-8'' album.jpeg

如何从中提取文件名(album.jpeg)。在查看值时,它具有编码格式值。

2 个答案:

答案 0 :(得分:0)

filename*参数在RFC 6266

中定义

使用java解码文件名:

String contentd = "attachment;filename*=UTF-8''album.jpeg";
String filename = java.net.URLDecoder.decode(contentd.substring(contentd.indexOf("''")+2), "UTF-8");

答案 1 :(得分:0)

使用Spring的ContentDisposition(从5.0版开始)对其进行解析。如果您负担不起将Spring作为项目的依赖项添加,则可以使用此实现(原始的import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; public class Main { public static void main(String[] args) { String fileName = ContentDispositionFileNameParser.parse("attachment; filename*=UTF-8''%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%B5%20%D1%81%D0%BB%D0%BE%D0%B2%D0%BE.txt"); System.out.println(fileName); } } /* * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Parses "filename" parameter of the Content-Disposition HTTP header as defined in RFC 6266. * * @author Sebastien Deleuze * @author Juergen Hoeller * @author Rossen Stoyanchev */ final class ContentDispositionFileNameParser { private static final String INVALID_HEADER_FIELD_PARAMETER_FORMAT = "Invalid header field parameter format (as defined in RFC 5987)"; /** * Parse a {@literal Content-Disposition} header value as defined in RFC 2183. * * @param contentDisposition the {@literal Content-Disposition} header value * @return Return the value of the {@literal filename} parameter (or the value of the * {@literal filename*} one decoded as defined in the RFC 5987), or {@code null} if not defined. */ public static String parse(String contentDisposition) { List<String> parts = tokenize(contentDisposition); String filename = null; Charset charset; for (int i = 1; i < parts.size(); i++) { String part = parts.get(i); int eqIndex = part.indexOf('='); if (eqIndex != -1) { String attribute = part.substring(0, eqIndex); String value = (part.startsWith("\"", eqIndex + 1) && part.endsWith("\"") ? part.substring(eqIndex + 2, part.length() - 1) : part.substring(eqIndex + 1)); if (attribute.equals("filename*")) { int idx1 = value.indexOf('\''); int idx2 = value.indexOf('\'', idx1 + 1); if (idx1 != -1 && idx2 != -1) { charset = Charset.forName(value.substring(0, idx1).trim()); if (!(UTF_8.equals(charset) || ISO_8859_1.equals(charset))) { throw new IllegalArgumentException("Charset should be UTF-8 or ISO-8859-1"); } filename = decodeFilename(value.substring(idx2 + 1), charset); } else { // US ASCII filename = decodeFilename(value, StandardCharsets.US_ASCII); } } else if (attribute.equals("filename") && (filename == null)) { filename = value; } } else { throw new IllegalArgumentException("Invalid content disposition format"); } } return filename; } private static List<String> tokenize(String headerValue) { int index = headerValue.indexOf(';'); String type = (index >= 0 ? headerValue.substring(0, index) : headerValue).trim(); if (type.isEmpty()) { throw new IllegalArgumentException("Content-Disposition header must not be empty"); } List<String> parts = new ArrayList<>(); parts.add(type); if (index >= 0) { do { int nextIndex = index + 1; boolean quoted = false; boolean escaped = false; while (nextIndex < headerValue.length()) { char ch = headerValue.charAt(nextIndex); if (ch == ';') { if (!quoted) { break; } } else if (!escaped && ch == '"') { quoted = !quoted; } escaped = (!escaped && ch == '\\'); nextIndex++; } String part = headerValue.substring(index + 1, nextIndex).trim(); if (!part.isEmpty()) { parts.add(part); } index = nextIndex; } while (index < headerValue.length()); } return parts; } /** * Decode the given header field param as described in RFC 5987. * <p>Only the US-ASCII, UTF-8 and ISO-8859-1 charsets are supported. * * @param filename the filename * @param charset the charset for the filename * @return the encoded header field param */ private static String decodeFilename(String filename, Charset charset) { if (filename == null) { throw new IllegalArgumentException("'input' String` should not be null"); } if (charset == null) { throw new IllegalArgumentException("'charset' should not be null"); } byte[] value = filename.getBytes(charset); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int index = 0; while (index < value.length) { byte b = value[index]; if (isRFC5987AttrChar(b)) { byteArrayOutputStream.write((char) b); index++; } else if (b == '%' && index < value.length - 2) { char[] array = new char[] {(char) value[index + 1], (char) value[index + 2]}; try { byteArrayOutputStream.write(Integer.parseInt(String.valueOf(array), 16)); } catch (NumberFormatException ex) { throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT, ex); } index += 3; } else { throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT); } } try { return byteArrayOutputStream.toString(charset.name()); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Failed to copy contents of ByteArrayOutputStream into a String", e); } } private static boolean isRFC5987AttrChar(byte c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '!' || c == '#' || c == '$' || c == '&' || c == '+' || c == '-' || c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~'; } } 被剥离)。

{{1}}