Compare commits

..

13 commits

5 changed files with 144 additions and 19 deletions

View file

@ -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

View file

@ -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)
@ -10,27 +12,26 @@ 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.
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)
```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!😁"
```
@ -39,8 +40,8 @@ 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")
}
```
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).

View file

@ -7,10 +7,10 @@ plugins {
}
group = "com.uwyn"
version = "1.0.1-SNAPSHOT"
base {
archivesName.set("urlencoder")
version = "0.9-SNAPSHOT"
archivesName.set(rootProject.name)
}
java {
@ -21,6 +21,12 @@ java {
}
}
tasks.jar {
manifest {
attributes["Main-Class"] = "com.uwyn.urlencoder.UrlEncoder"
}
}
tasks.jacocoTestReport {
reports {
xml.required.set(true)
@ -51,11 +57,11 @@ tasks.named<Test>("test") {
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifactId = "urlencoder"
artifactId = rootProject.name
from(components["java"])
pom {
name.set("URLEncoder")
description.set("A simple library to encode/decode URL parameters.")
description.set("A simple library to encode/decode URL parameters")
url.set("https://github.com/gbevin/urlencoder")
licenses {
license {

View file

@ -218,4 +218,57 @@ public final class UrlEncoder {
private static boolean isUnreservedUriChar(char ch) {
return ch <= '~' && UNRESERVED_URI_CHARS.get(ch);
}
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) {
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) {
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", 1);
}
if (1 == arguments.length) {
return new MainResult(UrlEncoder.encode(arguments[0]), 0);
} else if (arguments[0].equals("-e")) {
return new MainResult(UrlEncoder.encode(arguments[1]), 0);
}
return new MainResult(UrlEncoder.decode(arguments[1]), 0);
}
public static void main(String[] arguments) {
var result = handleMain(arguments);
if (result.status == 0) {
System.out.println(result.output);
System.exit(0);
} else {
System.err.println(result.output);
System.exit(result.status);
}
}
}

View file

@ -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)));
@ -43,4 +44,66 @@ 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 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"});
assertEquals(1, result.status);
assertTrue(result.output.contains(UrlEncoder.class.getName()));
}
@Test
void testMainWrongArgs3() {
var result = UrlEncoder.handleMain(new String[] {"stuff", "txt"});
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);
});
}
}