All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.utils.http.MultipartStream Maven / Gradle / Ivy

There is a newer version: 3.5.0
Show newest version
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