From 66e7ed4aafd23b8275d231f35066ea040542413e Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Sat, 28 Dec 2024 22:10:57 +0100 Subject: [PATCH] Added test case for HttpClient and fixed a small newline issue with the payload --- src/zutil/net/http/HttpClient.java | 56 ++++++++----- test/zutil/net/http/HttpClientTest.java | 103 ++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 22 deletions(-) create mode 100644 test/zutil/net/http/HttpClientTest.java diff --git a/src/zutil/net/http/HttpClient.java b/src/zutil/net/http/HttpClient.java index 03fd70c..2741d4b 100755 --- a/src/zutil/net/http/HttpClient.java +++ b/src/zutil/net/http/HttpClient.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020 Ziver Koc + * Copyright (c) 2020-2024 Ziver Koc * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -143,30 +143,38 @@ public class HttpClient implements AutoCloseable { this.content = content; } + protected Socket getSocket(int port) throws IOException { + Socket socket = null; + + if ("https".equals(url.getProtocol())) { + socket = SSLSocketFactory.getDefault().createSocket(url.getHost(), port); + ((SSLSocket)socket).startHandshake(); + } else { + socket = new Socket(url.getHost(), port); + } + + return socket; + } + /** * Will send a HTTP request to the target host. * NOTE: any previous request connections will be closed */ public HttpHeader send() throws IOException { int port = 80; - if (url == null) + if (url == null) { throw new IllegalArgumentException("No URL defined for request."); - else if (url.getPort() > 0) + } else if (url.getPort() > 0) { port = url.getPort(); - else if ("https".equals(url.getProtocol())) + } else if ("https".equals(url.getProtocol())) { port = 443; + } // --------------------------------- // Create Socket // --------------------------------- - Socket conn; - if ("https".equals(url.getProtocol())) { - conn = SSLSocketFactory.getDefault().createSocket(url.getHost(), port); - ((SSLSocket)conn).startHandshake(); - } else { - conn = new Socket(url.getHost(), port); - } + Socket conn = getSocket(port); // --------------------------------- // Request @@ -185,17 +193,21 @@ public class HttpClient implements AutoCloseable { // send payload - if (HttpRequestType.POST.toString().equals(type)) { - String postData; - if (content != null) - postData = content; - else - postData = url.getParameterString(); - request.setHeader(HttpHeader.HEADER_CONTENT_LENGTH, "" + postData.length()); - request.println(); - request.print(postData); - } else - request.println(); + String payload = null; + + if (content != null) { + payload = content; + } else if (HttpRequestType.POST.toString().equals(type)) { + payload = url.getParameterString(); + } + + if (payload != null) { + request.setHeader(HttpHeader.HEADER_CONTENT_LENGTH, "" + payload.length()); + request.print(payload); + } + + // Finish off by sending all buffered data + request.flush(); // --------------------------------- diff --git a/test/zutil/net/http/HttpClientTest.java b/test/zutil/net/http/HttpClientTest.java new file mode 100644 index 0000000..867eebe --- /dev/null +++ b/test/zutil/net/http/HttpClientTest.java @@ -0,0 +1,103 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package zutil.net.http; + +import org.junit.Test; +import zutil.io.StringInputStream; +import zutil.io.StringOutputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import static org.junit.Assert.*; + + +public class HttpClientTest { + + private class HttpClientMock extends HttpClient { + StringOutputStream outputStream = new StringOutputStream(); + StringInputStream inputStream = new StringInputStream(); + + public HttpClientMock(HttpRequestType httpRequestType) { + super(httpRequestType); + } + + @Override + protected Socket getSocket(int port) throws IOException { + return new Socket() { + + @Override + public OutputStream getOutputStream() { + return outputStream; + } + + @Override + public InputStream getInputStream(){ + return inputStream; + } + }; + } + } + + @Test + public void sendPostJson() throws IOException { + HttpClientMock client = new HttpClientMock(HttpClient.HttpRequestType.POST); + client.setURL("https://example.com/v1-beta/gql"); + client.setHeader("Authorization", "Bearer ABCDEF"); + client.setHeader("Content-Type", "application/json"); + String requestQuery = + "{\"query\": \"{" + + "viewer {" + + "homes {" + + "consumption(resolution: HOURLY, last: 1) {" + + "nodes {" + + "from " + + "to " + + "cost " + // Total cost + "unitPrice " + // Cost per Kwh + "unitPriceVAT " + // Cost per Kwh with taxes + "consumption " + // Total consumption + "consumptionUnit " + // Should be Kwh + "}" + + "}" + + "}" + + "}" + + "}\"}"; + client.setContent(requestQuery); + client.send(); + + assertEquals( + "POST /v1-beta/gql HTTP/1.0" + System.lineSeparator() + + "Authorization: Bearer ABCDEF" + System.lineSeparator() + + "Content-Length: " + requestQuery.length() + System.lineSeparator() + + "Content-Type: application/json" + System.lineSeparator() + + "Host: example.com:443" + System.lineSeparator() + + System.lineSeparator() + + requestQuery, + client.outputStream.toString()); + } +} \ No newline at end of file