HTTP Post Multipart
After some research about http multipart I came up with a basic implementation in Java supporting to post the Content-Type multipart/form-data. There are a lot of information about multipart in the web and complete modules, but not so much reference implementations. Here is mine. It supports the fluent style pattern and returns the server data as a String. The post method can be called multiple times, since the object keeps it state. It uses Apache Commons to save some lines of code.
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
public class MultipartUtility {
private static final String LINE_FEED = "\r\n";
private final Map fields = new HashMap<>();
private final Map> files = new HashMap<>();
private final String requestURL;
public MultipartUtility(String requestURL) {
this.requestURL = requestURL;
}
public MultipartUtility addFormField(String name, String value) {
fields.put(name, value);
return this;
}
public MultipartUtility addFilePart(String fieldName, File uploadFile) throws IOException {
byte[] fileData = FileUtils.readFileToByteArray(uploadFile);
files.put(fieldName, new ImmutablePair<>(uploadFile.getName(), fileData));
return this;
}
public MultipartUtility addFilePart(String fieldName, String fileName, byte[] fileData) {
files.put(fieldName, new ImmutablePair<>(fileName, fileData));
return this;
}
public String post() throws IOException {
final String boundary = "===" + System.currentTimeMillis() + "===";
URL url = new URL(requestURL);
final HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
httpConn.setRequestProperty("User-Agent", "Java");
try (final OutputStream outputStream = httpConn.getOutputStream();
final PrintWriter writer = new PrintWriter(outputStream);) {
fields.forEach((name, value) -> {
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"" + name + "\"").append(LINE_FEED);
writer.append("Content-Type: text/plain; charset=UTF-8").append(LINE_FEED);
writer.append(LINE_FEED);
writer.append(value);
writer.append(LINE_FEED);
});
for (Map.Entry> file : files.entrySet()) {
Pair uploadFile = file.getValue();
String fileName = uploadFile.getLeft();
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"" + file.getKey() + "\"; filename=\"" + fileName + "\"").append(LINE_FEED);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(fileName)).append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED).append(LINE_FEED);
writer.flush();
outputStream.write(uploadFile.getRight());
outputStream.flush();
writer.append(LINE_FEED);
}
writer.append("--" + boundary + "--").append(LINE_FEED);
}
int status = httpConn.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
try (InputStream stream = httpConn.getInputStream()) {
String result = IOUtils.toString(stream, Charset.defaultCharset());
System.out.println(result);
httpConn.disconnect();
return result;
}
} else {
throw new IOException("Server returned status: " + status);
}
}
}
Here is a minimalistic example on how to use it. Suppose the interface you wanna handle relates to a HTML block like this.
<form action="https://some.tld/upload" method="post" enctype="multipart/form-data">
<input type="text" name="myText" value="test">
<input type="file" name="fileToUpload">
<button type="submit">Submit</button>
</form>
Then your code would be this.
String result = new MultipartUtility("https://some.tld/upload").addFormField("myText", "test").addFilePart("fileToUpload", file).post();