mirror of
https://github.com/gbevin/urlencoder.git
synced 2025-04-29 08:58:11 -07:00
Compare commits
13 commits
10e793fc39
...
2ae47b770f
Author | SHA1 | Date | |
---|---|---|---|
2ae47b770f | |||
bfeb894372 | |||
48bc321058 | |||
f3c7853d02 | |||
0f12ed90cc | |||
3171b82ae1 | |||
79264bdb68 | |||
9af78b38d9 | |||
f5485bf2d5 | |||
1e4a930864 | |||
73942dcd49 | |||
8bf54f8eca | |||
46f99a6f2e |
5 changed files with 144 additions and 19 deletions
6
.github/workflows/gradle.yml
vendored
6
.github/workflows/gradle.yml
vendored
|
@ -15,13 +15,15 @@ jobs:
|
||||||
java-version: [ 11, 17, 19 ]
|
java-version: [ 11, 17, 19 ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout source repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up JDK ${{ matrix.java-version }}
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
|
|
||||||
- name: Grant execute permission for gradlew
|
- name: Grant execute permission for gradlew
|
||||||
|
|
17
README.md
17
README.md
|
@ -1,5 +1,7 @@
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://s01.oss.sonatype.org/content/repositories/snapshots/com/uwyn/urlencoder/)
|
[](https://s01.oss.sonatype.org/content/repositories/snapshots/com/uwyn/urlencoder/)
|
||||||
|
[](https://github.com/gbevin/urlencoder/releases/latest)
|
||||||
|
[](https://maven-badges.herokuapp.com/maven-central/com.uwyn/urlencoder)
|
||||||
[](https://sonarcloud.io/dashboard?id=gbevin_urlencoder)
|
[](https://sonarcloud.io/dashboard?id=gbevin_urlencoder)
|
||||||
[](https://github.com/gbevin/urlencoder/actions/workflows/gradle.yml)
|
[](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).
|
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).
|
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
|
because of its improper naming. It is actually intended to encode HTML form
|
||||||
parameters, not URLs, causing the wrong escape sequences to be used.
|
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
|
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))
|
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)
|
## Examples (TL;DR)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
UrlEncoder.encode("a test &"); // -> "a%20test%20%26"
|
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("%#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.encode("?test=a test", "?="); // -> ?test=a%20test
|
||||||
|
|
||||||
UrlEncoder.decode("a%20test%20%26"); // -> "a test &"
|
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!😁"
|
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
|
```gradle
|
||||||
dependencies {
|
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).
|
||||||
|
|
|
@ -7,10 +7,10 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.uwyn"
|
group = "com.uwyn"
|
||||||
|
version = "1.0.1-SNAPSHOT"
|
||||||
|
|
||||||
base {
|
base {
|
||||||
archivesName.set("urlencoder")
|
archivesName.set(rootProject.name)
|
||||||
version = "0.9-SNAPSHOT"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
@ -21,6 +21,12 @@ java {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.jar {
|
||||||
|
manifest {
|
||||||
|
attributes["Main-Class"] = "com.uwyn.urlencoder.UrlEncoder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.jacocoTestReport {
|
tasks.jacocoTestReport {
|
||||||
reports {
|
reports {
|
||||||
xml.required.set(true)
|
xml.required.set(true)
|
||||||
|
@ -51,11 +57,11 @@ tasks.named<Test>("test") {
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
artifactId = "urlencoder"
|
artifactId = rootProject.name
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
pom {
|
pom {
|
||||||
name.set("URL Encoder")
|
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")
|
url.set("https://github.com/gbevin/urlencoder")
|
||||||
licenses {
|
licenses {
|
||||||
license {
|
license {
|
||||||
|
|
|
@ -67,7 +67,7 @@ public final class UrlEncoder {
|
||||||
byte[] bytes_buffer = null;
|
byte[] bytes_buffer = null;
|
||||||
var bytes_pos = 0;
|
var bytes_pos = 0;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while(i < length) {
|
while (i < length) {
|
||||||
ch = source.charAt(i);
|
ch = source.charAt(i);
|
||||||
|
|
||||||
if (ch == '%') {
|
if (ch == '%') {
|
||||||
|
@ -137,7 +137,7 @@ public final class UrlEncoder {
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public static String encode(String source) {
|
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;
|
StringBuilder out = null;
|
||||||
char ch;
|
char ch;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while(i < source.length()) {
|
while (i < source.length()) {
|
||||||
ch = source.charAt(i);
|
ch = source.charAt(i);
|
||||||
if (isUnreservedUriChar(ch) || (allow != null && allow.indexOf(ch) != -1)) {
|
if (isUnreservedUriChar(ch) || (allow != null && allow.indexOf(ch) != -1)) {
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
|
@ -218,4 +218,57 @@ public final class UrlEncoder {
|
||||||
private static boolean isUnreservedUriChar(char ch) {
|
private static boolean isUnreservedUriChar(char ch) {
|
||||||
return ch <= '~' && UNRESERVED_URI_CHARS.get(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ class UrlEncoderTest {
|
||||||
@Test
|
@Test
|
||||||
void testDecodeURL() {
|
void testDecodeURL() {
|
||||||
assertNull(UrlEncoder.decode(null));
|
assertNull(UrlEncoder.decode(null));
|
||||||
|
assertSame("", UrlEncoder.decode(""));
|
||||||
assertSame(same, UrlEncoder.decode(same));
|
assertSame(same, UrlEncoder.decode(same));
|
||||||
validMap.forEach((expected, source) -> assertEquals(expected, UrlEncoder.decode(source)));
|
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("?test=a%20test", UrlEncoder.encode("?test=a test", '?', '='));
|
||||||
assertEquals("aaa", UrlEncoder.encode("aaa", 'a'));
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue