{"id":27042264,"url":"https://github.com/ethauvin/urlencoder","last_synced_at":"2025-04-05T04:22:17.585Z","repository":{"id":65509503,"uuid":"583800192","full_name":"ethauvin/urlencoder","owner":"ethauvin","description":"A simple defensive library to encode/decode URL components.","archived":false,"fork":false,"pushed_at":"2024-10-21T01:39:32.000Z","size":450,"stargazers_count":43,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-04T16:36:47.585Z","etag":null,"topics":["encoder","encoding","java","kotlin","library","url","urlenc","urlencode","urlencoded","urlencoder"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ethauvin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-31T00:50:10.000Z","updated_at":"2025-02-20T06:34:03.000Z","dependencies_parsed_at":"2023-09-22T08:12:12.373Z","dependency_job_id":"365c7380-0201-40c4-852f-bf70a3925772","html_url":"https://github.com/ethauvin/urlencoder","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethauvin%2Furlencoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethauvin%2Furlencoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethauvin%2Furlencoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ethauvin%2Furlencoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ethauvin","download_url":"https://codeload.github.com/ethauvin/urlencoder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247286695,"owners_count":20914036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["encoder","encoding","java","kotlin","library","url","urlenc","urlencode","urlencoded","urlencoder"],"created_at":"2025-04-05T04:22:16.981Z","updated_at":"2025-04-05T04:22:17.561Z","avatar_url":"https://github.com/ethauvin.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Kotlin](https://img.shields.io/badge/kotlin-1.6%2B-blue)](https://kotlinlang.org/)\n[![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik.urlencoder/urlencoder-lib?label=snapshot\u0026server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/urlencoder/)\n[![Release](https://img.shields.io/github/release/ethauvin/urlencoder.svg)](https://github.com/ethauvin/urlencoder/releases/latest)\n[![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik.urlencoder/urlencoder-lib)](https://central.sonatype.com/search?namespace=net.thauvin.erik.urlencoder)\n\n[![GitHub CI](https://github.com/ethauvin/urlencoder/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/urlencoder/actions/workflows/gradle.yml)\n[![Tests](https://rife2.com/tests-badge/badge/net.thauvin.erik/urlencoder)](https://github.com/ethauvin/urlencoder/actions/workflows/gradle.yml)\n\n# URL Encoder for Kotlin Multiplatform\n\nUrlEncoder is a simple defensive library to encode/decode URL components.\n\nThis library was adapted from the [RIFE2 Web Application Framework](https://rife2.com).  \nA pure Java version can also be found at [https://github.com/gbevin/urlencoder](https://github.com/gbevin/urlencoder).\n\nThe rules are determined by combining the unreserved character set from\n[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#page-13) with the\npercent-encode set from\n[application/x-www-form-urlencoded](https://url.spec.whatwg.org/#application-x-www-form-urlencoded-percent-encode-set).\n\nBoth specs above support percent decoding of two hexadecimal digits to a\nbinary octet, however their unreserved set of characters differs and\n`application/x-www-form-urlencoded` adds conversion of space to `+`,\nthat has the potential to be misunderstood.\n\nThis class encodes with rules that will be decoded correctly in either case.\n\nAdditionally, this library allocates no memory when encoding isn't needed and\ndoes the work in a single pass without multiple loops. Both of these\noptimizations have a significantly beneficial impact on performance of encoding\ncompared to other solutions like the standard `URLEncoder` in the JDK or\n`UriUtils` in Spring.\n\n## Examples (TL;DR)\n\n```kotlin\nUrlEncoderUtil.encode(\"a test \u0026\") // -\u003e a%20test%20%26\nUrlEncoderUtil.encode(\"%#okékÉȢ smile!😁\") // -\u003e %25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81\nUrlEncoderUtil.encode(\"?test=a test\", allow = \"?=\") // -\u003e ?test=a%20test\nUrlEncoderUtil.endode(\"foo bar\", spaceToPlus = true) // -\u003e foo+bar\n\nUrlEncoderUtil.decode(\"a%20test%20%26\") // -\u003e a test \u0026\nUrlEncoderUtil.decode(\"%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81\") // -\u003e %#okékÉȢ smile!😁\nUrlEncoderUtil.decode(\"foo+bar\", plusToSpace = true) // -\u003e foo bar\n```\n\n## Gradle, Maven, etc.\n\nTo use with [Gradle](https://gradle.org/), include the following dependency in your build file:\n\n```kotlin\nrepositories {\n    mavenCentral()\n    // only needed for SNAPSHOT\n    maven(\"https://oss.sonatype.org/content/repositories/snapshots\") { \n      name = \"SonatypeSnapshots\"\n      mavenContent { snapshotsOnly() }\n    }\n}\n\ndependencies {\n    implementation(\"net.thauvin.erik.urlencoder:urlencoder-lib:1.6.0\")\n}\n```\n\nAdding a dependency in [Maven](https://maven.apache.org/) requires specifying the JVM variant by adding a `-jvm` suffix\nto the artifact URL.\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.thauvin.erik.urlencoder\u003c/groupId\u003e\n    \u003cartifactId\u003eurlencoder-lib-jvm\u003c/artifactId\u003e\n    \u003cversion\u003e1.6.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nInstructions for using with Ivy, etc. can be found on\n[Maven Central](https://central.sonatype.com/search?namespace=net.thauvin.erik.urlencoder).\n\n## Standalone usage\n\nUrlEncoder can be used on the command line also, both for encoding and decoding.\n\nYou have two options:\n\n* run it with Gradle\n* build the jar and launch it with Java\n\nThe usage is as follows:\n\n```console\nEncode and decode URL components defensively.\n  -e  encode (default)\n  -d  decode\n```\n\n### Running with Gradle\n\n```console\n./gradlew run --quiet --args=\"-e 'a test \u0026'\"        # -\u003e a%20test%20%26\n./gradlew run --quiet --args=\"%#okékÉȢ\"             # -\u003e %25%23ok%C3%A9k%C3%89%C8%A2\n\n./gradlew run --quiet --args=\"-d 'a%20test%20%26'\"  # -\u003e a test \u0026\n```\n\n### Running with Java\n\nFirst build the jar file:\n\n```console\n./gradlew fatJar\n```\n\nThen run it:\n\n```console\njava -jar urlencoder-app/build/libs/urlencoder-*all.jar -e \"a test \u0026\"       # -\u003e a%20test%20%26\njava -jar urlencoder-app/build/libs/urlencoder-*all.jar \"%#okékÉȢ\"          # -\u003e %25%23ok%C3%A9k%C3%89%C8%A2\n\njava -jar urlencoder-app/build/libs/urlencoder-*all.jar -d \"a%20test%20%26\" # -\u003e a test \u0026\n```\n\n## Why not simply use `java.net.URLEncoder`?\n\nApart for being quite inefficient, some URL components encoded with `URLEncoder.encode` might not be able to be properly decoded.\n\nFor example, a simple search query such as:\n\n```kotlin\nval u = URLEncoder.encode(\"foo +bar\", StandardCharsets.UTF_8)\n```\n\nwould be encoded as:\n\n```\nfoo+%2Bbar\n```\n\nTrying to decode it with [Spring](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriUtils.html#decode(java.lang.String,java.lang.String)), for example:\n\n```kotlin\nUriUtils.decode(u, StandardCharsets.UTF_8)\n```\n\nwould return:\n\n```\nfoo++bar\n```\n\nUnfortunately, decoding with [Uri.decode](https://developer.android.com/reference/android/net/Uri#decode(java.lang.String)) on Android, [decodeURI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURI) in Javascript, etc. would yield the exact same result.\n\n![URLEncoder](https://live.staticflickr.com/65535/52607534147_6197b42666_z.jpg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethauvin%2Furlencoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fethauvin%2Furlencoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethauvin%2Furlencoder/lists"}