
fi.evolver.utils.http.MultipartStream Maven / Gradle / Ivy
package fi.evolver.utils.http;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MultipartStream {
private enum State { PART_BEGIN, MID_PART, FINISHED }
private static final Pattern BOUNDARY_PATTERN = Pattern.compile("(? headers = parseHeaders(parser);
return new Part(headers, new PartInputStream(parser, fullBoundary));
}
private static Map parseHeaders(StreamParser parser) throws IOException {
Map headers = new LinkedHashMap<>();
byte[] line;
while ((line = parser.readLine()).length > 0) {
String data = new String(line, StandardCharsets.ISO_8859_1);
String[] parts = data.split(": ", 2);
headers.put(parts[0], parts.length == 2 ? parts[1] : null);
}
return headers;
}
private static byte[] parseBoundary(String contentType) throws IOException {
Matcher matcher = BOUNDARY_PATTERN.matcher(contentType);
if (!matcher.find())
throw new IOException("Could not parse boundary from content type: " + contentType);
return matcher.group(1).getBytes(StandardCharsets.ISO_8859_1);
}
private static byte[] join(byte[]... arrays) {
int length = 0;
for (byte[] array: arrays)
length += array.length;
int i = 0;
byte[] result = new byte[length];
for (byte[] array: arrays) {
System.arraycopy(array, 0, result, i, array.length);
i += array.length;
}
return result;
}
private static class StreamParser {
private final BufferedInputStream in;
public StreamParser(InputStream in) {
this.in = new BufferedInputStream(in);
}
public boolean accept(byte[] token) throws IOException {
in.mark(token.length);
for (int i = 0; i < token.length; ++i) {
if (in.read() != token[i]) {
in.reset();
return false;
}
}
return true;
}
public byte[] readLine() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
char c;
while ((c = (char)in.read()) != '\r')
out.write(c);
in.mark(1);
if (in.read() != '\n')
in.reset();
return out.toByteArray();
}
}
private class PartInputStream extends InputStream {
private final StreamParser partParser;
private final byte[] boundary;
private boolean finished;
public PartInputStream(StreamParser parser, byte[] boundary) {
state = State.MID_PART;
this.partParser = parser;
this.boundary = boundary;
}
@Override
public int read() throws IOException {
if (finished)
return -1;
if (partParser.accept(boundary)) {
finished = true;
state = partParser.accept(DOUBLE_DASH) ? State.FINISHED : State.PART_BEGIN;
partParser.accept(LINE_CHANGE);
return -1;
}
return partParser.in.read();
}
@Override
public void close() throws IOException {
while (read() != -1) { /* Skip unread content */ }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy