diff --git a/src/zutil/net/http/HttpClient.java b/src/zutil/net/http/HttpClient.java index 2741d4b..daeb84a 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-2024 Ziver Koc + * Copyright (c) 2020-2025 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 @@ -114,8 +114,15 @@ public class HttpClient implements AutoCloseable { this.absoluteURL = absoluteURL; } + public HttpURL getURL() { + return url; + } + /** - * Adds a parameter to the request + * Adds a URL parameter to the request + * + * @param key the parameter key + * @param value the value of the parameter */ public void setParameter(String key, String value) { url.setParameter(key, value); @@ -123,6 +130,9 @@ public class HttpClient implements AutoCloseable { /** * Adds a cookie to the request + * + * @param key the cookie key + * @param value the value of the cookie */ public void setCookie(String key, String value) { cookies.put(key, value); @@ -130,6 +140,9 @@ public class HttpClient implements AutoCloseable { /** * Adds a header value to the request + * + * @param key the header key + * @param value the value of the header */ public void setHeader(String key, String value) { headers.put(key, value); @@ -180,10 +193,13 @@ public class HttpClient implements AutoCloseable { // Request // --------------------------------- + boolean isPost = HttpRequestType.POST.toString().equals(type); + boolean parametersInBody = isPost && content == null; + HttpPrintStream request = new HttpPrintStream(conn.getOutputStream(), HttpMessageType.REQUEST); request.setProtocol(protocol); request.setRequestType(type); - request.setRequestURL(absoluteURL ? url.getURL() : url.getHttpURL()); + request.setRequestURL(absoluteURL ? url.getURL() : url.getHttpURL(!parametersInBody)); request.setHeaders(headers); request.setCookies(cookies); @@ -197,7 +213,7 @@ public class HttpClient implements AutoCloseable { if (content != null) { payload = content; - } else if (HttpRequestType.POST.toString().equals(type)) { + } else if (parametersInBody) { payload = url.getParameterString(); } diff --git a/src/zutil/net/http/HttpURL.java b/src/zutil/net/http/HttpURL.java index 77c99ef..3afe3db 100755 --- a/src/zutil/net/http/HttpURL.java +++ b/src/zutil/net/http/HttpURL.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020 Ziver Koc + * Copyright (c) 2020-2025 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 @@ -26,6 +26,8 @@ package zutil.net.http; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; /** @@ -187,22 +189,25 @@ public class HttpURL { for (String key : parameters.keySet()) { if (param.length() > 0) param.append('&'); - param.append(key); + param.append(URLEncoder.encode(key)); param.append('='); - param.append(parameters.get(key)); + param.append(URLEncoder.encode(parameters.get(key))); } return param.toString(); } /** - * Generates a path that are used in the HTTP header + * Generates a path that are used in the HTTP header which includes the path and ? and parameters if parameters have any items. + * + * @param includeParameters if true will include URL parameters after a '?' character, if false then only the path will be returned. */ - public String getHttpURL() { + public String getHttpURL(boolean includeParameters) { StringBuilder url = new StringBuilder(); url.append(path); - if (!parameters.isEmpty()) - url.append(PARAMETER_SEPARATOR).append(getParameterString()); + if (includeParameters && !parameters.isEmpty()) { + url.append(PARAMETER_SEPARATOR).append(getParameterString()); + } return url.toString(); } diff --git a/src/zutil/net/ws/rest/RESTClient.java b/src/zutil/net/ws/rest/RESTClient.java index d36f916..2d35bc4 100644 --- a/src/zutil/net/ws/rest/RESTClient.java +++ b/src/zutil/net/ws/rest/RESTClient.java @@ -1,5 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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.ws.rest; +import zutil.MimeTypeUtil; import zutil.io.IOUtil; import zutil.log.LogUtil; import zutil.net.http.HttpClient; @@ -8,6 +33,7 @@ import zutil.net.http.HttpURL; import zutil.net.ws.WSInterface.RequestType; import zutil.parser.DataNode; import zutil.parser.json.JSONParser; +import zutil.parser.json.JSONWriter; import java.io.IOException; import java.util.logging.Logger; @@ -18,6 +44,13 @@ import java.util.logging.Logger; public class RESTClient { private static Logger logger = LogUtil.getLogger(); + + private HttpClient request; + + // -------------------------------------------------------------- + // Static functions + // -------------------------------------------------------------- + /** * See {@link #request(RequestType, HttpURL)} for details. */ @@ -57,10 +90,55 @@ public class RESTClient { * @return a DataNode object parsed from the JSON response from the REST endpoint. */ public static DataNode request(RequestType type, HttpURL url) throws IOException { - HttpClient request = new HttpClient(String.valueOf(type)); - request.setURL(url); + RESTClient client = new RESTClient(type, url); + return client.send(); + } - logger.fine("Sending request for: " + url); + // -------------------------------------------------------------- + // Object Code + // -------------------------------------------------------------- + + public RESTClient(RequestType type, HttpURL url) { + request = new HttpClient(String.valueOf(type)); + request.setURL(url); + } + + /** + * Adds a URL parameter to the request + * + * @param key the parameter key + * @param value the value of the parameter + */ + public void setParameter(String key, String value) { + request.setParameter(key, value); + } + + /** + * Adds a header value to the request + * + * @param key the header key + * @param value the value of the header + */ + public void setHeader(String key, String value) { + request.setHeader(key, value); + } + + /** + * @param body Specify the body content. + */ + public void setBody(DataNode body) { + request.setContent(JSONWriter.toString(body)); + } + + /** + * @param body Specify the body content. + */ + public void setBody(String body) { + request.setContent(body); + } + + public DataNode send() throws IOException { + logger.fine("Sending request for: " + request.getURL()); HttpHeader responseHeader = request.send(); logger.fine("Received response code: " + responseHeader.getResponseStatusCode());