From 46f99a6f2e61e6e0d57c95994e6751ccc40a4e50 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sat, 31 Dec 2022 21:46:56 -0500 Subject: [PATCH 01/12] Workflow tweaks --- .github/workflows/gradle.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index ef31be6..e4f46c2 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -15,13 +15,15 @@ jobs: java-version: [ 11, 17, 19 ] steps: - - uses: actions/checkout@v2 + - name: Checkout source repository + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up JDK ${{ matrix.java-version }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: 'temurin' java-version: ${{ matrix.java-version }} - name: Grant execute permission for gradlew From 8bf54f8eca1478169668a3c77cd726dac3456221 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 31 Dec 2022 18:50:10 -0800 Subject: [PATCH 02/12] Minor cleanup --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d72c1c9..902ab60 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ A simple library to encode/decode URL parameters. This library was extracted from the [RIFE2 Web Application Framework](https://rife2.com). A Kotlin version can also be found at [https://github.com/ethauvin/urlencoder](https://github.com/ethauvin/urlencoder). -For decades, we've been using `[java.net.URLEncoder](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URLEncoder.html) +For decades, we've been using [java.net.URLEncoder](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URLEncoder.html) because of its improper naming. It is actually intended to encode HTML form parameters, not URLs, causing the wrong escape sequences to be used. -Additionally, java.net.URLEncoder allocates memory even when no encoding is +Additionally, `java.net.URLEncoder` allocates memory even when no encoding is necessary, significantly impacting performance. This library has a negligible performance impact when the string that is passed in doesn't need to be encoded. @@ -25,12 +25,10 @@ also addresses these issues. ```java UrlEncoder.encode("a test &"); // -> "a%20test%20%26" -UrlEncoder.encode("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~"); // -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~" UrlEncoder.encode("%#okékÉȢ smile!😁"); // -> "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81" UrlEncoder.encode("?test=a test", "?="); // -> ?test=a%20test UrlEncoder.decode("a%20test%20%26"); // -> "a test &" -UrlEncoder.decode("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~"); // -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~" UrlEncoder.decode("%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81"); // -> "%#okékÉȢ smile!😁" ``` From 73942dcd49320fc2e22ccc26c9c292c4a107d381 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 01:49:49 -0500 Subject: [PATCH 03/12] Changed version to 1.0.0 --- README.md | 2 +- lib/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 902ab60..a267f82 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ To use with [Gradle](https://gradle.org/), include the following dependency in y ```gradle dependencies { - implementation("com.uwyn:urlencoder:0.9-SNAPSHOT") + implementation("com.uwyn:urlencoder:1.0.0") } ``` diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index d4d2d43..12c008c 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -10,7 +10,7 @@ group = "com.uwyn" base { archivesName.set("urlencoder") - version = "0.9-SNAPSHOT" + version = "1.0.0" } java { From 1e4a930864467abef9a19f042a11921478d644f8 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 02:00:11 -0500 Subject: [PATCH 04/12] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a267f82..d27e5ed 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ [![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Nexus Snapshot](https://img.shields.io/nexus/s/com.uwyn/urlencoder?server=https%3A%2F%2Fs01.oss.sonatype.org%2F)](https://s01.oss.sonatype.org/content/repositories/snapshots/com/uwyn/urlencoder/) +[![Release](https://img.shields.io/github/release/gbevin/urlencoder.svg)](https://github.com/gbevin/urlencoder/releases/latest) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.uwyn/urlencoder/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/com.uwyn/urlencoder) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=gbevin_urlencoder&metric=alert_status)](https://sonarcloud.io/dashboard?id=gbevin_urlencoder) [![GitHub CI](https://github.com/gbevin/urlencoder/actions/workflows/gradle.yml/badge.svg)](https://github.com/gbevin/urlencoder/actions/workflows/gradle.yml) From f5485bf2d50c5e5ab12b0441f1e5b32bcfd64646 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 02:00:58 -0500 Subject: [PATCH 05/12] Changed version to 1.0.1-SNAPSHOT --- lib/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 12c008c..67fb282 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -10,7 +10,7 @@ group = "com.uwyn" base { archivesName.set("urlencoder") - version = "1.0.0" + version = "1.0.1-SNAPSHOT" } java { From 9af78b38d941df1f451d8329b318014a48aa9bd0 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 31 Dec 2022 23:20:31 -0800 Subject: [PATCH 06/12] Minor cleanup --- README.md | 5 +++-- lib/build.gradle.kts | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d27e5ed..984afcf 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,11 @@ parameters, not URLs, causing the wrong escape sequences to be used. Additionally, `java.net.URLEncoder` allocates memory even when no encoding is necessary, significantly impacting performance. This library has a negligible -performance impact when the string that is passed in doesn't need to be encoded. +performance impact when a specified string doesn't need to be encoded. Android's [Uri.encode](https://developer.android.com/reference/android/net/Uri#encode(java.lang.String,%20java.lang.String)) -also addresses these issues. +also addresses these issues, but does not currently support [unicode surrogate pairs](https://learn.microsoft.com/en-us/globalization/encoding/surrogate-pairs). + ## Examples (TL;DR) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 67fb282..415985e 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -7,10 +7,10 @@ plugins { } group = "com.uwyn" +version = "1.0.1-SNAPSHOT" base { - archivesName.set("urlencoder") - version = "1.0.1-SNAPSHOT" + archivesName.set(rootProject.name) } java { @@ -51,11 +51,11 @@ tasks.named("test") { publishing { publications { create("mavenJava") { - artifactId = "urlencoder" + artifactId = rootProject.name from(components["java"]) pom { - name.set("URL Encoder") - description.set("A simple library to encode/decode URL parameters.") + name.set("URLEncoder") + description.set("A simple library to encode/decode URL parameters") url.set("https://github.com/gbevin/urlencoder") licenses { license { @@ -99,4 +99,4 @@ publishing { signing { sign(publishing.publications["mavenJava"]) -} \ No newline at end of file +} From 79264bdb68c4ee3ab2f906c5a6d905180d89e9a3 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 31 Dec 2022 23:37:33 -0800 Subject: [PATCH 07/12] Added Maven Central URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 984afcf..ef9d3f2 100644 --- a/README.md +++ b/README.md @@ -44,4 +44,4 @@ dependencies { } ``` -Instructions for using with Maven, Ivy, etc. can be found on Maven Central. +Instructions for using with Maven, Ivy, etc. can be found on [Maven Central](https://maven-badges.herokuapp.com/maven-central/com.uwyn/urlencoder). From 3171b82ae17ec8005580447a9d527745a5701de5 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 02:49:58 -0500 Subject: [PATCH 08/12] Added main method for command line usage --- lib/build.gradle.kts | 6 ++++ .../java/com/uwyn/urlencoder/UrlEncoder.java | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 415985e..ae809c3 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -21,6 +21,12 @@ java { } } +tasks.jar { + manifest { + attributes["Main-Class"] = "com.uwyn.urlencoder.UrlEncoder" + } +} + tasks.jacocoTestReport { reports { xml.required.set(true) diff --git a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java index 080af04..5e4a092 100644 --- a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java +++ b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java @@ -218,4 +218,40 @@ public final class UrlEncoder { private static boolean isUnreservedUriChar(char ch) { return ch <= '~' && UNRESERVED_URI_CHARS.get(ch); } + + public static void main(String[] arguments) { + var valid_arguments = true; + if (arguments.length < 1 || + arguments.length > 2) { + valid_arguments = false; + } else if (!arguments[0].startsWith("-")) { + if (arguments.length > 1) { + valid_arguments = false; + } + } else { + if (!arguments[0].equals("-e") && + !arguments[0].equals("-d")) { + valid_arguments = false; + } + } + + if (!valid_arguments) { + System.err.println("Usage : java " + UrlEncoder.class.getName() + " [-ed] text"); + System.err.println("Encode and decode URL parameters."); + System.err.println(" -e encode (default)"); + System.err.println(" -d decode"); + System.exit(1); + } + + if (1 == arguments.length) { + System.out.println(UrlEncoder.encode(arguments[0])); + System.exit(0); + } else if (arguments[0].equals("-e")) { + System.out.println(UrlEncoder.encode(arguments[1])); + System.exit(0); + } + + System.out.println(UrlEncoder.decode(arguments[1])); + System.exit(0); + } } From f3c7853d02640f98a12d219616b8346a24435f2a Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 03:27:11 -0500 Subject: [PATCH 09/12] Reworked main method for testability. --- .../java/com/uwyn/urlencoder/UrlEncoder.java | 50 ++++++++++++----- .../com/uwyn/urlencoder/UrlEncoderTest.java | 55 +++++++++++++++++++ 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java index 5e4a092..439a069 100644 --- a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java +++ b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java @@ -67,7 +67,7 @@ public final class UrlEncoder { byte[] bytes_buffer = null; var bytes_pos = 0; var i = 0; - while(i < length) { + while (i < length) { ch = source.charAt(i); if (ch == '%') { @@ -137,7 +137,7 @@ public final class UrlEncoder { * @since 1.0 */ public static String encode(String source) { - return encode(source, (String)null); + return encode(source, (String) null); } /** @@ -174,7 +174,7 @@ public final class UrlEncoder { StringBuilder out = null; char ch; var i = 0; - while(i < source.length()) { + while (i < source.length()) { ch = source.charAt(i); if (isUnreservedUriChar(ch) || (allow != null && allow.indexOf(ch) != -1)) { if (out != null) { @@ -219,7 +219,17 @@ public final class UrlEncoder { return ch <= '~' && UNRESERVED_URI_CHARS.get(ch); } - public static void main(String[] arguments) { + static class MainResult { + final String output; + final int status; + + public MainResult(String output, int status) { + this.output = output; + this.status = status; + } + } + + static MainResult handleMain(String[] arguments) { var valid_arguments = true; if (arguments.length < 1 || arguments.length > 2) { @@ -236,22 +246,32 @@ public final class UrlEncoder { } if (!valid_arguments) { - System.err.println("Usage : java " + UrlEncoder.class.getName() + " [-ed] text"); - System.err.println("Encode and decode URL parameters."); - System.err.println(" -e encode (default)"); - System.err.println(" -d decode"); - System.exit(1); + return new MainResult("Usage : java " + UrlEncoder.class.getName() + " [-ed] text" + System.lineSeparator() + + "Encode and decode URL parameters." + System.lineSeparator() + + " -e encode (default)" + System.lineSeparator() + + " -d decode" + System.lineSeparator(), 1); } if (1 == arguments.length) { - System.out.println(UrlEncoder.encode(arguments[0])); - System.exit(0); + return new MainResult(UrlEncoder.encode(arguments[0]), 0); } else if (arguments[0].equals("-e")) { - System.out.println(UrlEncoder.encode(arguments[1])); - System.exit(0); + return new MainResult(UrlEncoder.encode(arguments[1]), 0); } - System.out.println(UrlEncoder.decode(arguments[1])); - System.exit(0); + return new MainResult(UrlEncoder.decode(arguments[1]), 0); + } + + public static void main(String[] arguments) { + var result = handleMain(arguments); + switch (result.status) { + case 0: { + System.out.println(result.output); + System.exit(0); + } + case 1: { + System.err.println(result.output); + System.exit(1); + } + } } } diff --git a/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java b/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java index 530dd4c..0f5c67b 100644 --- a/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java +++ b/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java @@ -43,4 +43,59 @@ class UrlEncoderTest { assertEquals("?test=a%20test", UrlEncoder.encode("?test=a test", '?', '=')); assertEquals("aaa", UrlEncoder.encode("aaa", 'a')); } + + @Test + void testMainNoArgs() { + var result = UrlEncoder.handleMain(new String[0]); + assertEquals(1, result.status); + assertTrue(result.output.contains(UrlEncoder.class.getName())); + } + + @Test + void testMainTooManyArgs() { + var result = UrlEncoder.handleMain(new String[] {"-x", "-g", "f"}); + assertEquals(1, result.status); + assertTrue(result.output.contains(UrlEncoder.class.getName())); + } + + @Test + void testMainWrongArgs2() { + var result = UrlEncoder.handleMain(new String[] {"-x", "txt"}); + assertEquals(1, result.status); + assertTrue(result.output.contains(UrlEncoder.class.getName())); + } + + @Test + void testMainWrongArgs1() { + var result = UrlEncoder.handleMain(new String[] {"-p"}); + assertEquals(1, result.status); + assertTrue(result.output.contains(UrlEncoder.class.getName())); + } + + @Test + void testDecodeMainOption() { + validMap.forEach((expected, source) -> { + var result = UrlEncoder.handleMain(new String[] {"-d", source}); + assertEquals(0, result.status); + assertEquals(expected, result.output); + }); + } + + @Test + void testEncodeMainDefault() { + validMap.forEach((source, expected) -> { + var result = UrlEncoder.handleMain(new String[] {source}); + assertEquals(0, result.status); + assertEquals(expected, result.output); + }); + } + + @Test + void testEncodeMainOption() { + validMap.forEach((source, expected) -> { + var result = UrlEncoder.handleMain(new String[] {"-e", source}); + assertEquals(0, result.status); + assertEquals(expected, result.output); + }); + } } From 48bc3210588234ef3907658d286d45ce2dba9ca8 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 03:30:28 -0500 Subject: [PATCH 10/12] Code cleanup --- .../main/java/com/uwyn/urlencoder/UrlEncoder.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java index 439a069..87e7635 100644 --- a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java +++ b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java @@ -263,15 +263,12 @@ public final class UrlEncoder { public static void main(String[] arguments) { var result = handleMain(arguments); - switch (result.status) { - case 0: { - System.out.println(result.output); - System.exit(0); - } - case 1: { - System.err.println(result.output); - System.exit(1); - } + if (result.status == 0) { + System.out.println(result.output); + System.exit(0); + } else { + System.err.println(result.output); + System.exit(result.status); } } } From bfeb89437293f748c093b152e57aa55e21293a41 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 03:31:36 -0500 Subject: [PATCH 11/12] Remove spurious line separator --- lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java index 87e7635..497d58a 100644 --- a/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java +++ b/lib/src/main/java/com/uwyn/urlencoder/UrlEncoder.java @@ -249,7 +249,7 @@ public final class UrlEncoder { return new MainResult("Usage : java " + UrlEncoder.class.getName() + " [-ed] text" + System.lineSeparator() + "Encode and decode URL parameters." + System.lineSeparator() + " -e encode (default)" + System.lineSeparator() + - " -d decode" + System.lineSeparator(), 1); + " -d decode", 1); } if (1 == arguments.length) { From 2ae47b770fe76ab9ac4c2f6f50b5c5b2fb0bf5e1 Mon Sep 17 00:00:00 2001 From: Geert Bevin Date: Sun, 1 Jan 2023 03:35:24 -0500 Subject: [PATCH 12/12] A little more test coverage --- .../java/com/uwyn/urlencoder/UrlEncoderTest.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java b/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java index 0f5c67b..b587598 100644 --- a/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java +++ b/lib/src/test/java/com/uwyn/urlencoder/UrlEncoderTest.java @@ -23,6 +23,7 @@ class UrlEncoderTest { @Test void testDecodeURL() { assertNull(UrlEncoder.decode(null)); + assertSame("", UrlEncoder.decode("")); assertSame(same, UrlEncoder.decode(same)); validMap.forEach((expected, source) -> assertEquals(expected, UrlEncoder.decode(source))); @@ -58,6 +59,13 @@ class UrlEncoderTest { assertTrue(result.output.contains(UrlEncoder.class.getName())); } + @Test + void testMainWrongArgs1() { + var result = UrlEncoder.handleMain(new String[] {"-p"}); + assertEquals(1, result.status); + assertTrue(result.output.contains(UrlEncoder.class.getName())); + } + @Test void testMainWrongArgs2() { var result = UrlEncoder.handleMain(new String[] {"-x", "txt"}); @@ -66,8 +74,8 @@ class UrlEncoderTest { } @Test - void testMainWrongArgs1() { - var result = UrlEncoder.handleMain(new String[] {"-p"}); + void testMainWrongArgs3() { + var result = UrlEncoder.handleMain(new String[] {"stuff", "txt"}); assertEquals(1, result.status); assertTrue(result.output.contains(UrlEncoder.class.getName())); }