这个问题似乎是由于一个坏的线端和边界的检索方式。
根据A
RFC2046
引用自
SO answer
:
多部分实体的内容类型字段需要一个参数“boundary”。边界分隔符行定义为
完全由两个连字符组成的线
字符(“-”,十进制值45)
后接边界参数值
从content type header字段,可选的线性空白,和
终止CRLF
.
问题恰恰在于两点:
行尾类型
以及
两个连字符
在边界参数值之前。
行尾
因为你的代码没有准确显示bytestring的值,所以我尝试了两种方法
低频
(
\n
)
慢性淋巴细胞白血病
(
\r\n
)最后看看会发生什么。
当
坏的
行尾-即不是CRLF-是
就在之前
这个
最后边界
,如下所示:
String byteString=
"-----------------------------149742642616556\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"\r\n" +
"test\r\n" + // <-- only \n here lead to a MalformedStreamException
"-----------------------------149742642616556--\r\n";
听起来,multipartstream无法解析边界的开头,因为它没有在前一行捕获右行结尾(crlf)。
所以,我你用了低频终结者,你应该用低频终结者来代替。
边界格式
rfc告诉我们
定界符
是两个连字符+边界参数+crlf。regexp不仅捕获边界参数值,还包含两个连字符。所以我替换了这部分:
// capturing group = boundary parameter value
String regexp="(?m)\\A--(-*\\d+)$";
// [...]
while (matcher.find()) {
boundary = matcher.group(1);
// [...]
}
工作代码
作为MCVE运行
下面的代码可以在没有tomcat的控制台中运行。只有
commons-fileupload-1.3.3-bin.tar.gz
和
commons-io-2.6-bin.tar.gz
是需要的。
查看
MultipartStream
,我临时替换了
bos
通过
System.out
在
readBodyData()
打电话(如评论中所述)。
-
编译:
javac Test.java -classpath ./commons-fileupload-1.3.3-bin/commons-fileupload-1.3.3.jar
-
运行:
java -classpath ./commons-fileupload-1.3.3-bin/commons-fileupload-1.3.3.jar:./commons-io-2.6/commons-io-2.6.jar:. Test
代码本身
import java.util.regex.*;
import java.io.*;
import org.apache.commons.fileupload.*;
public class Test {
public final static void main(String[] argv) {
String byteString=
"-----------------------------149742642616556\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"\r\n" +
"test\r\n" + // <-- only \n here lead to a MalformedStreamException
"-----------------------------149742642616556--\r\n";
String regexp="(?m)\\A--(-*\\d+)$"; // edited regexp to catch the right boundary
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(byteString);
String boundary = null;
String contentType=null;
while (matcher.find()) {
boundary = matcher.group(1);
contentType = "multipart/form-data; boundary=\"" + boundary + "\"";
}
System.out.println("boundary = \"" + boundary + "\"");
@SuppressWarnings("deprecation")
org.apache.commons.fileupload.MultipartStream multipartStream =
new org.apache.commons.fileupload.MultipartStream
(new ByteArrayInputStream(byteString.getBytes()), boundary.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
// Use the commented line instead the following one
// To see what the multipartStream is reading (for debug)
// multipartStream.readBodyData(System.out);
multipartStream.readBodyData(bos);
} catch (MultipartStream.MalformedStreamException e) {
System.out.println("Malformed Exception " + e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
byte[] byteBody = bos.toByteArray();
// Displaying the body read
for(byte c : byteBody) {
System.out.format("%c", c);
}
System.out.println();
}
}
输出:
boundary = "---------------------------149742642616556"
-----------------------------149742642616556
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain; charset=UTF-8
test