MalformedStreamException:流意外结束 [英] MalformedStreamException: Stream ended unexpectedly
问题描述
给出:
byteString
是
-----------------------------149742642616556
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
test
-----------------------------149742642616556--
然后此代码(未优化):
Then this code (not optimized):
Pattern pattern = Pattern.compile(BOUNDARY_PATTERN); // "(?m)\\A-+\\d+$"
Matcher matcher = pattern.matcher(byteString);
String boundary = null;
while (matcher.find()) {
boundary = matcher.group();
contentType = "multipart/form-data; boundary=" + boundary;
}
LOG.info("Content Type = " + contentType);
@SuppressWarnings("deprecation")
org.apache.commons.fileupload.MultipartStream multipartStream =
new org.apache.commons.fileupload.MultipartStream(new ByteArrayInputStream(byteString.getBytes()), boundary.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
multipartStream.readBodyData(bos); // throw error
byte[] byteBody = bos.toByteArray();
引发此错误:
org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:1005)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:903)
at java.io.InputStream.read(InputStream.java:101)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:100)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70)
at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:593)
这里可能有什么问题?我会在这里为您提供帮助.
What could be possibly wrong here? I would appreciate a help here.
推荐答案
问题似乎是由于行尾不良以及检索边界的方式所致. ="http://www.ietf.org/rfc/rfc2046.txt" rel ="noreferrer"> RFC2046 引自
The issue seems to be due to a bad end of line and the way the boundary is retrieved. According to a RFC2046 quote taken from a SO answer:
多部分实体的Content-Type字段需要一个参数边界".然后将边界定界符线定义为完全由两个连字符组成的行(-",十进制值45),后跟Content-Type中的边界参数值标头字段,可选的线性空格和终止CRLF .
The Content-Type field for multipart entities requires one parameter, "boundary". The boundary delimiter line is then defined as a line consisting entirely of two hyphen characters ("-", decimal value 45) followed by the boundary parameter value from the Content-Type header field, optional linear whitespace, and a terminating CRLF.
问题恰好在于两点:线型末端和边界参数值之前的两个连字符.
The problem lies precisely on two points: the end of line type and the two hyphens preceding the boundary parameter value.
由于您的代码无法正确显示byteString的值,因此我尝试将 LF (\n
)和 CRLF (\r\n
)行尾看看会发生什么.
Since your code doesn't show accurately the value of byteString, I tried both LF (\n
) and CRLF (\r\n
) end of lines to see what will happen.
当行的坏末尾(即不是CRLF)出现在最后一个边界之前 时,似乎重现了该问题,如下所示:
It appears the issue is reproduced when a bad end of line - i.e. not CRLF - is right before the last boundary, as shown below:
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). 因此,我使用了LF终结器,应将它们替换为CRLF终结器.
It sounds like the MultipartStream fails to parse the begin of the boundary, since it doesn't catch a right end of line (CRLF) on the previous line. So, I you used LF terminators, you should replace them by CRLF ones.
RFC告知边界定界符是两个连字符+边界参数+ CRLF.您的正则表达式不仅捕获边界参数值,还包括两个连字符.所以我替换了这部分:
The RFC tells that a boundary delimiter is two hyphens + boundary parameter + CRLF. Your regexp doesn't catch only the boundary parameter value, it also includes the two hyphens. So I replaced this part:
// 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 和
Working code
Runnable as a MCVE
The code you'll find below can be run in a console without Tomcat. Only commons-fileupload-1.3.3-bin.tar.gz and commons-io-2.6-bin.tar.gz are needed.
要查看MultipartStream
解析的内容,我在readBodyData()
调用中将bos
临时替换为System.out
(如评论中所述).
To view what's parsed by the MultipartStream
, I temporarily replaced bos
by System.out
in the readBodyData()
call (as told in the comments).
-
要编译:
To compile:
javac Test.java -classpath ./commons-fileupload-1.3.3-bin/commons-fileupload-1.3.3.jar
要运行:
To run:
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
这篇关于MalformedStreamException:流意外结束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!