From 9bd44a1d7c6295b00710ce1206a3dcc496f3e639 Mon Sep 17 00:00:00 2001 From: Frederic Bregier Date: Sat, 7 Dec 2013 12:18:56 +0100 Subject: [PATCH] Add support for 'charset' property for multipart boundaries - Fixes #2004 --- .../HttpPostMultipartRequestDecoder.java | 14 ++++- .../multipart/HttpPostRequestDecoder.java | 60 ++++++++++++++----- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java index c6f9f25a4b..b17b9a66b1 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostMultipartRequestDecoder.java @@ -59,7 +59,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest /** * Default charset to use */ - private final Charset charset; + private Charset charset; /** * Does the last chunk already received @@ -193,10 +193,18 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest } /** - * Set from the request ContentType the multipartDataBoundary. + * Set from the request ContentType the multipartDataBoundary and the possible charset. */ private void setMultipart(String contentType) { - multipartDataBoundary = HttpPostRequestDecoder.getMultipartDataBoundary(contentType); + String[] dataBoundary = HttpPostRequestDecoder.getMultipartDataBoundary(contentType); + if (dataBoundary != null) { + multipartDataBoundary = dataBoundary[0]; + if (dataBoundary.length > 1 && dataBoundary[1] != null) { + charset = Charset.forName(dataBoundary[1]); + } + } else { + multipartDataBoundary = null; + } currentStatus = MultiPartStatus.HEADERDELIMITER; } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java index 7111dd7677..d15fefea0f 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java @@ -148,23 +148,40 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder { /** * Check from the request ContentType if this request is a Multipart request. - * @return the multipartDataBoundary if it exists, else null + * @return an array of String if multipartDataBoundary exists with the multipartDataBoundary + * as first element, charset if any as second (missing if not set), else null */ - protected static String getMultipartDataBoundary(String contentType) { - // Check if Post using "multipart/form-data; boundary=--89421926422648" + protected static String[] getMultipartDataBoundary(String contentType) { + // Check if Post using "multipart/form-data; boundary=--89421926422648 [; charset=xxx]" String[] headerContentType = splitHeaderContentType(contentType); if (headerContentType[0].toLowerCase().startsWith( - HttpHeaders.Values.MULTIPART_FORM_DATA) && - headerContentType[1].toLowerCase().startsWith( - HttpHeaders.Values.BOUNDARY)) { - String[] boundary = StringUtil.split(headerContentType[1], '='); + HttpHeaders.Values.MULTIPART_FORM_DATA)) { + int mrank = 1, crank = 2; + if (headerContentType[1].toLowerCase().startsWith( + HttpHeaders.Values.BOUNDARY)) { + mrank = 1; + crank = 2; + } else if (headerContentType[2].toLowerCase().startsWith( + HttpHeaders.Values.BOUNDARY)) { + mrank = 2; + crank = 1; + } else { + return null; + } + String[] boundary = StringUtil.split(headerContentType[mrank], '='); if (boundary.length != 2) { throw new ErrorDataDecoderException("Needs a boundary value"); } - return "--" + boundary[1]; - } else { - return null; + if (headerContentType[crank].toLowerCase().startsWith( + HttpHeaders.Values.CHARSET)) { + String[] charset = StringUtil.split(headerContentType[crank], '='); + if (charset.length > 1) { + return new String[] {"--" + boundary[1], charset[1]}; + } + } + return new String[] {"--" + boundary[1]}; } + return null; } @Override @@ -228,26 +245,37 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder { } /** - * Split the very first line (Content-Type value) in 2 Strings + * Split the very first line (Content-Type value) in 3 Strings * - * @return the array of 2 Strings + * @return the array of 3 Strings */ private static String[] splitHeaderContentType(String sb) { int aStart; int aEnd; int bStart; int bEnd; + int cStart; + int cEnd; aStart = HttpPostBodyUtil.findNonWhitespace(sb, 0); aEnd = sb.indexOf(';'); if (aEnd == -1) { - return new String[] { sb, "" }; + return new String[] { sb, "", "" }; } + bStart = HttpPostBodyUtil.findNonWhitespace(sb, aEnd + 1); if (sb.charAt(aEnd - 1) == ' ') { aEnd--; } - bStart = HttpPostBodyUtil.findNonWhitespace(sb, aEnd + 1); - bEnd = HttpPostBodyUtil.findEndOfString(sb); - return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd) }; + bEnd = sb.indexOf(';', bStart); + if (bEnd == -1) { + bEnd = HttpPostBodyUtil.findEndOfString(sb); + return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), "" }; + } + cStart = HttpPostBodyUtil.findNonWhitespace(sb, bEnd + 1); + if (sb.charAt(bEnd - 1) == ' ') { + bEnd--; + } + cEnd = HttpPostBodyUtil.findEndOfString(sb); + return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), sb.substring(cStart, cEnd) }; } /**