MalformedStreamException:流意外结束 [英] MalformedStreamException: Stream ended unexpectedly

查看:281
本文介绍了MalformedStreamException:流意外结束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出:

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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆