Кажется, проблема связана с неправильным концом строки и способом получения границы. Согласно цитате 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