From 92f9f247f7d809c2fd1598bf1ec6351dfcc7c6ba Mon Sep 17 00:00:00 2001 From: Nic0Nic0Nii Date: Fri, 20 May 2022 17:58:49 +0000 Subject: [PATCH] Add multipart entity --- sig/MultipartUtility.java | 151 ++++++++++++++++++++++++++++++++++ sig/requests/POSTRequest.java | 29 +++++-- test.json | 105 +++++++++++++++++++++++ 3 files changed, 280 insertions(+), 5 deletions(-) create mode 100644 sig/MultipartUtility.java create mode 100644 test.json diff --git a/sig/MultipartUtility.java b/sig/MultipartUtility.java new file mode 100644 index 0000000..2a1a55f --- /dev/null +++ b/sig/MultipartUtility.java @@ -0,0 +1,151 @@ +package sig; + +import java.io.BufferedReader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; + +/** + * This utility class provides an abstraction layer for sending multipart HTTP + * POST requests to a web server. + * @author www.codejava.net + * + */ +public class MultipartUtility { + private final String boundary; + private static final String LINE_FEED = "\r\n"; + private HttpURLConnection httpConn; + private String charset; + private OutputStream outputStream; + private PrintWriter writer; + + /** + * This constructor initializes a new HTTP POST request with content type + * is set to multipart/form-data + * @param requestURL + * @param charset + * @throws IOException + */ + public MultipartUtility(String requestURL, String charset) + throws IOException { + this.charset = charset; + + // creates a unique boundary based on time stamp + boundary = "===" + System.currentTimeMillis() + "==="; + + URL url = new URL(requestURL); + httpConn = (HttpURLConnection) url.openConnection(); + httpConn.setUseCaches(false); + httpConn.setDoOutput(true); // indicates POST method + httpConn.setDoInput(true); + httpConn.setRequestProperty("Content-Type", + "multipart/form-data; boundary=" + boundary); + httpConn.setRequestProperty("User-Agent", "CodeJava Agent"); + httpConn.setRequestProperty("Test", "Bonjour"); + outputStream = httpConn.getOutputStream(); + writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), + true); + } + + /** + * Adds a form field to the request + * @param name field name + * @param value field value + */ + public void addFormField(String name, String 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=" + charset).append( + LINE_FEED); + writer.append(LINE_FEED); + writer.append(value).append(LINE_FEED); + writer.flush(); + } + + /** + * Adds a upload file section to the request + * @param fieldName name attribute in + * @param uploadFile a File to be uploaded + * @throws IOException + */ + public void addFilePart(String fieldName, File uploadFile) + throws IOException { + String fileName = uploadFile.getName(); + writer.append("--" + boundary).append(LINE_FEED); + writer.append( + "Content-Disposition: form-data; name=\"" + fieldName + + "\"; filename=\"" + fileName + "\"") + .append(LINE_FEED); + writer.append( + "Content-Type: " + + URLConnection.guessContentTypeFromName(fileName)) + .append(LINE_FEED); + writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED); + writer.append(LINE_FEED); + writer.flush(); + + FileInputStream inputStream = new FileInputStream(uploadFile); + byte[] buffer = new byte[4096]; + int bytesRead = -1; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + inputStream.close(); + + writer.append(LINE_FEED); + writer.flush(); + } + + /** + * Adds a header field to the request. + * @param name - name of the header field + * @param value - value of the header field + */ + public void addHeaderField(String name, String value) { + writer.append(name + ": " + value).append(LINE_FEED); + writer.flush(); + } + + /** + * Completes the request and receives response from the server. + * @return a list of Strings as response in case the server returned + * status OK, otherwise an exception is thrown. + * @throws IOException + */ + public List finish() throws IOException { + List response = new ArrayList(); + + writer.append(LINE_FEED).flush(); + writer.append("--" + boundary + "--").append(LINE_FEED); + writer.close(); + + // checks server's status code first + int status = httpConn.getResponseCode(); + if (status == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader( + httpConn.getInputStream())); + String line = null; + while ((line = reader.readLine()) != null) { + response.add(line); + } + reader.close(); + httpConn.disconnect(); + } else { + throw new IOException("Server returned non-OK status: " + status); + } + + return response; + } +} \ No newline at end of file diff --git a/sig/requests/POSTRequest.java b/sig/requests/POSTRequest.java index 53d2a7e..7b808fe 100644 --- a/sig/requests/POSTRequest.java +++ b/sig/requests/POSTRequest.java @@ -1,23 +1,37 @@ package sig.requests; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; import java.net.http.HttpRequest; import java.net.http.HttpClient.Builder; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import sig.exceptions.FailedResponseException; public class POSTRequest extends GETRequest{ String body = ""; + Path uploadFile = null; - public POSTRequest(String url, String body, String username, String password, long timeout, Path file, String... headers) { - super(url, username, password, timeout, file, headers); + public POSTRequest(String url, String body, String username, String password, long timeout, Path outputFile, String... headers) { + super(url, username, password, timeout, outputFile, headers); this.body=body; } - public POSTRequest(String url, String body, long timeout, Path file, String... headers) { - super(url, timeout, file, headers); + public POSTRequest(String url, String body, long timeout, Path outputFile, String... headers) { + super(url, timeout, outputFile, headers); this.body=body; } @@ -31,6 +45,11 @@ public class POSTRequest extends GETRequest{ this.body=body; } + public POSTRequest(String url, Path uploadFile) { + super(url); + this.uploadFile=uploadFile; + } + @Override protected java.net.http.HttpRequest.Builder finalizeRequestPreBuild( java.net.http.HttpRequest.Builder requestBuild) throws FailedResponseException{ @@ -50,4 +69,4 @@ public class POSTRequest extends GETRequest{ return clientBuild; } -} +} \ No newline at end of file diff --git a/test.json b/test.json new file mode 100644 index 0000000..6d32c9a --- /dev/null +++ b/test.json @@ -0,0 +1,105 @@ +{ + "args": {}, + "data": { + "args": {}, + "data": { + "args": { + "foo1": "bar1", + "foo2": "bar2" + }, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6268427f-1fb34bbf61bee0cc55bcfced", + "default": "value", + "user-agent": "Java-http-client/11.0.13" + }, + "url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2" + }, + "files": {}, + "form": {}, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6287d143-6d0b63bb5323290e00ed4cdd", + "content-length": "305", + "content-type": "application/json", + "user-agent": "Java-http-client/11.0.13" + }, + "json": { + "args": { + "foo1": "bar1", + "foo2": "bar2" + }, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6268427f-1fb34bbf61bee0cc55bcfced", + "default": "value", + "user-agent": "Java-http-client/11.0.13" + }, + "url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2" + }, + "url": "https://postman-echo.com/post" + }, + "files": {}, + "form": {}, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6287d178-5fa9648d07a57aa20d5b8e0f", + "content-length": "945", + "content-type": "application/json", + "user-agent": "Java-http-client/11.0.13" + }, + "json": { + "args": {}, + "data": { + "args": { + "foo1": "bar1", + "foo2": "bar2" + }, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6268427f-1fb34bbf61bee0cc55bcfced", + "default": "value", + "user-agent": "Java-http-client/11.0.13" + }, + "url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2" + }, + "files": {}, + "form": {}, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6287d143-6d0b63bb5323290e00ed4cdd", + "content-length": "305", + "content-type": "application/json", + "user-agent": "Java-http-client/11.0.13" + }, + "json": { + "args": { + "foo1": "bar1", + "foo2": "bar2" + }, + "headers": { + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "host": "postman-echo.com", + "x-amzn-trace-id": "Root=1-6268427f-1fb34bbf61bee0cc55bcfced", + "default": "value", + "user-agent": "Java-http-client/11.0.13" + }, + "url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2" + }, + "url": "https://postman-echo.com/post" + }, + "url": "https://postman-echo.com/post" +} \ No newline at end of file