MalformedStreamException: поток завершился неожиданно - PullRequest
0 голосов
/ 27 ноября 2018

Дано:

byteString равно

-----------------------------149742642616556
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain

test
-----------------------------149742642616556--

Тогда этот код (не оптимизирован):

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)

Что здесь может быть не так?Буду признателен за помощь здесь.

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

После некоторой отладки я обнаружил, что MultipartStream добавляет \r\n-- в качестве префикса к границе, потому что у меня не было новой строки в начале содержимого, я получил исключение MultipartStream.MalformedStreamException("Stream ended unexpectedly"), потому что граница не моглане может быть найдено.

Возможно, это из-за более старой версии commons-fileupload или из-за того, что я читал многокомпонентный контент из запроса HTTP PUT, отправленного curl

tl;dr

добавьте новую строку в начале вашего контента, если больше ничего не помогло.

0 голосов
/ 29 ноября 2018

Кажется, проблема связана с неправильным концом строки и способом получения границы. Согласно цитате RFC2046 , взятой из ответа SO :

Для поля Content-Type для составных объектов требуется один параметр - border.Строка ограничителя границы затем определяется как строка, состоящая полностью из двух дефисов символов ("-", десятичное значение 45) , за которыми следует значение параметра границы из поля заголовка Content-Type, необязательный линейный пробел и завершающий CRLF .

Проблема заключается именно в двух точках: конец типа линии и дваДефисы , предшествующие значению параметра границы.

Конец строк

Так как ваш код не показывает точно значение byteString, я попробовал оба LF (\n) и CRLF (\r\n) конец строки, чтобы увидеть, что произойдет.

Кажется, что проблема воспроизводится, когда bad конец строки -т. е. не 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) на pпредыдущая линия. Итак, если вы использовали LF-терминаторы, вы должны заменить их на CRLF.

Формат границы

RFC сообщает, что граница delimiter два дефиса + граничный параметр + CRLF.Ваше регулярное выражение не захватывает только значение граничного параметра, оно также включает два дефиса.Поэтому я заменил эту часть:

// 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...