├── .github └── workflows │ ├── main.yml │ └── pr.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── NOTICE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jacoco.gradle ├── publish.gradle ├── rfc3986-uri ├── build.gradle ├── gradle.properties └── src │ ├── main │ └── java │ │ └── org │ │ └── dmfs │ │ └── rfc3986 │ │ ├── Authority.java │ │ ├── Fragment.java │ │ ├── Path.java │ │ ├── Query.java │ │ ├── Scheme.java │ │ ├── Uri.java │ │ ├── UriEncoded.java │ │ ├── authorities │ │ ├── EncodedAuthority.java │ │ ├── OptionalLazyAuthority.java │ │ ├── OptionalLazyUserInfo.java │ │ ├── StructuredAuthority.java │ │ └── Text.java │ │ ├── encoding │ │ ├── Encoded.java │ │ ├── FormEncoded.java │ │ ├── FormPrecoded.java │ │ ├── IdempotentEncoded.java │ │ ├── Normalized.java │ │ ├── Precoded.java │ │ ├── XWwwFormUrlEncoded.java │ │ └── utils │ │ │ ├── FormPercentEncodingOutputStream.java │ │ │ └── PercentEncodingOutputStream.java │ │ ├── fragments │ │ ├── OptionalLazyFragment.java │ │ └── SimpleFragment.java │ │ ├── parameters │ │ ├── FluentParameterList.java │ │ ├── Parameter.java │ │ ├── ParameterList.java │ │ ├── ParameterType.java │ │ ├── ValueType.java │ │ ├── adapters │ │ │ ├── MultiParameter.java │ │ │ ├── OptionalParameter.java │ │ │ ├── TextParameter.java │ │ │ └── XwfueParameterList.java │ │ ├── parameters │ │ │ └── UrlEncodedParameter.java │ │ ├── parametersets │ │ │ ├── Appending.java │ │ │ ├── BasicParameterList.java │ │ │ ├── EmptyParameterList.java │ │ │ ├── Fluent.java │ │ │ ├── Removing.java │ │ │ └── Replacing.java │ │ ├── parametertypes │ │ │ └── BasicParameterType.java │ │ └── valuetypes │ │ │ ├── BooleanValueType.java │ │ │ ├── IntegerValueType.java │ │ │ └── TextValueType.java │ │ ├── paths │ │ ├── EmptyPath.java │ │ ├── EncodedPath.java │ │ ├── Extended.java │ │ ├── LazyPath.java │ │ ├── Normalized.java │ │ ├── Resolved.java │ │ ├── StructuredPath.java │ │ └── Text.java │ │ ├── queries │ │ ├── OptionalLazyQuery.java │ │ └── SimpleQuery.java │ │ ├── schemes │ │ ├── OptionalLazyScheme.java │ │ ├── Schemes.java │ │ └── StringScheme.java │ │ ├── uris │ │ ├── EmptyUri.java │ │ ├── LazyUri.java │ │ ├── Normalized.java │ │ ├── OpaqueUri.java │ │ ├── RelativeUri.java │ │ ├── Resolved.java │ │ ├── StructuredUri.java │ │ └── Text.java │ │ ├── utils │ │ ├── Parsed.java │ │ └── Split.java │ │ └── validation │ │ ├── BitMapCharSet.java │ │ ├── CharSet.java │ │ ├── CharSets.java │ │ └── Validated.java │ └── test │ └── java │ └── org │ └── dmfs │ └── rfc3986 │ ├── authorities │ ├── OptionalLazyAuthorityTest.java │ └── TextTest.java │ ├── encoding │ ├── EncodedTest.java │ ├── FormEncodedTest.java │ ├── FormPrecodedTest.java │ ├── NormalizedTest.java │ └── PrecodedTest.java │ ├── parameters │ ├── FluentTest.java │ ├── parameters │ │ └── UrlEncodedParameterTest.java │ └── valuetypes │ │ └── TextValueTypeTest.java │ ├── paths │ ├── EmptyPathTest.java │ ├── EncodedPathTest.java │ ├── ExtendedTest.java │ ├── NormalizedTest.java │ ├── ResolvedTest.java │ ├── StructuredPathTest.java │ └── TextTest.java │ ├── schemes │ ├── OptionalLazySchemeTest.java │ ├── SchemesTest.java │ └── StringSchemeTest.java │ ├── uris │ ├── Bench.java │ ├── EmptyUriTest.java │ ├── LazyUriTest.java │ └── TextTest.java │ ├── utils │ └── SplitTest.java │ └── validation │ ├── BitMapCharSetTest.java │ └── CharSetsTest.java ├── rfc6570-uri-templates ├── build.gradle ├── gradle.properties └── src │ └── main │ └── java │ └── org │ └── dmfs │ └── rfc6570 │ └── UriTemplate.java └── settings.gradle /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build main 2 | on: 3 | push: 4 | branches: 5 | - 'main' 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | main: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Set up JDK 11 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: '11' 18 | distribution: 'temurin' 19 | 20 | - name: Checkout Repo 21 | uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Build Project 26 | run: ./gradlew gitVersion check javadoc -P GITHUB_API_TOKEN=${{ secrets.GITHUB_TOKEN }} 27 | 28 | - name: Tag Release 29 | run: ./gradlew gitTagRelease -P GITHUB_API_TOKEN=${{ secrets.GITHUB_TOKEN }} 30 | 31 | # enable after rework 32 | # - name: Push Tags 33 | # run: git push --tags 34 | 35 | # - name: Upload Test Results 36 | # uses: codecov/codecov-action@v4 37 | # with: 38 | # fail_ci_if_error: true # optional (default = false) 39 | # verbose: true # optional (default = false) 40 | # token: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Build PR 2 | on: 3 | pull_request: 4 | branches: 5 | - 'main' 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Set up JDK 11 11 | uses: actions/setup-java@v3 12 | with: 13 | java-version: '11' 14 | distribution: 'temurin' 15 | 16 | - name: Checkout Repo 17 | uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Build Project 22 | run: ./gradlew gitVersion check javadoc -P GITHUB_API_TOKEN=${{ secrets.GITHUB_TOKEN }} 23 | 24 | # - name: Upload Test Results 25 | # uses: codecov/codecov-action@v4 26 | # with: 27 | # fail_ci_if_error: true # optional (default = false) 28 | # verbose: true # optional (default = false) 29 | # token: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/gradle,intellij 3 | 4 | ### Intellij ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff: 9 | .idea 10 | 11 | ## File-based project format: 12 | *.iws 13 | 14 | ## Plugin-specific files: 15 | 16 | # IntelliJ 17 | /out/ 18 | /*/out/ 19 | 20 | # mpeltonen/sbt-idea plugin 21 | .idea_modules/ 22 | 23 | # JIRA plugin 24 | atlassian-ide-plugin.xml 25 | 26 | # Crashlytics plugin (for Android Studio and IntelliJ) 27 | com_crashlytics_export_strings.xml 28 | crashlytics.properties 29 | crashlytics-build.properties 30 | fabric.properties 31 | 32 | ### Intellij Patch ### 33 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 34 | 35 | *.iml 36 | modules.xml 37 | .idea/misc.xml 38 | *.ipr 39 | 40 | 41 | ### Gradle ### 42 | .gradle 43 | /build/ 44 | /*/build 45 | 46 | # Ignore Gradle GUI config 47 | gradle-app.setting 48 | 49 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 50 | !gradle-wrapper.jar 51 | 52 | # Cache of project 53 | .gradletasknamecache 54 | 55 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 56 | # gradle/wrapper/gradle-wrapper.properties 57 | 58 | build/ 59 | 60 | *.class 61 | pom.xml* 62 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | uri-toolkit 2 | 3 | Copyright 2017 Marten Gajda, licensed under Apache2. 4 | 5 | This product contains software developed at dmfs.org 6 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'org.dmfs.gver' version '0.18.0' 4 | id 'io.github.gradle-nexus.publish-plugin' version '1.1.0' apply false 5 | } 6 | 7 | sourceCompatibility = JavaVersion.VERSION_1_8 8 | targetCompatibility = JavaVersion.VERSION_1_8 9 | 10 | gver { 11 | issueTracker GitHub { 12 | repo = "dmfs/uri-toolkit" 13 | if (project.hasProperty("GITHUB_API_TOKEN")) { 14 | accessToken = GITHUB_API_TOKEN 15 | } 16 | } 17 | changes { 18 | are none when { 19 | affects only(matches(~/.*\.md/)) 20 | } 21 | are major when { 22 | commitMessage contains(~/(?i)#(major|break(ing)?)\b/) 23 | } 24 | are minor when { 25 | commitMessage contains(~/(?i)#(?\d+)\b/) { 26 | where("issue") { isIssue { labeled "enhancement" } } 27 | } 28 | } 29 | are patch when { 30 | commitMessage contains(~/(?i)#(?\d+)\b/) { 31 | where("issue") { isIssue { labeled "bug" } } 32 | } 33 | } 34 | are minor when { 35 | commitMessage contains("#feature\\b") 36 | } 37 | otherwise patch 38 | } 39 | preReleases { 40 | on ~/main/ use { "beta" } 41 | on ~/(.*\/)?(?.*)/ use { "alpha-${group('name')}.1" } 42 | } 43 | releaseBranchPattern ~/main$/ 44 | } 45 | 46 | allprojects { 47 | group 'org.dmfs' 48 | repositories { 49 | mavenCentral() 50 | } 51 | } 52 | 53 | if (project.hasProperty('SONATYPE_USERNAME') && project.hasProperty('SONATYPE_PASSWORD')) { 54 | apply plugin: 'io.github.gradle-nexus.publish-plugin' 55 | 56 | nexusPublishing { 57 | repositories { 58 | sonatype { 59 | username = SONATYPE_USERNAME 60 | password = SONATYPE_PASSWORD 61 | nexusUrl.set(uri("https://oss.sonatype.org/service/local/")) 62 | snapshotRepositoryUrl.set(uri("https://oss.sonatype.org/content/repositories/snapshots/")) 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | RELEASE_REPOSITORY=https://oss.sonatype.org/service/local/staging/deploy/maven2 2 | POM_DEVELOPER_ID=dmfs 3 | POM_DEVELOPER_NAME=Marten Gajda 4 | POM_DEVELOPER_EMAIL=marten@dmfs.org 5 | POM_DEVELOPER_ORGANIZATION=dmfs GmbH 6 | POM_DEVELOPER_ORGANIZATION_URL=https://dmfs.org 7 | POM_LICENSE=The Apache Software License, Version 2.0 8 | POM_LICENSE_URL=http://www.apache.org/license/LICENSE-2.0.txt 9 | POM_PROJECT_URL=https://github.com/dmfs/uri-toolkit 10 | POM_SCM_URL=git@github.com:dmfs/uri-toolkit.git 11 | POM_SCM_CONNECTION=scm:git:git@github.com:dmfs/uri-toolkit.git 12 | POM_SCM_DEVELOPER_CONNECTION=scm:git:git@github.com:dmfs/uri-toolkit.git 13 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | hamcrest = "2.2" 3 | confidence = "0.57.0" 4 | jems2 = "2.25.0" 5 | junit = "5.11.0" 6 | junit-testkit = "1.11.0" 7 | 8 | [libraries] 9 | junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } 10 | junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } 11 | junit-testkit = { module = 'org.junit.platform:junit-platform-testkit', version.ref = "junit-testkit" } 12 | hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } 13 | 14 | jems2 = { module = "org.dmfs:jems2", version.ref = "jems2" } 15 | jems2-testing = { module = "org.dmfs:jems2-testing", version.ref = "jems2" } 16 | jems2-confidence = { module = "org.dmfs:jems2-confidence", version.ref = "jems2" } 17 | 18 | confidence-core = { module = "org.saynotobugs:confidence-core", version.ref = "confidence" } 19 | 20 | [bundles] 21 | 22 | [plugins] 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmfs/uri-toolkit/d39bf79d22ea65e18115beb0be718829f6e8ed98/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /jacoco.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "jacoco" 2 | 3 | jacocoTestReport { 4 | reports { 5 | xml.enabled = true 6 | html.enabled = true 7 | } 8 | } 9 | 10 | check.dependsOn jacocoTestReport -------------------------------------------------------------------------------- /publish.gradle: -------------------------------------------------------------------------------- 1 | if (project.hasProperty('SONATYPE_USERNAME') && project.hasProperty('SONATYPE_PASSWORD')) { 2 | 3 | apply plugin: 'maven-publish' 4 | apply plugin: 'signing' 5 | 6 | task javadocJar(type: Jar, dependsOn: javadoc) { 7 | classifier = 'javadoc' 8 | from javadoc.destinationDir 9 | } 10 | 11 | task sourceJar(type: Jar) { 12 | classifier "sources" 13 | from sourceSets.main.allJava 14 | } 15 | 16 | publishing { 17 | 18 | publications { 19 | jar(MavenPublication) { 20 | from components.java 21 | artifact sourceJar 22 | artifact javadocJar 23 | 24 | pom { 25 | name = project.name 26 | description = POM_DESCRIPTION 27 | url = POM_PROJECT_URL 28 | scm { 29 | url = POM_SCM_URL 30 | connection = POM_SCM_CONNECTION 31 | developerConnection = POM_SCM_DEVELOPER_CONNECTION 32 | } 33 | licenses { 34 | license { 35 | name = POM_LICENSE 36 | url = POM_LICENSE_URL 37 | } 38 | } 39 | developers { 40 | developer { 41 | id = POM_DEVELOPER_ID 42 | name = POM_DEVELOPER_NAME 43 | email = POM_DEVELOPER_EMAIL 44 | organization = POM_DEVELOPER_ORGANIZATION 45 | organizationUrl = POM_DEVELOPER_ORGANIZATION_URL 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | signing { 54 | useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) 55 | sign publishing.publications 56 | } 57 | } -------------------------------------------------------------------------------- /rfc3986-uri/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | } 4 | 5 | apply from: '../jacoco.gradle' 6 | apply from: '../publish.gradle' 7 | 8 | sourceCompatibility = JavaVersion.VERSION_1_8 9 | targetCompatibility = JavaVersion.VERSION_1_8 10 | 11 | dependencies { 12 | api libs.jems2 13 | testImplementation libs.jems2.testing 14 | testImplementation libs.junit.jupiter.api 15 | testImplementation libs.confidence.core 16 | testRuntimeOnly libs.junit.jupiter.engine 17 | } 18 | 19 | test { 20 | useJUnitPlatform() 21 | } 22 | -------------------------------------------------------------------------------- /rfc3986-uri/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_DESCRIPTION=RFC 3986 compliant URI implementation. -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Authority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | 20 | import org.dmfs.jems2.Optional; 21 | 22 | /** 23 | * An authority. 24 | *

25 | * An authority has a host, optional user info and an optional port. 26 | */ 27 | public interface Authority 28 | { 29 | /** 30 | * Returns the {@link Optional} user info part of the authority in encoded form. 31 | * 32 | * @return The {@link UriEncoded} user info. 33 | */ 34 | Optional userInfo(); 35 | 36 | /** 37 | * Returns the host of this authority. 38 | * 39 | * @return The {@link UriEncoded} host. 40 | */ 41 | UriEncoded host(); 42 | 43 | /** 44 | * The {@link Optional} port number. 45 | * 46 | * @return An {@link Optional} port number (as an {@link Integer}). 47 | */ 48 | Optional port(); 49 | } 50 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Fragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | import org.dmfs.rfc3986.parameters.adapters.XwfueParameterList; 20 | 21 | 22 | /** 23 | * The fragment component of a URI. A fragment is a {@link UriEncoded} {@link CharSequence}. 24 | *

25 | * Often the fragment is structured, for instance with {@code x-www-form-urlencoded}. Use an appropriate adapter like {@link XwfueParameterList} to read these 26 | * structured values. 27 | */ 28 | public interface Fragment extends UriEncoded 29 | { 30 | 31 | /** 32 | * Returns the encoded String representation of the fragment. 33 | * 34 | * @return A {@link String} representing the encoded fragment. 35 | */ 36 | @Override 37 | String toString(); 38 | } 39 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Path.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | import org.dmfs.rfc3986.paths.Text; 20 | 21 | 22 | /** 23 | * Represents the path component of a {@link Uri}. 24 | *

25 | * Use {@link Text} to convert a {@link Path} into an encoded {@link CharSequence}. 26 | */ 27 | public interface Path extends Iterable 28 | { 29 | /** 30 | * Returns whether this path is empty, i.e. contains no path segments. 31 | * 32 | * @return {@code true} if this path is empty, {@code false} otherwise. 33 | */ 34 | boolean isEmpty(); 35 | 36 | /** 37 | * Returns whether this path is absolute, i.e. starts with a "/". 38 | * 39 | * @return {@code true} if this path is absolute, {@code false} otherwise. 40 | */ 41 | boolean isAbsolute(); 42 | } 43 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Query.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | import org.dmfs.rfc3986.parameters.adapters.XwfueParameterList; 20 | 21 | 22 | /** 23 | * /** The query component of a URI. A fragment is a {@link UriEncoded} {@link CharSequence}. 24 | *

25 | * Often the query is structured, for instance with {@code x-www-form-urlencoded}. Use an appropriate adapter like {@link XwfueParameterList} to read these 26 | * structured values. 27 | */ 28 | public interface Query extends UriEncoded 29 | { 30 | 31 | /** 32 | * Returns the encoded String representation of the query. 33 | * 34 | * @return A {@link String} representing the encoded query. 35 | */ 36 | @Override 37 | String toString(); 38 | } 39 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Scheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | /** 20 | * The interface of a {@link Uri} scheme. 21 | */ 22 | public interface Scheme extends CharSequence 23 | { 24 | @Override 25 | String toString(); 26 | } 27 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/Uri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | 20 | import org.dmfs.jems2.Optional; 21 | 22 | /** 23 | * A URI as specified in RFC 3986. 24 | *

25 | * For convenience this represents a URI-reference as specified in RFC 3986, Section 4.1. For 26 | * brevity and as per common usage it's still called just {@code Uri} instead of {@code UriReference}. 27 | *

28 | * As a consequence, {@link #scheme()} returns an {@link Optional}, because in contrast to a URI, a relative reference doesn't have a scheme. 29 | *

30 | * {@link #isAbsolute()} may be used to distinguish between real URIs that have a scheme ({@link #isAbsolute()} returns {@code true}) and relative references 31 | * ({@link #isAbsolute()} returns {@code false}). 32 | */ 33 | public interface Uri 34 | { 35 | /** 36 | * Returns the {@link Optional} {@link Scheme} of the URI reference. 37 | * 38 | * @return An {@link Optional} {@link Scheme}. 39 | */ 40 | Optional scheme(); 41 | 42 | /** 43 | * Returns the {@link Optional} {@link Authority} of the URI reference. 44 | * 45 | * @return An {@link Optional} {@link Authority}. 46 | */ 47 | Optional authority(); 48 | 49 | /** 50 | * Returns the {@link Path} of this URI reference. 51 | * 52 | * @return A {@link Path}. The path is always present, but may be empty. 53 | */ 54 | Path path(); 55 | 56 | /** 57 | * Returns the {@link Optional} {@link Query} of the URI reference. 58 | * 59 | * @return An {@link Optional} {@link Query}. 60 | */ 61 | Optional query(); 62 | 63 | /** 64 | * Returns the {@link Optional} {@link Fragment} of the URI reference. 65 | * 66 | * @return An {@link Optional} {@link Fragment}. 67 | */ 68 | Optional fragment(); 69 | 70 | /** 71 | * Returns whether this URI reference is hierarchical. 72 | * 73 | * @return {@code true} if the URI is hierarchical, {@code false} otherwise. 74 | */ 75 | boolean isHierarchical(); 76 | 77 | /** 78 | * Returns whether this URI reference is absolute, i.e. a URI. A URI reference is absolute if it has a scheme, otherwise it's a relative reference as per RFC 3986, Section 4.2 80 | * 81 | * @return {@code true} if the URI is absolute, {@code false} otherwise. 82 | */ 83 | boolean isAbsolute(); 84 | } 85 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/UriEncoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986; 18 | 19 | import java.io.UnsupportedEncodingException; 20 | 21 | 22 | /** 23 | * Interface of a percent-encoded {@link CharSequence}. 24 | *

25 | * Note that two {@link UriEncoded} objects are considered equal if their encoded and normalized values are equal. 26 | *

27 | * All implementations of this must also implement {@link #toString()} to return a {@link String} representation of the encoded value. 28 | */ 29 | public interface UriEncoded extends CharSequence 30 | { 31 | /** 32 | * Returns a normalized version of this {@link UriEncoded}. In particular that means any percent-encoded unreserved characters are decoded and 33 | * percent-encoding sequences are converted to uppercase. 34 | * 35 | * @return The normalized version of this {@link UriEncoded}. 36 | */ 37 | UriEncoded normalized(); 38 | 39 | /** 40 | * Returns the decoded text, using the given charset to decode the non-ASCII characters. 41 | * 42 | * @param charset 43 | * The name of the charset. 44 | * 45 | * @return 46 | */ 47 | CharSequence decoded(String charset) throws UnsupportedEncodingException; 48 | 49 | /** 50 | * Returns the decoded text assuming UTF-8 encoding. 51 | * 52 | * @return 53 | */ 54 | CharSequence decoded(); 55 | 56 | @Override 57 | UriEncoded subSequence(int startIndex, int endIndex); 58 | 59 | @Override 60 | String toString(); 61 | } 62 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/authorities/OptionalLazyAuthority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.authorities; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.Authority; 22 | import org.dmfs.rfc3986.UriEncoded; 23 | import org.dmfs.rfc3986.utils.Parsed; 24 | 25 | import java.util.NoSuchElementException; 26 | 27 | import static org.dmfs.jems2.optional.Absent.absent; 28 | 29 | 30 | /** 31 | * The {@link Optional} {@link Authority} of a {@link UriEncoded} {@link CharSequence}. 32 | */ 33 | public final class OptionalLazyAuthority implements Optional, Parsed 34 | { 35 | private final UriEncoded mUriEncoded; 36 | private Optional mOptionalAuthority; 37 | 38 | 39 | public OptionalLazyAuthority(UriEncoded uriEncoded) 40 | { 41 | mUriEncoded = uriEncoded; 42 | } 43 | 44 | 45 | @Override 46 | public boolean isPresent() 47 | { 48 | return authority().isPresent(); 49 | } 50 | 51 | 52 | @Override 53 | public Authority value() throws NoSuchElementException 54 | { 55 | return authority().value(); 56 | } 57 | 58 | 59 | private Optional authority() 60 | { 61 | if (mOptionalAuthority == null) 62 | { 63 | mOptionalAuthority = parsedAuthority(); 64 | } 65 | return mOptionalAuthority; 66 | } 67 | 68 | 69 | private Optional parsedAuthority() 70 | { 71 | if (mUriEncoded.length() < 2 || mUriEncoded.charAt(0) != '/' || mUriEncoded.charAt(1) != '/') 72 | { 73 | // too short or not starting with "//", not an authority 74 | return absent(); 75 | } 76 | // this looks like an authority 77 | return new Present(new EncodedAuthority(mUriEncoded.subSequence(2, mUriEncoded.length()))); 78 | } 79 | 80 | 81 | @Override 82 | public int parsedLength() 83 | { 84 | return authority().isPresent() ? ((EncodedAuthority) mOptionalAuthority.value()).parsedLength() + 2 : 0; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/authorities/OptionalLazyUserInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.authorities; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.UriEncoded; 22 | import org.dmfs.rfc3986.utils.Parsed; 23 | 24 | import java.util.NoSuchElementException; 25 | 26 | import static org.dmfs.jems2.optional.Absent.absent; 27 | import static org.dmfs.rfc3986.validation.CharSets.REG_NAME_CHAR; 28 | 29 | 30 | /** 31 | * An {@link Optional} {@link UriEncoded} user info. 32 | */ 33 | public final class OptionalLazyUserInfo implements Optional, Parsed 34 | { 35 | private final UriEncoded mEncodedAuthority; 36 | private Optional mUserInfo; 37 | private int mEnd; 38 | 39 | 40 | public OptionalLazyUserInfo(UriEncoded encodedAuthority) 41 | { 42 | mEncodedAuthority = encodedAuthority; 43 | } 44 | 45 | 46 | @Override 47 | public boolean isPresent() 48 | { 49 | return userInfo().isPresent(); 50 | } 51 | 52 | 53 | @Override 54 | public UriEncoded value() throws NoSuchElementException 55 | { 56 | return userInfo().value(); 57 | } 58 | 59 | 60 | private Optional userInfo() 61 | { 62 | if (mUserInfo == null) 63 | { 64 | mUserInfo = parsedUserInfo(); 65 | } 66 | return mUserInfo; 67 | } 68 | 69 | 70 | private Optional parsedUserInfo() 71 | { 72 | final UriEncoded encodedAuthority = mEncodedAuthority; 73 | final int count = encodedAuthority.length(); 74 | int i = 0; 75 | while (i < count && (REG_NAME_CHAR.contains(encodedAuthority.charAt(i)) || encodedAuthority.charAt(i) == ':')) 76 | { 77 | ++i; 78 | } 79 | 80 | if (i == count || encodedAuthority.charAt(i) != '@') 81 | { 82 | // no @ -> no user info 83 | return absent(); 84 | } 85 | 86 | mEnd = i + 1 /* account for the "@" which is not part of the user info */; 87 | return new Present<>(encodedAuthority.subSequence(0, i)); 88 | } 89 | 90 | 91 | @Override 92 | public int parsedLength() 93 | { 94 | return mEnd; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/authorities/StructuredAuthority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.authorities; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Absent; 21 | import org.dmfs.jems2.optional.Present; 22 | import org.dmfs.rfc3986.Authority; 23 | import org.dmfs.rfc3986.UriEncoded; 24 | 25 | 26 | /** 27 | * An {@link Authority} built from its components. 28 | */ 29 | public final class StructuredAuthority implements Authority 30 | { 31 | private final Optional mUserInfo; 32 | private final UriEncoded mHost; 33 | private final Optional mPort; 34 | 35 | 36 | public StructuredAuthority(UriEncoded host) 37 | { 38 | this(Absent.absent(), host, Absent.absent()); 39 | } 40 | 41 | 42 | public StructuredAuthority(UriEncoded host, int port) 43 | { 44 | this(Absent.absent(), host, new Present<>(port)); 45 | } 46 | 47 | 48 | public StructuredAuthority(UriEncoded userInfo, UriEncoded host) 49 | { 50 | this(new Present<>(userInfo), host, Absent.absent()); 51 | } 52 | 53 | 54 | public StructuredAuthority(UriEncoded userInfo, UriEncoded host, int port) 55 | { 56 | this(new Present<>(userInfo), host, new Present<>(port)); 57 | } 58 | 59 | 60 | public StructuredAuthority(Optional userInfo, UriEncoded host, Optional port) 61 | { 62 | mUserInfo = userInfo; 63 | mHost = host; 64 | mPort = port; 65 | } 66 | 67 | 68 | @Override 69 | public Optional userInfo() 70 | { 71 | return mUserInfo; 72 | } 73 | 74 | 75 | @Override 76 | public UriEncoded host() 77 | { 78 | return mHost; 79 | } 80 | 81 | 82 | @Override 83 | public Optional port() 84 | { 85 | return mPort; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/authorities/Text.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.authorities; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.rfc3986.Authority; 21 | import org.dmfs.rfc3986.UriEncoded; 22 | import org.dmfs.rfc3986.encoding.Precoded; 23 | 24 | import java.io.UnsupportedEncodingException; 25 | 26 | 27 | /** 28 | * The (normalized) {@link UriEncoded} representation of an {@link Authority}. 29 | */ 30 | public final class Text implements UriEncoded 31 | { 32 | private final Authority mDelegate; 33 | private String mText; 34 | 35 | 36 | public Text(Authority delegate) 37 | { 38 | mDelegate = delegate; 39 | } 40 | 41 | 42 | @Override 43 | public int length() 44 | { 45 | if (mText == null) 46 | { 47 | // result not cached yet, calculate the length on the fly 48 | int len = mDelegate.host().length(); 49 | if (mDelegate.userInfo().isPresent()) 50 | { 51 | len += mDelegate.userInfo().value().length() + 1; 52 | } 53 | Optional optionalPort = mDelegate.port(); 54 | if (optionalPort.isPresent()) 55 | { 56 | int port = optionalPort.value(); 57 | // we use this if-else chain, because it's supposed to be faster than to string conversion and easier than calculations via log 58 | if (port < 10) 59 | { 60 | len += 2; 61 | } 62 | else if (port < 100) 63 | { 64 | len += 3; 65 | } 66 | else if (port < 1000) 67 | { 68 | len += 4; 69 | } 70 | else if (port < 10000) 71 | { 72 | len += 5; 73 | } 74 | else if (port < 100000) 75 | { 76 | len += 6; 77 | } 78 | else 79 | { 80 | throw new IllegalArgumentException(String.format("Port number %d out of range (<100000)", port)); 81 | } 82 | } 83 | return len; 84 | } 85 | return mText.length(); 86 | } 87 | 88 | 89 | @Override 90 | public char charAt(int i) 91 | { 92 | return toString().charAt(i); 93 | } 94 | 95 | 96 | @Override 97 | public UriEncoded subSequence(int startIndex, int endIndex) 98 | { 99 | if (startIndex == 0 && endIndex == toString().length()) 100 | { 101 | return this; 102 | } 103 | return new Precoded(toString().subSequence(startIndex, endIndex)); 104 | } 105 | 106 | 107 | @Override 108 | public String toString() 109 | { 110 | if (mText == null) 111 | { 112 | StringBuilder builder = new StringBuilder(64); 113 | Optional mUserInfo = mDelegate.userInfo(); 114 | if (mUserInfo.isPresent()) 115 | { 116 | builder.append(mUserInfo.value().normalized()); 117 | builder.append('@'); 118 | } 119 | builder.append(mDelegate.host().normalized()); 120 | Optional port = mDelegate.port(); 121 | if (port.isPresent()) 122 | { 123 | builder.append(':'); 124 | builder.append((int) port.value()); 125 | } 126 | mText = builder.toString(); 127 | } 128 | return mText; 129 | } 130 | 131 | 132 | @Override 133 | public UriEncoded normalized() 134 | { 135 | return this; 136 | } 137 | 138 | 139 | @Override 140 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 141 | { 142 | throw new UnsupportedOperationException("an Authority can't be decoded as a whole"); 143 | } 144 | 145 | 146 | @Override 147 | public CharSequence decoded() 148 | { 149 | throw new UnsupportedOperationException("an Authority can't be decoded as a whole"); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/Encoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | import org.dmfs.rfc3986.encoding.utils.PercentEncodingOutputStream; 21 | import org.dmfs.rfc3986.validation.CharSets; 22 | 23 | import java.io.IOException; 24 | import java.io.OutputStreamWriter; 25 | import java.io.UnsupportedEncodingException; 26 | import java.io.Writer; 27 | 28 | 29 | /** 30 | * A lazily encoded {@link CharSequence}. This encodes all reserved characters and delimiters. The only characters not encoded are "a"-"z", 31 | * "A"-"Z", "0"-"9", "-", "_", "." and "~". 32 | * @see RFC 3986 Section 2.3 33 | */ 34 | public final class Encoded implements UriEncoded 35 | { 36 | private final CharSequence mPlain; 37 | private final String mCharSet; 38 | private CharSequence mEncoded; 39 | 40 | 41 | public Encoded(CharSequence plain) 42 | { 43 | this(plain, "UTF-8"); 44 | } 45 | 46 | 47 | public Encoded(CharSequence plain, String charSet) 48 | { 49 | mPlain = plain; 50 | mCharSet = charSet; 51 | } 52 | 53 | 54 | @Override 55 | public UriEncoded normalized() 56 | { 57 | // this will be encoded in a normalized form 58 | return this; 59 | } 60 | 61 | 62 | @Override 63 | public CharSequence decoded(String charset) 64 | { 65 | return mPlain; 66 | } 67 | 68 | 69 | @Override 70 | public CharSequence decoded() 71 | { 72 | return mPlain; 73 | } 74 | 75 | 76 | @Override 77 | public int length() 78 | { 79 | return toString().length(); 80 | } 81 | 82 | 83 | @Override 84 | public char charAt(int i) 85 | { 86 | return toString().charAt(i); 87 | } 88 | 89 | 90 | @Override 91 | public UriEncoded subSequence(int startIndex, int endIndex) 92 | { 93 | if (startIndex == 0 && endIndex == toString().length()) 94 | { 95 | return this; 96 | } 97 | return new Precoded(toString().subSequence(startIndex, endIndex)); 98 | } 99 | 100 | 101 | @Override 102 | public int hashCode() 103 | { 104 | return toString().hashCode(); 105 | } 106 | 107 | 108 | @Override 109 | public boolean equals(Object obj) 110 | { 111 | return obj instanceof UriEncoded && toString().equals(((UriEncoded) obj).normalized().toString()); 112 | } 113 | 114 | 115 | @Override 116 | public String toString() 117 | { 118 | if (mEncoded == null) 119 | { 120 | try 121 | { 122 | mEncoded = encoded(mPlain, mCharSet); 123 | } 124 | catch (UnsupportedEncodingException e) 125 | { 126 | throw new IllegalArgumentException(String.format("Charset %s not supported by Runtime", mCharSet)); 127 | } 128 | } 129 | return mEncoded.toString(); 130 | } 131 | 132 | 133 | private CharSequence encoded(CharSequence charSequence, String charSet) throws UnsupportedEncodingException 134 | { 135 | final int len = charSequence.length(); 136 | if (len == 0) 137 | { 138 | return IdempotentEncoded.EMPTY; 139 | } 140 | try 141 | { 142 | // TODO: improve the performance. This appears to have quite some overhead compared to URLEncoder.encode(). 143 | PercentEncodingOutputStream out = new PercentEncodingOutputStream(len, CharSets.UNRESERVED); 144 | Writer w = new OutputStreamWriter(out, charSet); 145 | w.append(charSequence); 146 | w.close(); 147 | return out.toString(); 148 | } 149 | catch (UnsupportedEncodingException e) 150 | { 151 | throw e; 152 | } 153 | catch (IOException e) 154 | { 155 | throw new RuntimeException("IOException while operating on CharSequences"); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/FormEncoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | import org.dmfs.rfc3986.encoding.utils.FormPercentEncodingOutputStream; 21 | import org.dmfs.rfc3986.validation.CharSets; 22 | 23 | import java.io.IOException; 24 | import java.io.OutputStream; 25 | import java.io.OutputStreamWriter; 26 | import java.io.UnsupportedEncodingException; 27 | import java.io.Writer; 28 | 29 | 30 | /** 31 | * A lazily encoded {@link CharSequence}. This encodes all reserved characters and delimiters. The only characters not encoded are "a"-"z", 32 | * "A"-"Z", "0"-"9", "-", "_", "." and "~". 33 | *

34 | * Note, in contrast to {@link Encoded} this encodes spaces as {@code +} instead of {@code %20} and normalizes new line squences to {@code %0D%0A}. 35 | * @see RFC 3986 Section 2.3 36 | */ 37 | public final class FormEncoded implements UriEncoded 38 | { 39 | private final CharSequence mPlain; 40 | private final String mCharSet; 41 | private CharSequence mEncoded; 42 | 43 | 44 | public FormEncoded(CharSequence plain) 45 | { 46 | this(plain, "UTF-8"); 47 | } 48 | 49 | 50 | public FormEncoded(CharSequence plain, String charSet) 51 | { 52 | mPlain = plain; 53 | mCharSet = charSet; 54 | } 55 | 56 | 57 | @Override 58 | public UriEncoded normalized() 59 | { 60 | // this will be encoded in a normalized form 61 | return this; 62 | } 63 | 64 | 65 | @Override 66 | public CharSequence decoded(String charset) 67 | { 68 | return mPlain; 69 | } 70 | 71 | 72 | @Override 73 | public CharSequence decoded() 74 | { 75 | return mPlain; 76 | } 77 | 78 | 79 | @Override 80 | public int length() 81 | { 82 | return toString().length(); 83 | } 84 | 85 | 86 | @Override 87 | public char charAt(int i) 88 | { 89 | return toString().charAt(i); 90 | } 91 | 92 | 93 | @Override 94 | public UriEncoded subSequence(int startIndex, int endIndex) 95 | { 96 | if (startIndex == 0 && endIndex == toString().length()) 97 | { 98 | return this; 99 | } 100 | return new Precoded(toString().subSequence(startIndex, endIndex)); 101 | } 102 | 103 | 104 | @Override 105 | public int hashCode() 106 | { 107 | return toString().hashCode(); 108 | } 109 | 110 | 111 | @Override 112 | public boolean equals(Object obj) 113 | { 114 | return obj instanceof UriEncoded && toString().equals(((UriEncoded) obj).normalized().toString()); 115 | } 116 | 117 | 118 | @Override 119 | public String toString() 120 | { 121 | if (mEncoded == null) 122 | { 123 | try 124 | { 125 | mEncoded = encoded(mPlain, mCharSet); 126 | } 127 | catch (UnsupportedEncodingException e) 128 | { 129 | throw new IllegalArgumentException(String.format("Charset %s not supported by Runtime", mCharSet)); 130 | } 131 | } 132 | return mEncoded.toString(); 133 | } 134 | 135 | 136 | private CharSequence encoded(CharSequence charSequence, String charSet) throws UnsupportedEncodingException 137 | { 138 | final int len = charSequence.length(); 139 | if (len == 0) 140 | { 141 | return IdempotentEncoded.EMPTY; 142 | } 143 | try 144 | { 145 | // TODO: improve the performance. This appears to have quite some overhead compared to URLEncoder.encode(). 146 | OutputStream out = new FormPercentEncodingOutputStream(len, CharSets.UNRESERVED); 147 | Writer w = new OutputStreamWriter(out, charSet); 148 | w.append(charSequence); 149 | w.close(); 150 | return out.toString(); 151 | } 152 | catch (UnsupportedEncodingException e) 153 | { 154 | throw e; 155 | } 156 | catch (IOException e) 157 | { 158 | throw new RuntimeException("IOException while operating on CharSequences"); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/FormPrecoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | 21 | import java.io.ByteArrayOutputStream; 22 | import java.io.UnsupportedEncodingException; 23 | 24 | 25 | /** 26 | * An {@link UriEncoded} {@link CharSequence} that is derived from an already encoded {@link CharSequence}. In contrast to {@link Precoded} this decodes {@code 27 | * +} into a space character. This is meant to decode values in {@code x-www-form-urlencoded} data (like most query strings). 28 | *

29 | * TODO: validate the provided string. 30 | */ 31 | public final class FormPrecoded implements UriEncoded 32 | { 33 | private final CharSequence mEncoded; 34 | private CharSequence mUtf8Plain; 35 | private UriEncoded mNormalized; 36 | 37 | 38 | public FormPrecoded(CharSequence encoded) 39 | { 40 | mEncoded = encoded; 41 | } 42 | 43 | 44 | @Override 45 | public UriEncoded normalized() 46 | { 47 | if (mNormalized == null) 48 | { 49 | mNormalized = new Normalized(this); 50 | } 51 | return mNormalized; 52 | } 53 | 54 | 55 | @Override 56 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 57 | { 58 | if ("UTF-8".equalsIgnoreCase(charset)) 59 | { 60 | return decoded(); 61 | } 62 | return decoded(mEncoded, charset); 63 | } 64 | 65 | 66 | @Override 67 | public CharSequence decoded() 68 | { 69 | if (mUtf8Plain == null) 70 | { 71 | try 72 | { 73 | mUtf8Plain = decoded(mEncoded, "UTF-8"); 74 | } 75 | catch (UnsupportedEncodingException e) 76 | { 77 | throw new RuntimeException("Runtime doesn't support UTF-8"); 78 | } 79 | } 80 | return mUtf8Plain; 81 | } 82 | 83 | 84 | @Override 85 | public int length() 86 | { 87 | return mEncoded.length(); 88 | } 89 | 90 | 91 | @Override 92 | public char charAt(int i) 93 | { 94 | return mEncoded.charAt(i); 95 | } 96 | 97 | 98 | @Override 99 | public UriEncoded subSequence(int startIndex, int endIndex) 100 | { 101 | return new FormPrecoded(mEncoded.subSequence(startIndex, endIndex)); 102 | } 103 | 104 | 105 | @Override 106 | public int hashCode() 107 | { 108 | return normalized().hashCode(); 109 | } 110 | 111 | 112 | @Override 113 | public boolean equals(Object obj) 114 | { 115 | return obj instanceof UriEncoded && normalized().equals(obj); 116 | } 117 | 118 | 119 | @Override 120 | public String toString() 121 | { 122 | return mEncoded.toString(); 123 | } 124 | 125 | 126 | private CharSequence decoded(CharSequence encoded, String charSet) throws UnsupportedEncodingException 127 | { 128 | if (encoded.length() == 0) 129 | { 130 | return encoded; 131 | } 132 | ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length()); 133 | final int count = encoded.length(); 134 | int i = 0; 135 | while (i < count) 136 | { 137 | char c = encoded.charAt(i); 138 | if (c == '%') 139 | { 140 | if (i + 2 >= count) 141 | { 142 | throw new IllegalArgumentException("Illegal percent encoding."); 143 | } 144 | 145 | out.write((decodeDigit(encoded.charAt(i + 1)) << 4) + decodeDigit(encoded.charAt(i + 2))); 146 | i += 3; 147 | } 148 | else if (c == '+') 149 | { 150 | out.write(' '); 151 | i += 1; 152 | } 153 | else 154 | { 155 | out.write(c); 156 | i += 1; 157 | } 158 | } 159 | return out.toString(charSet); 160 | } 161 | 162 | 163 | private int decodeDigit(char c) 164 | { 165 | if ('0' <= c && c <= '9') 166 | { 167 | return c - '0'; 168 | } 169 | int r = (c - 'A') & 0xffffffDF; 170 | if (r < 0 || r > 5) 171 | { 172 | throw new IllegalArgumentException(String.format("%c is not a valid hex digit")); 173 | } 174 | return r + 10; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/IdempotentEncoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | 21 | import java.io.UnsupportedEncodingException; 22 | 23 | 24 | /** 25 | * Adapter for special {@link CharSequence}s that remain the same before and after encoding. 26 | *

27 | * To be used with care! 28 | */ 29 | public final class IdempotentEncoded implements UriEncoded 30 | { 31 | public final static UriEncoded EMPTY = new IdempotentEncoded(""); 32 | public final static UriEncoded CURRENT = new IdempotentEncoded("."); 33 | public final static UriEncoded PARENT = new IdempotentEncoded(".."); 34 | 35 | private final CharSequence mText; 36 | 37 | 38 | public IdempotentEncoded(CharSequence text) 39 | { 40 | mText = text; 41 | } 42 | 43 | 44 | @Override 45 | public UriEncoded normalized() 46 | { 47 | return this; 48 | } 49 | 50 | 51 | @Override 52 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 53 | { 54 | return mText; 55 | } 56 | 57 | 58 | @Override 59 | public CharSequence decoded() 60 | { 61 | return mText; 62 | } 63 | 64 | 65 | @Override 66 | public int length() 67 | { 68 | return mText.length(); 69 | } 70 | 71 | 72 | @Override 73 | public char charAt(int i) 74 | { 75 | return mText.charAt(i); 76 | } 77 | 78 | 79 | @Override 80 | public UriEncoded subSequence(int startIndex, int endIndex) 81 | { 82 | if (startIndex == 0 && endIndex == mText.length()) 83 | { 84 | return this; 85 | } 86 | return new IdempotentEncoded(mText.subSequence(startIndex, endIndex)); 87 | } 88 | 89 | 90 | @Override 91 | public int hashCode() 92 | { 93 | return mText.hashCode(); 94 | } 95 | 96 | 97 | @Override 98 | public boolean equals(Object obj) 99 | { 100 | return obj instanceof UriEncoded && mText.equals(((UriEncoded) obj).normalized().toString()); 101 | } 102 | 103 | 104 | @Override 105 | public String toString() 106 | { 107 | return mText.toString(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/XWwwFormUrlEncoded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | import org.dmfs.rfc3986.parameters.Parameter; 21 | import org.dmfs.rfc3986.parameters.ParameterList; 22 | 23 | import java.io.UnsupportedEncodingException; 24 | 25 | 26 | /** 27 | * An adapter to adapt a {@link ParameterList} to {@code x-www-form-urlencoded} a {@link UriEncoded}. 28 | *

29 | * Note, this can't be decoded as a whole. Calling {@link #decoded()} or {@link #decoded(String)} with result in an Exception. 30 | */ 31 | public final class XWwwFormUrlEncoded implements UriEncoded 32 | { 33 | private final ParameterList mParams; 34 | private final String mCharSet; 35 | private String mText; 36 | 37 | 38 | public XWwwFormUrlEncoded(ParameterList params) 39 | { 40 | this(params, "UTF-8"); 41 | } 42 | 43 | 44 | public XWwwFormUrlEncoded(ParameterList params, String charset) 45 | { 46 | mParams = params; 47 | mCharSet = charset; 48 | } 49 | 50 | 51 | @Override 52 | public UriEncoded normalized() 53 | { 54 | // this will be rendered in normalized form 55 | return this; 56 | } 57 | 58 | 59 | @Override 60 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 61 | { 62 | throw new UnsupportedOperationException("x-www-form-urlencoded can't be decoded as a whole"); 63 | } 64 | 65 | 66 | @Override 67 | public CharSequence decoded() 68 | { 69 | throw new UnsupportedOperationException("x-www-form-urlencoded can't be decoded as a whole"); 70 | } 71 | 72 | 73 | @Override 74 | public int length() 75 | { 76 | return toString().length(); 77 | } 78 | 79 | 80 | @Override 81 | public char charAt(int i) 82 | { 83 | return toString().charAt(i); 84 | } 85 | 86 | 87 | @Override 88 | public UriEncoded subSequence(int startIndex, int endIndex) 89 | { 90 | if (startIndex == 0 && endIndex == toString().length()) 91 | { 92 | return this; 93 | } 94 | return new Precoded(toString().subSequence(startIndex, endIndex)); 95 | } 96 | 97 | 98 | @Override 99 | public String toString() 100 | { 101 | if (mText == null) 102 | { 103 | StringBuilder sb = new StringBuilder(256); 104 | boolean first = true; 105 | for (Parameter parameter : mParams) 106 | { 107 | if (first) 108 | { 109 | first = false; 110 | } 111 | else 112 | { 113 | sb.append('&'); 114 | } 115 | sb.append(new FormEncoded(parameter.name(), mCharSet)); 116 | sb.append('='); 117 | sb.append(new FormEncoded(parameter.textValue(), mCharSet)); 118 | } 119 | mText = sb.toString(); 120 | } 121 | return mText; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/utils/FormPercentEncodingOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding.utils; 18 | 19 | import org.dmfs.rfc3986.validation.CharSet; 20 | 21 | import java.io.IOException; 22 | import java.io.OutputStream; 23 | 24 | 25 | /** 26 | * An {@link OutputStream} that percent-encodes characters transparently. Calling {@link #toString()} returns the result. 27 | */ 28 | public final class FormPercentEncodingOutputStream extends OutputStream 29 | { 30 | private final static char[] HEXDIGITS = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 31 | 32 | private final StringBuilder mStringBuilder; 33 | private final CharSet mNoEncodeMap; 34 | 35 | 36 | public FormPercentEncodingOutputStream(int initialCapacity, CharSet noEncodeMap) 37 | { 38 | mStringBuilder = new StringBuilder(initialCapacity); 39 | mNoEncodeMap = noEncodeMap; 40 | } 41 | 42 | 43 | @Override 44 | public void write(int i) throws IOException 45 | { 46 | if (mNoEncodeMap.contains((char) i)) 47 | { 48 | mStringBuilder.append((char) i); 49 | } 50 | else if (i == ' ') 51 | { 52 | mStringBuilder.append('+'); 53 | } 54 | else if (i == 0x0a) 55 | { 56 | // normalize new line 57 | mStringBuilder.append("%0D%0A"); 58 | } 59 | else if (i != 0x0d) // don't encode CR chars CRLF sequences will be encoded when the LF is written 60 | { 61 | mStringBuilder.append('%'); 62 | mStringBuilder.append(HEXDIGITS[(i >>> 4) & 0x0f]); 63 | mStringBuilder.append(HEXDIGITS[i & 0x0f]); 64 | } 65 | } 66 | 67 | 68 | @Override 69 | public String toString() 70 | { 71 | return mStringBuilder.toString(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/encoding/utils/PercentEncodingOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding.utils; 18 | 19 | import org.dmfs.rfc3986.validation.CharSet; 20 | 21 | import java.io.IOException; 22 | import java.io.OutputStream; 23 | 24 | 25 | /** 26 | * An {@link OutputStream} that percent-encodes characters transparently. Calling {@link #toString()} returns the result. 27 | */ 28 | public final class PercentEncodingOutputStream extends OutputStream 29 | { 30 | private final static char[] HEXDIGITS = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 31 | 32 | private final StringBuilder mStringBuilder; 33 | private final CharSet mNoEncodeMap; 34 | 35 | 36 | public PercentEncodingOutputStream(int initialCapacity, CharSet noEncodeMap) 37 | { 38 | mStringBuilder = new StringBuilder(initialCapacity); 39 | mNoEncodeMap = noEncodeMap; 40 | } 41 | 42 | 43 | @Override 44 | public void write(int i) throws IOException 45 | { 46 | if (mNoEncodeMap.contains((char) i)) 47 | { 48 | mStringBuilder.append((char) i); 49 | } 50 | else 51 | { 52 | mStringBuilder.append('%'); 53 | mStringBuilder.append(HEXDIGITS[(i >>> 4) & 0x0f]); 54 | mStringBuilder.append(HEXDIGITS[i & 0x0f]); 55 | } 56 | } 57 | 58 | 59 | @Override 60 | public String toString() 61 | { 62 | return mStringBuilder.toString(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/fragments/OptionalLazyFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.fragments; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.Fragment; 22 | import org.dmfs.rfc3986.UriEncoded; 23 | 24 | import java.util.NoSuchElementException; 25 | 26 | import static org.dmfs.jems2.optional.Absent.absent; 27 | import static org.dmfs.rfc3986.validation.CharSets.FRAGMENT_CHAR; 28 | 29 | 30 | /** 31 | * An {@link Optional} {@link Fragment} parsed lazily. 32 | */ 33 | public final class OptionalLazyFragment implements Optional 34 | { 35 | private final UriEncoded mUriEncoded; 36 | private Optional mDelegate; 37 | 38 | 39 | public OptionalLazyFragment(UriEncoded uriEncoded) 40 | { 41 | mUriEncoded = uriEncoded; 42 | } 43 | 44 | 45 | @Override 46 | public boolean isPresent() 47 | { 48 | return fragment().isPresent(); 49 | } 50 | 51 | 52 | @Override 53 | public Fragment value() throws NoSuchElementException 54 | { 55 | return fragment().value(); 56 | } 57 | 58 | 59 | private Optional fragment() 60 | { 61 | if (mDelegate == null) 62 | { 63 | mDelegate = parsedFragment(); 64 | } 65 | return mDelegate; 66 | } 67 | 68 | 69 | private Optional parsedFragment() 70 | { 71 | final UriEncoded uriEncoded = mUriEncoded; 72 | final int count = uriEncoded.length(); 73 | if (count == 0 || uriEncoded.charAt(0) != '#') 74 | { 75 | // not a fragment 76 | return absent(); 77 | } 78 | 79 | int i = 1; 80 | while (i < count && FRAGMENT_CHAR.contains(uriEncoded.charAt(i))) 81 | { 82 | ++i; 83 | } 84 | 85 | if (i != count) 86 | { 87 | // illegal character in fragment 88 | throw new IllegalArgumentException( 89 | String.format("Query %s contains illegal char %c at position %d", uriEncoded.toString(), uriEncoded.charAt(i), i)); 90 | } 91 | 92 | return new Present(new SimpleFragment(uriEncoded.subSequence(1, count))); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/fragments/SimpleFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.fragments; 18 | 19 | import org.dmfs.rfc3986.Fragment; 20 | import org.dmfs.rfc3986.UriEncoded; 21 | import org.dmfs.rfc3986.encoding.XWwwFormUrlEncoded; 22 | import org.dmfs.rfc3986.parameters.ParameterList; 23 | 24 | import java.io.UnsupportedEncodingException; 25 | 26 | 27 | /** 28 | * A {@link Fragment} derived from a {@link UriEncoded} {@link CharSequence}. 29 | */ 30 | public final class SimpleFragment implements Fragment 31 | { 32 | private final UriEncoded mDelegate; 33 | 34 | 35 | public SimpleFragment(ParameterList parameters) 36 | { 37 | this(new XWwwFormUrlEncoded(parameters)); 38 | } 39 | 40 | 41 | public SimpleFragment(UriEncoded fragment) 42 | { 43 | mDelegate = fragment; 44 | } 45 | 46 | 47 | @Override 48 | public UriEncoded normalized() 49 | { 50 | return mDelegate.normalized(); 51 | } 52 | 53 | 54 | @Override 55 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 56 | { 57 | return mDelegate.decoded(charset); 58 | } 59 | 60 | 61 | @Override 62 | public CharSequence decoded() 63 | { 64 | return mDelegate.decoded(); 65 | } 66 | 67 | 68 | @Override 69 | public int length() 70 | { 71 | return mDelegate.length(); 72 | } 73 | 74 | 75 | @Override 76 | public char charAt(int i) 77 | { 78 | return mDelegate.charAt(i); 79 | } 80 | 81 | 82 | @Override 83 | public UriEncoded subSequence(int startIndex, int endIndex) 84 | { 85 | return mDelegate.subSequence(startIndex, endIndex); 86 | } 87 | 88 | 89 | @Override 90 | public String toString() 91 | { 92 | return mDelegate.toString(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/FluentParameterList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters; 18 | 19 | /** 20 | * A fluent interface to edit {@link ParameterList}s. 21 | */ 22 | public interface FluentParameterList extends ParameterList 23 | { 24 | /** 25 | * Appends the given parameters, even if parameters with the same names already exist. 26 | * 27 | * @param parameters The parameters to append. 28 | * @return An updated {@link FluentParameterList} instance. 29 | */ 30 | FluentParameterList alsoWith(Parameter... parameters); 31 | 32 | /** 33 | * Appends the given parameters, removing any other parameters that have the same names as the new ones. 34 | * 35 | * @param parameters The new parameters. 36 | * @return An updated {@link FluentParameterList} instance. 37 | */ 38 | FluentParameterList ratherWith(Parameter... parameters); 39 | 40 | /** 41 | * Removes any parameters of the given {@link ParameterType}s. 42 | * 43 | * @param types The parameter parametertypes to remove. 44 | * @return An updated {@link FluentParameterList} instance. 45 | */ 46 | FluentParameterList without(ParameterType... types); 47 | } 48 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/Parameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters; 18 | 19 | /** 20 | * A parameter. Parameters have a name and a text representation of the parameter value. 21 | */ 22 | public interface Parameter 23 | { 24 | /** 25 | * Returns the name of the parameter. 26 | * 27 | * @return The parameter name, 28 | */ 29 | CharSequence name(); 30 | 31 | /** 32 | * Returns the text value of the parameter. 33 | * 34 | * @return A {@link CharSequence} containing the parameter value in its text form. 35 | */ 36 | CharSequence textValue(); 37 | } 38 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/ParameterList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters; 18 | 19 | /** 20 | * Represents a set of {@link Parameter}s. 21 | */ 22 | public interface ParameterList extends Iterable 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/ParameterType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters; 18 | 19 | /** 20 | * The type of a parameter. 21 | */ 22 | public interface ParameterType 23 | { 24 | /** 25 | * Returns the name of the parameter. 26 | */ 27 | CharSequence name(); 28 | 29 | /** 30 | * Returns the parsed value of the given {@link Parameter}. 31 | * 32 | * @param parameter The {@link Parameter} to parse. 33 | */ 34 | T value(Parameter parameter); 35 | 36 | /** 37 | * Returns a parameter of this type with the given value. 38 | */ 39 | Parameter parameter(T value); 40 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/ValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters; 18 | 19 | /** 20 | * The type of a value a {@link Parameter} can have. 21 | */ 22 | public interface ValueType 23 | { 24 | /** 25 | * Returns the parsed value of the given text value. 26 | * 27 | * @param valueText The text representation of the value. 28 | * @return The parsed value. 29 | */ 30 | T parsedValue(CharSequence valueText); 31 | 32 | /** 33 | * Serializes the given value to its plain text representation. 34 | * 35 | * @param value The value to serialize. 36 | * @return The serialized value. 37 | */ 38 | CharSequence serializedValue(T value); 39 | } 40 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/adapters/MultiParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.adapters; 18 | 19 | import org.dmfs.jems2.iterator.Mapped; 20 | import org.dmfs.jems2.iterator.Sieved; 21 | import org.dmfs.rfc3986.parameters.Parameter; 22 | import org.dmfs.rfc3986.parameters.ParameterList; 23 | import org.dmfs.rfc3986.parameters.ParameterType; 24 | 25 | import java.util.Iterator; 26 | 27 | 28 | /** 29 | * The values of a {@link Parameter} that may be present any number of times. 30 | */ 31 | public final class MultiParameter implements Iterable 32 | { 33 | private final ParameterType mParameterType; 34 | private final Iterable mDelegate; 35 | 36 | 37 | public MultiParameter(ParameterType parameterType, ParameterList delegate) 38 | { 39 | mParameterType = parameterType; 40 | mDelegate = delegate; 41 | } 42 | 43 | 44 | @Override 45 | public Iterator iterator() 46 | { 47 | return new Mapped<>( 48 | mParameterType::value, 49 | new Sieved<>( 50 | // TODO: get rid of the toString conversion and use something like an `Equalable` 51 | // TODO: maybe move this check to ParameterType 52 | element -> element.name().toString().equals(mParameterType.name().toString()), 53 | mDelegate.iterator())); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/adapters/OptionalParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.adapters; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.iterator.Mapped; 21 | import org.dmfs.jems2.iterator.Sieved; 22 | import org.dmfs.rfc3986.parameters.Parameter; 23 | import org.dmfs.rfc3986.parameters.ParameterList; 24 | import org.dmfs.rfc3986.parameters.ParameterType; 25 | 26 | import java.util.Iterator; 27 | import java.util.NoSuchElementException; 28 | 29 | 30 | /** 31 | * The value of a {@link Parameter} that can be present once or not at all. 32 | */ 33 | public final class OptionalParameter implements Optional 34 | { 35 | private final Iterable mDelegate; 36 | private V mValue; 37 | private Boolean mIsPresent; 38 | 39 | 40 | public OptionalParameter(final ParameterType parameterType, final ParameterList delegate) 41 | { 42 | mDelegate = new Iterable() 43 | { 44 | @Override 45 | public Iterator iterator() 46 | { 47 | return new Mapped<>( 48 | parameterType::value, 49 | new Sieved<>( 50 | element -> 51 | // TODO: get rid of the toString conversion and use something like an `Equalable` 52 | // TODO: maybe move this check to ParameterType 53 | element.name().toString().equals(parameterType.name().toString()), 54 | delegate.iterator() 55 | )); 56 | } 57 | }; 58 | } 59 | 60 | 61 | @Override 62 | public boolean isPresent() 63 | { 64 | if (mIsPresent == null) 65 | { 66 | mIsPresent = mDelegate.iterator().hasNext(); 67 | } 68 | return mIsPresent; 69 | } 70 | 71 | 72 | @Override 73 | public V value() throws NoSuchElementException 74 | { 75 | if (mValue == null) 76 | { 77 | Iterator iterator = mDelegate.iterator(); 78 | if (!iterator.hasNext()) 79 | { 80 | throw new NoSuchElementException("No value present. Better call \"isPresent()\" beforehand."); 81 | } 82 | mValue = iterator.next(); 83 | } 84 | return mValue; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/adapters/TextParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.adapters; 18 | 19 | import org.dmfs.rfc3986.parameters.ParameterList; 20 | import org.dmfs.rfc3986.parameters.ParameterType; 21 | 22 | import java.util.NoSuchElementException; 23 | 24 | 25 | /** 26 | * A mandatory text parameter. If the given {@link ParameterList} doesn't contain any parameter of this type all methods will throw {@link 27 | * NoSuchElementException}. 28 | */ 29 | public final class TextParameter implements CharSequence 30 | { 31 | private final OptionalParameter mParameter; 32 | 33 | 34 | public TextParameter(ParameterType type, ParameterList parameterList) 35 | { 36 | mParameter = new OptionalParameter<>(type, parameterList); 37 | } 38 | 39 | 40 | @Override 41 | public int length() 42 | { 43 | return mParameter.value().length(); 44 | } 45 | 46 | 47 | @Override 48 | public char charAt(int i) 49 | { 50 | return mParameter.value().charAt(i); 51 | } 52 | 53 | 54 | @Override 55 | public CharSequence subSequence(int i, int i1) 56 | { 57 | return mParameter.value().subSequence(i, i1); 58 | } 59 | 60 | 61 | @Override 62 | public String toString() 63 | { 64 | return mParameter.value().toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/adapters/XwfueParameterList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.adapters; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.iterator.EmptyIterator; 21 | import org.dmfs.jems2.iterator.Mapped; 22 | import org.dmfs.jems2.optional.Present; 23 | import org.dmfs.rfc3986.UriEncoded; 24 | import org.dmfs.rfc3986.encoding.Precoded; 25 | import org.dmfs.rfc3986.parameters.Parameter; 26 | import org.dmfs.rfc3986.parameters.ParameterList; 27 | import org.dmfs.rfc3986.parameters.parameters.UrlEncodedParameter; 28 | import org.dmfs.rfc3986.utils.Split; 29 | 30 | import java.util.Iterator; 31 | 32 | 33 | /** 34 | * {@link ParameterList} adapter that interpret the adapted {@link UriEncoded} as an {@code x-www-form-urlencoded} structure. 35 | */ 36 | public final class XwfueParameterList implements ParameterList 37 | { 38 | private final Optional mDelegate; 39 | 40 | 41 | public XwfueParameterList(UriEncoded delegate) 42 | { 43 | this(new Present<>(delegate)); 44 | } 45 | 46 | 47 | public XwfueParameterList(Optional delegate) 48 | { 49 | mDelegate = delegate; 50 | } 51 | 52 | 53 | @Override 54 | public Iterator iterator() 55 | { 56 | if (!mDelegate.isPresent() || mDelegate.value().length() == 0) 57 | { 58 | return EmptyIterator.emptyIterator(); 59 | } 60 | 61 | return new Mapped<>(param -> new UrlEncodedParameter(new Precoded(param)), new Split(mDelegate.value(), '&')); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parameters/UrlEncodedParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parameters; 18 | 19 | import org.dmfs.rfc3986.UriEncoded; 20 | import org.dmfs.rfc3986.encoding.FormPrecoded; 21 | import org.dmfs.rfc3986.encoding.IdempotentEncoded; 22 | import org.dmfs.rfc3986.parameters.Parameter; 23 | 24 | import java.io.UnsupportedEncodingException; 25 | import java.nio.charset.Charset; 26 | import java.nio.charset.UnsupportedCharsetException; 27 | 28 | 29 | /** 30 | * A {@link Parameter} derived from a url encoded key-value-pair. 31 | */ 32 | public final class UrlEncodedParameter implements Parameter 33 | { 34 | private final CharSequence mEncodedParameter; 35 | private final String mCharSet; 36 | private UriEncoded mName; 37 | private UriEncoded mValue; 38 | 39 | 40 | public UrlEncodedParameter(UriEncoded encodedPair) 41 | { 42 | this(encodedPair, "UTF-8"); 43 | } 44 | 45 | 46 | public UrlEncodedParameter(UriEncoded encodedParameter, String charSet) throws UnsupportedCharsetException 47 | { 48 | mEncodedParameter = encodedParameter; 49 | mCharSet = charSet; 50 | // check early if the charset exists 51 | Charset.forName(charSet); 52 | } 53 | 54 | 55 | @Override 56 | public CharSequence name() 57 | { 58 | parse(); 59 | try 60 | { 61 | return mName.decoded(mCharSet); 62 | } 63 | catch (UnsupportedEncodingException e) 64 | { 65 | // this should not happen since we've already tried to load the charset in the constructor 66 | throw new RuntimeException(String.format("CharSet %s not supported by Runtime", mCharSet)); 67 | } 68 | } 69 | 70 | 71 | @Override 72 | public CharSequence textValue() 73 | { 74 | parse(); 75 | try 76 | { 77 | return mValue.decoded(mCharSet); 78 | } 79 | catch (UnsupportedEncodingException e) 80 | { 81 | // this should not happen since we've already tried to load the charset in the constructor 82 | throw new RuntimeException(String.format("CharSet %s not supported by Runtime", mCharSet)); 83 | } 84 | } 85 | 86 | 87 | private void parse() 88 | { 89 | if (mName == null) 90 | { 91 | int equalsPos = equalsPos(mEncodedParameter); 92 | mName = new FormPrecoded(mEncodedParameter.subSequence(0, equalsPos)); 93 | if (equalsPos < mEncodedParameter.length()) 94 | { 95 | mValue = new FormPrecoded(mEncodedParameter.subSequence(equalsPos + 1, mEncodedParameter.length())); 96 | } 97 | else 98 | { 99 | mValue = IdempotentEncoded.EMPTY; 100 | } 101 | } 102 | } 103 | 104 | 105 | private int equalsPos(CharSequence charSequence) 106 | { 107 | final int len = charSequence.length(); 108 | int i = 0; 109 | while (i < len && charSequence.charAt(i) != '=') 110 | { 111 | ++i; 112 | } 113 | return i; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/Appending.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.jems2.iterator.Concat; 20 | import org.dmfs.jems2.iterator.Seq; 21 | import org.dmfs.rfc3986.parameters.Parameter; 22 | import org.dmfs.rfc3986.parameters.ParameterList; 23 | 24 | import java.util.Iterator; 25 | 26 | 27 | /** 28 | * A {@link ParameterList} which appends the given parameters to the decorated ones. 29 | */ 30 | public final class Appending implements ParameterList 31 | { 32 | private final ParameterList mDelegate; 33 | private final Parameter[] mNewParameters; 34 | 35 | 36 | public Appending(ParameterList delegate, Parameter... newParameters) 37 | { 38 | mDelegate = delegate; 39 | mNewParameters = newParameters; 40 | } 41 | 42 | 43 | @Override 44 | public Iterator iterator() 45 | { 46 | return new Concat<>(mDelegate.iterator(), new Seq<>(mNewParameters)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/BasicParameterList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.rfc3986.parameters.Parameter; 20 | import org.dmfs.rfc3986.parameters.ParameterList; 21 | 22 | import java.util.Arrays; 23 | import java.util.Iterator; 24 | 25 | 26 | /** 27 | * Basic {@link ParameterList} containing all {@link Parameter}s passed in an array or {@link Iterable}. 28 | */ 29 | public final class BasicParameterList implements ParameterList 30 | { 31 | private final Iterable mParameters; 32 | 33 | 34 | public BasicParameterList(Parameter... parameters) 35 | { 36 | this(Arrays.asList(parameters.clone())); 37 | } 38 | 39 | 40 | /** 41 | * Creates a {@link ParameterList} from the given {@link Iterable} or {@link Parameter}s. The given {@link Iterable} must be immutable. 42 | * 43 | * @param parameters An immutable {@link Iterable} of {@link Parameter}s. 44 | */ 45 | public BasicParameterList(Iterable parameters) 46 | { 47 | mParameters = parameters; 48 | } 49 | 50 | 51 | @Override 52 | public Iterator iterator() 53 | { 54 | return mParameters.iterator(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/EmptyParameterList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.jems2.iterator.EmptyIterator; 20 | import org.dmfs.rfc3986.parameters.Parameter; 21 | import org.dmfs.rfc3986.parameters.ParameterList; 22 | 23 | import java.util.Iterator; 24 | 25 | 26 | /** 27 | * {@link ParameterList} that doesn't contain any parameters. 28 | */ 29 | public final class EmptyParameterList implements ParameterList 30 | { 31 | public static final ParameterList INSTANCE = new EmptyParameterList(); 32 | 33 | 34 | @Override 35 | public Iterator iterator() 36 | { 37 | return EmptyIterator.emptyIterator(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/Fluent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.rfc3986.parameters.FluentParameterList; 20 | import org.dmfs.rfc3986.parameters.Parameter; 21 | import org.dmfs.rfc3986.parameters.ParameterList; 22 | import org.dmfs.rfc3986.parameters.ParameterType; 23 | 24 | import java.util.Iterator; 25 | 26 | 27 | /** 28 | * A fluent decorator to edit {@link ParameterList} in a convenient manner. 29 | */ 30 | public final class Fluent implements FluentParameterList 31 | { 32 | private final ParameterList mDelegate; 33 | 34 | 35 | public Fluent() 36 | { 37 | this(EmptyParameterList.INSTANCE); 38 | } 39 | 40 | 41 | public Fluent(ParameterList delegate) 42 | { 43 | mDelegate = delegate; 44 | } 45 | 46 | 47 | @Override 48 | public FluentParameterList alsoWith(Parameter... parameters) 49 | { 50 | return new Fluent(new Appending(mDelegate, parameters)); 51 | } 52 | 53 | 54 | @Override 55 | public FluentParameterList ratherWith(Parameter... parameters) 56 | { 57 | return new Fluent(new Replacing(mDelegate, parameters)); 58 | } 59 | 60 | 61 | @Override 62 | public FluentParameterList without(ParameterType... types) 63 | { 64 | return new Fluent(new Removing(mDelegate, types)); 65 | } 66 | 67 | 68 | @Override 69 | public Iterator iterator() 70 | { 71 | return mDelegate.iterator(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/Removing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.jems2.iterator.Sieved; 20 | import org.dmfs.rfc3986.parameters.Parameter; 21 | import org.dmfs.rfc3986.parameters.ParameterList; 22 | import org.dmfs.rfc3986.parameters.ParameterType; 23 | 24 | import java.util.Iterator; 25 | 26 | 27 | /** 28 | * {@link ParameterList} decorator that removes any parameters of the given {@link ParameterType}s. 29 | */ 30 | public final class Removing implements ParameterList 31 | { 32 | private final ParameterList mDelegate; 33 | private final ParameterType[] mRemovedTypes; 34 | 35 | 36 | public Removing(ParameterList delegate, ParameterType... removedTypes) 37 | { 38 | mDelegate = delegate; 39 | mRemovedTypes = removedTypes; 40 | } 41 | 42 | 43 | @Override 44 | public Iterator iterator() 45 | { 46 | return new Sieved<>( 47 | element -> { 48 | for (ParameterType param : mRemovedTypes) 49 | { 50 | // TODO: get rid of the toString conversion and use something like an `Equalable` 51 | // TODO: maybe move this check to ParameterType 52 | if (param.name().toString().equals(element.name().toString())) 53 | { 54 | return false; 55 | } 56 | } 57 | return true; 58 | }, 59 | 60 | mDelegate.iterator()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametersets/Replacing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametersets; 18 | 19 | import org.dmfs.jems2.iterator.Concat; 20 | import org.dmfs.jems2.iterator.Seq; 21 | import org.dmfs.jems2.iterator.Sieved; 22 | import org.dmfs.rfc3986.parameters.Parameter; 23 | import org.dmfs.rfc3986.parameters.ParameterList; 24 | 25 | import java.util.Iterator; 26 | 27 | 28 | /** 29 | * {@link ParameterList} that replaces values of the decorated {@link ParameterList} with the given values. 30 | */ 31 | public final class Replacing implements ParameterList 32 | { 33 | private final ParameterList mDelegate; 34 | private final Parameter[] mNewParameters; 35 | 36 | 37 | public Replacing(ParameterList delegate, Parameter... newParameters) 38 | { 39 | mDelegate = delegate; 40 | mNewParameters = newParameters; 41 | } 42 | 43 | 44 | @Override 45 | public Iterator iterator() 46 | { 47 | return new Concat<>( 48 | 49 | new Sieved<>( 50 | element -> { 51 | // don't iterate keys that we have in mNewParameters 52 | for (Parameter parameter : mNewParameters) 53 | { 54 | // TODO: get rid of the toString conversion and use something like an `Equalable` 55 | // TODO: maybe move this check to ParameterType 56 | if (parameter.name().toString().equals(element.name().toString())) 57 | { 58 | return false; 59 | } 60 | } 61 | return true; 62 | }, 63 | mDelegate.iterator()), new Seq<>(mNewParameters)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/parametertypes/BasicParameterType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parametertypes; 18 | 19 | import org.dmfs.rfc3986.parameters.Parameter; 20 | import org.dmfs.rfc3986.parameters.ParameterType; 21 | import org.dmfs.rfc3986.parameters.ValueType; 22 | 23 | 24 | /** 25 | * A basic {@link ParameterType} implementation. 26 | */ 27 | public final class BasicParameterType implements ParameterType 28 | { 29 | private final CharSequence mName; 30 | private final ValueType mValueType; 31 | 32 | 33 | /** 34 | * Creates a {@link ParameterType} with the given name and {@link ValueType}. 35 | */ 36 | public BasicParameterType(CharSequence name, ValueType valueType) 37 | { 38 | mName = name; 39 | mValueType = valueType; 40 | } 41 | 42 | 43 | @Override 44 | public CharSequence name() 45 | { 46 | return mName; 47 | } 48 | 49 | 50 | @Override 51 | public T value(Parameter parameter) 52 | { 53 | if (!name().toString().equals(parameter.name().toString())) 54 | { 55 | throw new IllegalArgumentException( 56 | String.format("Given parameter has wrong type \"%s\". Expected type \"%s\"", parameter.name().toString(), mName.toString())); 57 | } 58 | return mValueType.parsedValue(parameter.textValue()); 59 | } 60 | 61 | 62 | @Override 63 | public Parameter parameter(final T value) 64 | { 65 | return new Parameter() 66 | { 67 | @Override 68 | public CharSequence name() 69 | { 70 | return mName; 71 | } 72 | 73 | 74 | @Override 75 | public CharSequence textValue() 76 | { 77 | return mValueType.serializedValue(value); 78 | } 79 | }; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/valuetypes/BooleanValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.valuetypes; 18 | 19 | import org.dmfs.rfc3986.parameters.ValueType; 20 | 21 | 22 | /** 23 | * A {@link ValueType} for {@link Boolean} parameters. 24 | */ 25 | public final class BooleanValueType implements ValueType 26 | { 27 | public final static BooleanValueType INSTANCE = new BooleanValueType(); 28 | 29 | 30 | @Override 31 | public Boolean parsedValue(CharSequence valueText) 32 | { 33 | return Boolean.parseBoolean(valueText.toString()) || "1".equals(valueText.toString()); 34 | } 35 | 36 | 37 | @Override 38 | public CharSequence serializedValue(Boolean value) 39 | { 40 | return value.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/valuetypes/IntegerValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.valuetypes; 18 | 19 | import org.dmfs.rfc3986.parameters.ValueType; 20 | 21 | 22 | /** 23 | * A {@link ValueType} for integer parameters. 24 | */ 25 | public final class IntegerValueType implements ValueType 26 | { 27 | public final static IntegerValueType INSTANCE = new IntegerValueType(); 28 | 29 | 30 | @Override 31 | public Integer parsedValue(CharSequence valueText) 32 | { 33 | return Integer.parseInt(valueText.toString()); 34 | } 35 | 36 | 37 | @Override 38 | public CharSequence serializedValue(Integer value) 39 | { 40 | return value.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/parameters/valuetypes/TextValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.valuetypes; 18 | 19 | import org.dmfs.rfc3986.parameters.ValueType; 20 | 21 | 22 | /** 23 | * A {@link ValueType} for plain text parameters. 24 | */ 25 | public final class TextValueType implements ValueType 26 | { 27 | public final static TextValueType INSTANCE = new TextValueType(); 28 | 29 | 30 | @Override 31 | public CharSequence parsedValue(CharSequence valueText) 32 | { 33 | return valueText; 34 | } 35 | 36 | 37 | @Override 38 | public CharSequence serializedValue(CharSequence value) 39 | { 40 | return value; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/paths/EmptyPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.rfc3986.Path; 20 | import org.dmfs.rfc3986.UriEncoded; 21 | 22 | import java.util.Iterator; 23 | 24 | import static org.dmfs.jems2.iterator.EmptyIterator.emptyIterator; 25 | 26 | 27 | /** 28 | * An empty {@link Path}. By definition, it has no path segments and is not absolute. 29 | */ 30 | public final class EmptyPath implements Path 31 | { 32 | public final static EmptyPath INSTANCE = new EmptyPath(); 33 | 34 | 35 | @Override 36 | public boolean isEmpty() 37 | { 38 | return true; 39 | } 40 | 41 | 42 | @Override 43 | public boolean isAbsolute() 44 | { 45 | return false; 46 | } 47 | 48 | 49 | @Override 50 | public Iterator iterator() 51 | { 52 | return emptyIterator(); 53 | } 54 | 55 | 56 | @Override 57 | public int hashCode() 58 | { 59 | return 0; 60 | } 61 | 62 | 63 | @Override 64 | public boolean equals(Object obj) 65 | { 66 | return obj instanceof Path && ((Path) obj).isEmpty(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/paths/EncodedPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.jems2.iterator.Mapped; 20 | import org.dmfs.rfc3986.Path; 21 | import org.dmfs.rfc3986.UriEncoded; 22 | import org.dmfs.rfc3986.encoding.Precoded; 23 | import org.dmfs.rfc3986.utils.Split; 24 | 25 | import java.util.Iterator; 26 | 27 | 28 | /** 29 | * A path that's derived from a properly encoded String. 30 | */ 31 | public final class EncodedPath implements Path 32 | { 33 | private final CharSequence mPath; 34 | 35 | 36 | public EncodedPath(UriEncoded path) 37 | { 38 | mPath = path; 39 | } 40 | 41 | 42 | @Override 43 | public boolean isEmpty() 44 | { 45 | return mPath.length() == 0; 46 | } 47 | 48 | 49 | @Override 50 | public boolean isAbsolute() 51 | { 52 | return mPath.length() > 0 && mPath.charAt(0) == '/'; 53 | } 54 | 55 | 56 | @Override 57 | public Iterator iterator() 58 | { 59 | if (isEmpty()) 60 | { 61 | return org.dmfs.jems2.iterator.EmptyIterator.emptyIterator(); 62 | } 63 | return new Mapped<>(Precoded::new, new Split(mPath, '/')); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/paths/LazyPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.rfc3986.Path; 20 | import org.dmfs.rfc3986.UriEncoded; 21 | import org.dmfs.rfc3986.utils.Parsed; 22 | 23 | import java.util.Iterator; 24 | 25 | import static org.dmfs.rfc3986.validation.CharSets.PCHAR; 26 | 27 | 28 | /** 29 | * A lazy {@link Path}. It's not parsed nor validated until it's actually needed. 30 | */ 31 | public final class LazyPath implements Path, Parsed 32 | { 33 | private final UriEncoded mUriEncoded; 34 | private Path mDelegate; 35 | private int mEnd; 36 | 37 | 38 | public LazyPath(UriEncoded uri) 39 | { 40 | mUriEncoded = uri; 41 | } 42 | 43 | 44 | @Override 45 | public boolean isEmpty() 46 | { 47 | return path().isEmpty(); 48 | } 49 | 50 | 51 | @Override 52 | public boolean isAbsolute() 53 | { 54 | return path().isAbsolute(); 55 | } 56 | 57 | 58 | @Override 59 | public Iterator iterator() 60 | { 61 | return path().iterator(); 62 | } 63 | 64 | 65 | private Path path() 66 | { 67 | if (mDelegate == null) 68 | { 69 | mDelegate = parsedPath(); 70 | } 71 | return mDelegate; 72 | } 73 | 74 | 75 | private Path parsedPath() 76 | { 77 | final UriEncoded uriEncoded = mUriEncoded; 78 | final int count = uriEncoded.length(); 79 | int i = 0; 80 | if (i == count) 81 | { 82 | return EmptyPath.INSTANCE; 83 | } 84 | while (i < count && (PCHAR.contains(uriEncoded.charAt(i)) || uriEncoded.charAt(i) == '/')) 85 | { 86 | ++i; 87 | } 88 | mEnd = i; 89 | return new EncodedPath(uriEncoded.subSequence(0, i)); 90 | } 91 | 92 | 93 | @Override 94 | public int parsedLength() 95 | { 96 | path(); 97 | return mEnd; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/paths/StructuredPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.jems2.iterator.Seq; 20 | import org.dmfs.rfc3986.Path; 21 | import org.dmfs.rfc3986.UriEncoded; 22 | import org.dmfs.rfc3986.encoding.IdempotentEncoded; 23 | 24 | import java.util.Iterator; 25 | 26 | 27 | /** 28 | * A path that's assembled from its individual (encoded) path segments 29 | *

30 | * Note: If the first segment equals {@link IdempotentEncoded#EMPTY} the result is an absolute Path. A {@link IdempotentEncoded#EMPTY} element at the 31 | * essentially appends a '/' to the end of the String representation. 32 | */ 33 | public final class StructuredPath implements Path 34 | { 35 | private final UriEncoded[] mPathSegments; 36 | 37 | 38 | public StructuredPath(UriEncoded... segments) 39 | { 40 | mPathSegments = segments.clone(); 41 | } 42 | 43 | 44 | @Override 45 | public boolean isEmpty() 46 | { 47 | return mPathSegments.length == 0; 48 | } 49 | 50 | 51 | @Override 52 | public boolean isAbsolute() 53 | { 54 | return mPathSegments.length > 0 && IdempotentEncoded.EMPTY.equals(mPathSegments[0]); 55 | } 56 | 57 | 58 | @Override 59 | public Iterator iterator() 60 | { 61 | return new Seq<>(mPathSegments); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/paths/Text.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.rfc3986.Path; 20 | import org.dmfs.rfc3986.UriEncoded; 21 | 22 | 23 | /** 24 | * An adapter that adapts a {@link Path} to a {@link CharSequence}. 25 | */ 26 | public final class Text implements CharSequence 27 | { 28 | private final Path mDelegate; 29 | private String mPath; 30 | 31 | 32 | public Text(Path delegate) 33 | { 34 | mDelegate = delegate; 35 | } 36 | 37 | 38 | @Override 39 | public int length() 40 | { 41 | if (mPath == null) 42 | { 43 | // we don't have a cached copy of the path, so just sum the length of all segments 44 | int len = 0; 45 | for (UriEncoded segment : mDelegate) 46 | { 47 | len += segment.length() + 1; 48 | } 49 | return len == 0 ? 0 : len - 1; 50 | } 51 | return mPath.length(); 52 | } 53 | 54 | 55 | @Override 56 | public char charAt(int index) 57 | { 58 | return toString().charAt(index); 59 | } 60 | 61 | 62 | @Override 63 | public CharSequence subSequence(int beginIndex, int endIndex) 64 | { 65 | return toString().subSequence(beginIndex, endIndex); 66 | } 67 | 68 | 69 | @Override 70 | public String toString() 71 | { 72 | if (mPath == null) 73 | { 74 | StringBuilder stringBuilder = new StringBuilder(256); 75 | boolean first = true; 76 | for (UriEncoded segment : mDelegate) 77 | { 78 | if (first) 79 | { 80 | first = false; 81 | } 82 | else 83 | { 84 | stringBuilder.append('/'); 85 | } 86 | stringBuilder.append(segment); 87 | } 88 | mPath = stringBuilder.toString(); 89 | } 90 | return mPath; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/queries/OptionalLazyQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.queries; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.Query; 22 | import org.dmfs.rfc3986.UriEncoded; 23 | import org.dmfs.rfc3986.utils.Parsed; 24 | 25 | import java.util.NoSuchElementException; 26 | 27 | import static org.dmfs.jems2.optional.Absent.absent; 28 | import static org.dmfs.rfc3986.validation.CharSets.QUERY_CHAR; 29 | 30 | 31 | /** 32 | * An {@link Optional}, lazily parsed and validated {@link Query}. 33 | */ 34 | public final class OptionalLazyQuery implements Optional, Parsed 35 | { 36 | private final UriEncoded mUriEncoded; 37 | private Optional mDelegate; 38 | private int mEnd; 39 | 40 | 41 | /** 42 | * Creates an {@link Optional} lazily evaluated {@link Query}. The given input is considered to contain a {@link Query} if it starts with a {@code "?"} 43 | * character. The {@code "?"} will not be part of the {@link Query}. 44 | *

45 | * If the input doesn't start with a {@code "?"}, the optional {@link Query} will not be "present". 46 | */ 47 | public OptionalLazyQuery(UriEncoded uriEncoded) 48 | { 49 | mUriEncoded = uriEncoded; 50 | } 51 | 52 | 53 | @Override 54 | public boolean isPresent() 55 | { 56 | return query().isPresent(); 57 | } 58 | 59 | 60 | @Override 61 | public Query value() throws NoSuchElementException 62 | { 63 | return query().value(); 64 | } 65 | 66 | 67 | private Optional query() 68 | { 69 | if (mDelegate == null) 70 | { 71 | mDelegate = parsedQuery(); 72 | } 73 | return mDelegate; 74 | } 75 | 76 | 77 | private Optional parsedQuery() 78 | { 79 | final UriEncoded encoded = mUriEncoded; 80 | final int count = encoded.length(); 81 | 82 | if (count == 0 || encoded.charAt(0) != '?') 83 | { 84 | // not a query 85 | return absent(); 86 | } 87 | 88 | int i = 1; 89 | while (i < count && QUERY_CHAR.contains(encoded.charAt(i))) 90 | { 91 | ++i; 92 | } 93 | 94 | if (i < count && encoded.charAt(i) != '#') 95 | { 96 | // the query can only be terminated by the end of the string or a fragment 97 | throw new IllegalArgumentException( 98 | String.format("Query %s contains illegal char %c at position %d", encoded.toString(), encoded.charAt(i), i)); 99 | } 100 | 101 | mEnd = i; 102 | return new Present(new SimpleQuery(encoded.subSequence(1 /* don't include the "?" */, i))); 103 | } 104 | 105 | 106 | @Override 107 | public int parsedLength() 108 | { 109 | // make sure the query has been parsed 110 | query(); 111 | return mEnd; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/queries/SimpleQuery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.queries; 18 | 19 | import org.dmfs.rfc3986.Query; 20 | import org.dmfs.rfc3986.UriEncoded; 21 | import org.dmfs.rfc3986.encoding.XWwwFormUrlEncoded; 22 | import org.dmfs.rfc3986.parameters.ParameterList; 23 | 24 | import java.io.UnsupportedEncodingException; 25 | 26 | 27 | /** 28 | * A {@link Query} derived from an encoded query string. 29 | */ 30 | public final class SimpleQuery implements Query 31 | { 32 | private final UriEncoded mDelegate; 33 | 34 | 35 | public SimpleQuery(ParameterList params) 36 | { 37 | this(new XWwwFormUrlEncoded(params)); 38 | } 39 | 40 | 41 | public SimpleQuery(UriEncoded delegate) 42 | { 43 | mDelegate = delegate; 44 | } 45 | 46 | 47 | @Override 48 | public UriEncoded normalized() 49 | { 50 | return mDelegate.normalized(); 51 | } 52 | 53 | 54 | @Override 55 | public CharSequence decoded(String charset) throws UnsupportedEncodingException 56 | { 57 | return mDelegate.decoded(charset); 58 | } 59 | 60 | 61 | @Override 62 | public CharSequence decoded() 63 | { 64 | return mDelegate.decoded(); 65 | } 66 | 67 | 68 | @Override 69 | public int length() 70 | { 71 | return mDelegate.length(); 72 | } 73 | 74 | 75 | @Override 76 | public char charAt(int i) 77 | { 78 | return mDelegate.charAt(i); 79 | } 80 | 81 | 82 | @Override 83 | public UriEncoded subSequence(int startIndex, int endIndex) 84 | { 85 | return mDelegate.subSequence(startIndex, endIndex); 86 | } 87 | 88 | 89 | @Override 90 | public String toString() 91 | { 92 | return mDelegate.toString(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/schemes/OptionalLazyScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.Scheme; 22 | import org.dmfs.rfc3986.UriEncoded; 23 | import org.dmfs.rfc3986.utils.Parsed; 24 | 25 | import java.util.NoSuchElementException; 26 | 27 | import static org.dmfs.jems2.optional.Absent.absent; 28 | import static org.dmfs.rfc3986.validation.CharSets.ALPHA; 29 | import static org.dmfs.rfc3986.validation.CharSets.SCHEME_CHAR; 30 | 31 | 32 | /** 33 | * The {@link Optional} {@link Scheme} of a {@link UriEncoded} URI. 34 | *

35 | * Note that the presence of a {@link Scheme} in the result doesn't guarantee a valid URI. It only guarantees, if the input data represents a valid URI, this is 36 | * the Scheme of it. 37 | */ 38 | public final class OptionalLazyScheme implements Optional, Parsed 39 | { 40 | private final UriEncoded mUriEncoded; 41 | private Optional mOptionalScheme; 42 | private int mEnd; 43 | 44 | 45 | public OptionalLazyScheme(UriEncoded uriEncoded) 46 | { 47 | mUriEncoded = uriEncoded; 48 | } 49 | 50 | 51 | @Override 52 | public boolean isPresent() 53 | { 54 | return scheme().isPresent(); 55 | } 56 | 57 | @Override 58 | public Scheme value() throws NoSuchElementException 59 | { 60 | return scheme().value(); 61 | } 62 | 63 | 64 | private Optional scheme() 65 | { 66 | if (mOptionalScheme == null) 67 | { 68 | mOptionalScheme = parsedScheme(); 69 | } 70 | return mOptionalScheme; 71 | } 72 | 73 | 74 | private Optional parsedScheme() 75 | { 76 | final UriEncoded uriEncoded = mUriEncoded; 77 | final int count = uriEncoded.length(); 78 | if (count < 2 || !ALPHA.contains(uriEncoded.charAt(0))) 79 | { 80 | // too short (to hold an ALPHA and a colon) or doesn't start with an ALPHA, not a scheme 81 | return absent(); 82 | } 83 | 84 | int i = 1; 85 | while (i < count && SCHEME_CHAR.contains(uriEncoded.charAt(i))) 86 | { 87 | ++i; 88 | } 89 | 90 | if (i < 2 || i == count || uriEncoded.charAt(i) != ':') 91 | { 92 | // a scheme needs to be at least one character long and has to be terminated by a colon 93 | return absent(); 94 | } 95 | mEnd = i + 1 /* account for the colon which is not part of the actual scheme */; 96 | return new Present(new ParsedScheme(uriEncoded.subSequence(0, i))); 97 | } 98 | 99 | 100 | @Override 101 | public int parsedLength() 102 | { 103 | scheme(); 104 | return mEnd; 105 | } 106 | 107 | 108 | /** 109 | * A private class to hold the actual scheme. It doesn't perform any validation, so we don't make it public and use it with validated {@link CharSequence}s 110 | * only. 111 | *

112 | * TODO: implement equals && hashCode 113 | */ 114 | private final static class ParsedScheme implements Scheme 115 | { 116 | private final CharSequence mScheme; 117 | 118 | 119 | private ParsedScheme(CharSequence scheme) 120 | { 121 | mScheme = scheme; 122 | } 123 | 124 | 125 | @Override 126 | public int length() 127 | { 128 | return mScheme.length(); 129 | } 130 | 131 | 132 | @Override 133 | public char charAt(int i) 134 | { 135 | return mScheme.charAt(i); 136 | } 137 | 138 | 139 | @Override 140 | public CharSequence subSequence(int i, int i1) 141 | { 142 | return mScheme.subSequence(i, i1); 143 | } 144 | 145 | 146 | @Override 147 | public String toString() 148 | { 149 | return mScheme.toString(); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/schemes/Schemes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.dmfs.rfc3986.Scheme; 20 | 21 | 22 | /** 23 | * A collection of known URI schemes. 24 | */ 25 | public final class Schemes 26 | { 27 | public final static Scheme FTP = new StringScheme("ftp"); 28 | public final static Scheme HTTP = new StringScheme("http"); 29 | public final static Scheme HTTPS = new StringScheme("https"); 30 | public final static Scheme MAILTO = new StringScheme("mailto"); 31 | 32 | 33 | private Schemes() 34 | { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/schemes/StringScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.dmfs.rfc3986.Scheme; 20 | import org.dmfs.rfc3986.validation.CharSets; 21 | import org.dmfs.rfc3986.validation.Validated; 22 | 23 | import java.util.Locale; 24 | 25 | 26 | /** 27 | * A {@link Scheme} derived from a String. 28 | */ 29 | public final class StringScheme implements Scheme 30 | { 31 | private final CharSequence mScheme; 32 | 33 | 34 | public StringScheme(String scheme) 35 | { 36 | mScheme = new Validated(scheme.toLowerCase(Locale.ENGLISH), CharSets.SCHEME_CHAR); 37 | } 38 | 39 | 40 | @Override 41 | public int length() 42 | { 43 | return mScheme.length(); 44 | } 45 | 46 | 47 | @Override 48 | public char charAt(int i) 49 | { 50 | return mScheme.charAt(i); 51 | } 52 | 53 | 54 | @Override 55 | public CharSequence subSequence(int i, int i1) 56 | { 57 | return mScheme.subSequence(i, i1); 58 | } 59 | 60 | 61 | @Override 62 | public String toString() 63 | { 64 | return mScheme.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/EmptyUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.rfc3986.*; 21 | import org.dmfs.rfc3986.paths.EmptyPath; 22 | 23 | import static org.dmfs.jems2.optional.Absent.absent; 24 | 25 | 26 | /** 27 | * Special case of a {@link Uri} that doesn't contain any values. 28 | */ 29 | public final class EmptyUri implements Uri 30 | { 31 | public final static EmptyUri INSTANCE = new EmptyUri(); 32 | 33 | 34 | @Override 35 | public Optional scheme() 36 | { 37 | return absent(); 38 | } 39 | 40 | 41 | @Override 42 | public Optional authority() 43 | { 44 | return absent(); 45 | } 46 | 47 | 48 | @Override 49 | public Path path() 50 | { 51 | return EmptyPath.INSTANCE; 52 | } 53 | 54 | 55 | @Override 56 | public Optional query() 57 | { 58 | return absent(); 59 | } 60 | 61 | 62 | @Override 63 | public Optional fragment() 64 | { 65 | return absent(); 66 | } 67 | 68 | 69 | @Override 70 | public boolean isHierarchical() 71 | { 72 | return false; 73 | } 74 | 75 | 76 | @Override 77 | public boolean isAbsolute() 78 | { 79 | return false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/LazyUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.rfc3986.Fragment; 21 | import org.dmfs.rfc3986.Scheme; 22 | import org.dmfs.rfc3986.Uri; 23 | import org.dmfs.rfc3986.UriEncoded; 24 | import org.dmfs.rfc3986.authorities.OptionalLazyAuthority; 25 | import org.dmfs.rfc3986.fragments.OptionalLazyFragment; 26 | import org.dmfs.rfc3986.paths.LazyPath; 27 | import org.dmfs.rfc3986.queries.OptionalLazyQuery; 28 | import org.dmfs.rfc3986.schemes.OptionalLazyScheme; 29 | 30 | 31 | /** 32 | * A lazily parsed and validated {@link Uri}. 33 | *

34 | * To validate the entire URI you need to call {@link #fragment()}, otherwise the URI is only parsed and validated as far as necessary. 35 | */ 36 | public final class LazyUri implements Uri 37 | { 38 | private final UriEncoded mUriEncoded; 39 | private final OptionalLazyScheme mOptionalScheme; 40 | private OptionalLazyAuthority mAuthority; 41 | private LazyPath mPath; 42 | private OptionalLazyQuery mQuery; 43 | private Optional mFragment; 44 | 45 | 46 | /** 47 | * Create a lazy {@link Uri} from the given {@link UriEncoded} {@link CharSequence}. 48 | * 49 | * @param uri The properly {@link UriEncoded} uri. 50 | */ 51 | public LazyUri(UriEncoded uri) 52 | { 53 | mUriEncoded = uri; 54 | mOptionalScheme = new OptionalLazyScheme(uri); 55 | } 56 | 57 | 58 | @Override 59 | public Optional scheme() 60 | { 61 | return mOptionalScheme; 62 | } 63 | 64 | 65 | @Override 66 | public OptionalLazyAuthority authority() 67 | { 68 | if (mAuthority == null) 69 | { 70 | mAuthority = new OptionalLazyAuthority(mUriEncoded.subSequence(mOptionalScheme.parsedLength(), mUriEncoded.length())); 71 | } 72 | return mAuthority; 73 | } 74 | 75 | 76 | @Override 77 | public LazyPath path() 78 | { 79 | if (mPath == null) 80 | { 81 | mPath = new LazyPath(mUriEncoded.subSequence(mOptionalScheme.parsedLength() + authority().parsedLength(), mUriEncoded.length())); 82 | } 83 | return mPath; 84 | } 85 | 86 | 87 | @Override 88 | public OptionalLazyQuery query() 89 | { 90 | if (mQuery == null) 91 | { 92 | mQuery = new OptionalLazyQuery( 93 | mUriEncoded.subSequence(mOptionalScheme.parsedLength() + authority().parsedLength() + path().parsedLength(), mUriEncoded.length())); 94 | } 95 | return mQuery; 96 | } 97 | 98 | 99 | @Override 100 | public Optional fragment() 101 | { 102 | if (mFragment == null) 103 | { 104 | mFragment = new OptionalLazyFragment( 105 | mUriEncoded.subSequence(mOptionalScheme.parsedLength() + authority().parsedLength() + path().parsedLength() + query().parsedLength(), 106 | mUriEncoded.length())); 107 | } 108 | return mFragment; 109 | } 110 | 111 | 112 | @Override 113 | public boolean isHierarchical() 114 | { 115 | return !mOptionalScheme.isPresent() || authority().isPresent() || path().isAbsolute(); 116 | } 117 | 118 | 119 | @Override 120 | public boolean isAbsolute() 121 | { 122 | return mOptionalScheme.isPresent(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/Normalized.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Present; 21 | import org.dmfs.rfc3986.*; 22 | import org.dmfs.rfc3986.fragments.SimpleFragment; 23 | import org.dmfs.rfc3986.queries.SimpleQuery; 24 | 25 | 26 | /** 27 | * {@link Uri} decorator that normalizes the path of any given {@link Uri} 28 | */ 29 | public final class Normalized implements Uri 30 | { 31 | private final Uri mDelegate; 32 | 33 | 34 | public Normalized(Uri delegate) 35 | { 36 | mDelegate = delegate; 37 | } 38 | 39 | 40 | @Override 41 | public Optional scheme() 42 | { 43 | return mDelegate.scheme(); 44 | } 45 | 46 | 47 | @Override 48 | public Optional authority() 49 | { 50 | return mDelegate.authority(); 51 | } 52 | 53 | 54 | @Override 55 | public Path path() 56 | { 57 | return new org.dmfs.rfc3986.paths.Normalized(mDelegate.path()); 58 | } 59 | 60 | 61 | @Override 62 | public Optional query() 63 | { 64 | Optional query = mDelegate.query(); 65 | if (!query.isPresent()) 66 | { 67 | return query; 68 | } 69 | return new Present<>(new SimpleQuery(mDelegate.query().value().normalized())); 70 | } 71 | 72 | 73 | @Override 74 | public Optional fragment() 75 | { 76 | Optional fragment = mDelegate.fragment(); 77 | if (!fragment.isPresent()) 78 | { 79 | return fragment; 80 | } 81 | return new Present<>(new SimpleFragment(mDelegate.fragment().value().normalized())); 82 | } 83 | 84 | 85 | @Override 86 | public boolean isHierarchical() 87 | { 88 | return mDelegate.isHierarchical(); 89 | } 90 | 91 | 92 | @Override 93 | public boolean isAbsolute() 94 | { 95 | return mDelegate.isAbsolute(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/OpaqueUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Absent; 21 | import org.dmfs.jems2.optional.Present; 22 | import org.dmfs.rfc3986.*; 23 | import org.dmfs.rfc3986.paths.EmptyPath; 24 | 25 | import static org.dmfs.jems2.optional.Absent.absent; 26 | 27 | 28 | /** 29 | * An absolute {@link Uri} without authority. 30 | */ 31 | public final class OpaqueUri implements Uri 32 | { 33 | private final Optional mScheme; 34 | private final Path mPath; 35 | private final Optional mQuery; 36 | private final Optional mFragment; 37 | 38 | 39 | public OpaqueUri(Scheme scheme) 40 | { 41 | this(new Present<>(scheme), EmptyPath.INSTANCE, Absent.absent(), Absent.absent()); 42 | } 43 | 44 | 45 | public OpaqueUri(Scheme scheme, Path path) 46 | { 47 | this(new Present<>(scheme), path, Absent.absent(), Absent.absent()); 48 | } 49 | 50 | 51 | public OpaqueUri(Scheme scheme, Path path, Query query) 52 | { 53 | this(new Present<>(scheme), path, new Present<>(query), Absent.absent()); 54 | } 55 | 56 | 57 | public OpaqueUri(Scheme scheme, Path path, Query query, Fragment fragment) 58 | { 59 | this(new Present<>(scheme), path, new Present<>(query), new Present<>(fragment)); 60 | } 61 | 62 | 63 | private OpaqueUri(Optional scheme, Path path, Optional query, Optional fragment) 64 | { 65 | mScheme = scheme; 66 | mPath = path; 67 | mQuery = query; 68 | mFragment = fragment; 69 | } 70 | 71 | 72 | @Override 73 | public Optional scheme() 74 | { 75 | return mScheme; 76 | } 77 | 78 | 79 | @Override 80 | public Optional authority() 81 | { 82 | return absent(); 83 | } 84 | 85 | 86 | @Override 87 | public Path path() 88 | { 89 | return mPath; 90 | } 91 | 92 | 93 | @Override 94 | public Optional query() 95 | { 96 | return mQuery; 97 | } 98 | 99 | 100 | @Override 101 | public Optional fragment() 102 | { 103 | return mFragment; 104 | } 105 | 106 | 107 | @Override 108 | public boolean isHierarchical() 109 | { 110 | return false; 111 | } 112 | 113 | 114 | @Override 115 | public boolean isAbsolute() 116 | { 117 | return true; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/RelativeUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Absent; 21 | import org.dmfs.jems2.optional.Present; 22 | import org.dmfs.rfc3986.*; 23 | import org.dmfs.rfc3986.paths.EmptyPath; 24 | 25 | import static org.dmfs.jems2.optional.Absent.absent; 26 | 27 | 28 | /** 29 | * A simplified relative reference {@link Uri} as per RFC 3986, Section 4.2. A relative {@link 30 | * Uri} has no {@link Scheme}. Since scheme relative references are less common, this class supports only relative references without {@link Scheme} and {@link 31 | * Authority}. To create a scheme relative reference use {@link StructuredUri#StructuredUri(Optional, Optional, Path, Optional, Optional)} and pass {@code 32 | * None.none()} as the {@link Scheme}. 33 | */ 34 | public final class RelativeUri implements Uri 35 | { 36 | private final Path mPath; 37 | private final Optional mQuery; 38 | private final Optional mFragment; 39 | 40 | 41 | public RelativeUri(Path path) 42 | { 43 | this(path, Absent.absent(), Absent.absent()); 44 | } 45 | 46 | 47 | public RelativeUri(Query query) 48 | { 49 | this(EmptyPath.INSTANCE, new Present<>(query), Absent.absent()); 50 | } 51 | 52 | 53 | public RelativeUri(Fragment fragment) 54 | { 55 | this(EmptyPath.INSTANCE, Absent.absent(), new Present<>(fragment)); 56 | } 57 | 58 | 59 | public RelativeUri(Path path, Query query) 60 | { 61 | this(path, new Present<>(query), Absent.absent()); 62 | } 63 | 64 | 65 | public RelativeUri(Query query, Fragment fragment) 66 | { 67 | this(EmptyPath.INSTANCE, new Present<>(query), new Present<>(fragment)); 68 | } 69 | 70 | 71 | public RelativeUri(Path path, Query query, Fragment fragment) 72 | { 73 | this(path, new Present<>(query), new Present<>(fragment)); 74 | } 75 | 76 | 77 | public RelativeUri(Path path, Optional query, Optional fragment) 78 | { 79 | mPath = path; 80 | mQuery = query; 81 | mFragment = fragment; 82 | } 83 | 84 | 85 | @Override 86 | public Optional scheme() 87 | { 88 | return absent(); 89 | } 90 | 91 | 92 | @Override 93 | public Optional authority() 94 | { 95 | return absent(); 96 | } 97 | 98 | 99 | @Override 100 | public Path path() 101 | { 102 | return mPath; 103 | } 104 | 105 | 106 | @Override 107 | public Optional query() 108 | { 109 | return mQuery; 110 | } 111 | 112 | 113 | @Override 114 | public Optional fragment() 115 | { 116 | return mFragment; 117 | } 118 | 119 | 120 | @Override 121 | public boolean isHierarchical() 122 | { 123 | return true; 124 | } 125 | 126 | 127 | @Override 128 | public boolean isAbsolute() 129 | { 130 | return false; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/Resolved.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.rfc3986.*; 21 | 22 | 23 | /** 24 | * A {@link Uri} decorator that resolves a reference {@link Uri} against the decorated base {@link Uri}. 25 | */ 26 | public final class Resolved implements Uri 27 | { 28 | private final Uri mBase; 29 | private final Uri mReference; 30 | 31 | 32 | public Resolved(Uri base, Uri reference) 33 | { 34 | mBase = base; 35 | mReference = reference; 36 | } 37 | 38 | 39 | @Override 40 | public Optional scheme() 41 | { 42 | return mReference.isAbsolute() ? mReference.scheme() : mBase.scheme(); 43 | } 44 | 45 | 46 | @Override 47 | public Optional authority() 48 | { 49 | return mReference.isAbsolute() || mReference.authority().isPresent() ? mReference.authority() : mBase.authority(); 50 | } 51 | 52 | 53 | @Override 54 | public Path path() 55 | { 56 | return mReference.isAbsolute() || mReference.authority().isPresent() ? 57 | new org.dmfs.rfc3986.paths.Normalized(mReference.path()) : 58 | new org.dmfs.rfc3986.paths.Resolved(mBase.path(), mReference.path()); 59 | } 60 | 61 | 62 | @Override 63 | public Optional query() 64 | { 65 | return mReference.isAbsolute() || 66 | mReference.authority().isPresent() || 67 | !mReference.path().isEmpty() || 68 | mReference.query().isPresent() ? mReference.query() : mBase.query(); 69 | } 70 | 71 | 72 | @Override 73 | public Optional fragment() 74 | { 75 | return mReference.fragment(); 76 | } 77 | 78 | 79 | @Override 80 | public boolean isHierarchical() 81 | { 82 | return mBase.isHierarchical() || mReference.isHierarchical(); 83 | } 84 | 85 | 86 | @Override 87 | public boolean isAbsolute() 88 | { 89 | return mBase.isAbsolute() || mReference.isAbsolute(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/StructuredUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.jems2.optional.Absent; 21 | import org.dmfs.jems2.optional.Present; 22 | import org.dmfs.rfc3986.*; 23 | import org.dmfs.rfc3986.paths.EmptyPath; 24 | 25 | 26 | /** 27 | * A {@link Uri} that's composed of its individual components. 28 | */ 29 | public final class StructuredUri implements Uri 30 | { 31 | private final Optional mScheme; 32 | private final Optional mAuthority; 33 | private final Path mPath; 34 | private final Optional mQuery; 35 | private final Optional mFragment; 36 | 37 | 38 | public StructuredUri(Scheme scheme, Authority authority) 39 | { 40 | this(new Present<>(scheme), new Present<>(authority), EmptyPath.INSTANCE, Absent.absent(), Absent.absent()); 41 | } 42 | 43 | 44 | public StructuredUri(Scheme scheme, Authority authority, Path path) 45 | { 46 | this(new Present<>(scheme), new Present<>(authority), path, Absent.absent(), Absent.absent()); 47 | } 48 | 49 | 50 | public StructuredUri(Scheme scheme, Authority authority, Path path, Query query) 51 | { 52 | this(new Present<>(scheme), new Present<>(authority), path, new Present<>(query), Absent.absent()); 53 | } 54 | 55 | 56 | public StructuredUri(Scheme scheme, Authority authority, Path path, Query query, Fragment fragment) 57 | { 58 | this(new Present<>(scheme), new Present<>(authority), path, new Present<>(query), new Present<>(fragment)); 59 | } 60 | 61 | 62 | private StructuredUri(Optional scheme, Optional authority, Path path, Optional query, Optional fragment) 63 | { 64 | mScheme = scheme; 65 | mAuthority = authority; 66 | mPath = path; 67 | mQuery = query; 68 | mFragment = fragment; 69 | if (authority.isPresent() && !path.isAbsolute() && !path.isEmpty()) 70 | { 71 | throw new IllegalArgumentException("URIs with an authority must have an absolute or empty path."); 72 | } 73 | if (!scheme.isPresent() && !authority.isPresent() && !mPath.isAbsolute() && !path.isEmpty() && path.iterator().next().toString().contains(":")) 74 | { 75 | throw new IllegalArgumentException( 76 | "URIs without scheme and authority must have not have a \":\" in the first path segment unless the path is absolute."); 77 | } 78 | // TODO: do we have more constraints? 79 | } 80 | 81 | 82 | @Override 83 | public Optional scheme() 84 | { 85 | return mScheme; 86 | } 87 | 88 | 89 | @Override 90 | public Optional authority() 91 | { 92 | return mAuthority; 93 | } 94 | 95 | 96 | @Override 97 | public Path path() 98 | { 99 | return mPath; 100 | } 101 | 102 | 103 | @Override 104 | public Optional query() 105 | { 106 | return mQuery; 107 | } 108 | 109 | 110 | @Override 111 | public Optional fragment() 112 | { 113 | return mFragment; 114 | } 115 | 116 | 117 | @Override 118 | public boolean isHierarchical() 119 | { 120 | return !mScheme.isPresent() || mAuthority.isPresent() || mPath.isAbsolute(); 121 | } 122 | 123 | 124 | @Override 125 | public boolean isAbsolute() 126 | { 127 | return mScheme.isPresent(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/uris/Text.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.jems2.Optional; 20 | import org.dmfs.rfc3986.Authority; 21 | import org.dmfs.rfc3986.Fragment; 22 | import org.dmfs.rfc3986.Query; 23 | import org.dmfs.rfc3986.Uri; 24 | 25 | 26 | /** 27 | * Adapter to adapt a {@link Uri} to a {@link CharSequence}. 28 | */ 29 | public final class Text implements CharSequence 30 | { 31 | private final Uri mUri; 32 | private String mString; 33 | 34 | 35 | public Text(Uri uri) 36 | { 37 | mUri = uri; 38 | } 39 | 40 | 41 | @Override 42 | public int length() 43 | { 44 | return toString().length(); 45 | } 46 | 47 | 48 | @Override 49 | public char charAt(int i) 50 | { 51 | return toString().charAt(i); 52 | } 53 | 54 | 55 | @Override 56 | public CharSequence subSequence(int i, int i1) 57 | { 58 | return toString().subSequence(i, i1); 59 | } 60 | 61 | 62 | @Override 63 | public String toString() 64 | { 65 | if (mString == null) 66 | { 67 | StringBuilder stringBuilder = new StringBuilder(128); 68 | if (mUri.scheme().isPresent()) 69 | { 70 | stringBuilder.append(mUri.scheme().value().toString()); 71 | stringBuilder.append(':'); 72 | } 73 | Optional optAuthority = mUri.authority(); 74 | if (optAuthority.isPresent()) 75 | { 76 | stringBuilder.append('/'); 77 | stringBuilder.append('/'); 78 | stringBuilder.append(new org.dmfs.rfc3986.authorities.Text(optAuthority.value())); 79 | } 80 | 81 | // Path is the only component that's always present, although it might be empty 82 | stringBuilder.append(new org.dmfs.rfc3986.paths.Text(mUri.path())); 83 | 84 | Optional optQuery = mUri.query(); 85 | if (optQuery.isPresent()) 86 | { 87 | stringBuilder.append('?'); 88 | stringBuilder.append(optQuery.value()); 89 | } 90 | Optional optFragment = mUri.fragment(); 91 | if (optFragment.isPresent()) 92 | { 93 | stringBuilder.append('#'); 94 | stringBuilder.append(optFragment.value()); 95 | } 96 | mString = stringBuilder.toString(); 97 | } 98 | return mString; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/utils/Parsed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.utils; 18 | 19 | /** 20 | * An component that has been parsed from a URI. 21 | */ 22 | public interface Parsed 23 | { 24 | /** 25 | * The length of the component in the source. 26 | * 27 | * @return 28 | */ 29 | int parsedLength(); 30 | } 31 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/utils/Split.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.utils; 18 | 19 | import org.dmfs.jems2.iterator.BaseIterator; 20 | 21 | import java.nio.file.Path; 22 | import java.util.Iterator; 23 | import java.util.NoSuchElementException; 24 | 25 | 26 | /** 27 | * An {@link Iterator} that iterates the elements of a CharSequence of a comma (or other character) separated value list . 28 | *

29 | * Example: 30 | *

31 | *

 32 |  * 
 33 |  * 	Iterator<CharSequence> i = new Split("a, b,def,123", ',');
 34 |  * 	i.next(); // returns "a"
 35 |  * 	i.next(); // returns " b"
 36 |  * 	i.next(); // returns "def"
 37 |  * 	i.next(); // returns "123"
 38 |  * 	i.hasNext(); // false
 39 |  * 
 40 |  * 
41 | *

42 | * Iterating an empty CharSequence or a CharSequence without (unquoted) separators will return exactly one element. 43 | *

44 | * Example: 45 | *

46 | *

 47 |  * 
 48 |  * 	Iterator<CharSequence> i = new Split("", ',');
 49 |  * 	i.next(); // returns ""
 50 |  * 	i.hasNext(); // false
 51 |  * 
 52 |  * 
53 | *

54 | * TODO: replace with the implementation in Iterators once it has been released 55 | * 56 | * @author Marten Gajda 57 | */ 58 | public final class Split extends BaseIterator 59 | { 60 | private final CharSequence mValue; 61 | private final char mSeparator; 62 | private final int mLimit; 63 | 64 | private int mLastSeparatorPos = -1; 65 | private int mNextSeparatorPos = -1; 66 | private int mSplitCount; 67 | 68 | /** 69 | * Creates an {@link Iterator} that iterates all segments of the given CharSequence which are separated by the given separator. 70 | * 71 | * @param value The CharSequence that contains a list of values. 72 | * @param separator The separator that separates the values. 73 | */ 74 | public Split(CharSequence value, char separator) 75 | { 76 | this(value, separator, Integer.MAX_VALUE); 77 | } 78 | 79 | 80 | /** 81 | * Creates an {@link Iterator} that iterates all segments of the given CharSequence which are separated by the given separator. 82 | * 83 | * @param value The CharSequence that contains a separated list of values. 84 | * @param separator The separator to scan for. 85 | * @param maxSplits The maximum number of splits to perform. The iterator will return at most this number +1 elements (the last iterated element containing the rest 86 | * of the {@link CharSequence}. 87 | */ 88 | public Split(CharSequence value, char separator, int maxSplits) 89 | { 90 | mValue = value; 91 | mSeparator = separator; 92 | mLimit = maxSplits; 93 | } 94 | 95 | 96 | @Override 97 | public boolean hasNext() 98 | { 99 | if (mNextSeparatorPos == -1) 100 | { 101 | findNextSeparator(); 102 | } 103 | return mLastSeparatorPos < mValue.length(); 104 | } 105 | 106 | 107 | @Override 108 | public CharSequence next() 109 | { 110 | if (mLastSeparatorPos >= mValue.length()) 111 | { 112 | throw new NoSuchElementException("Last element has already been iterated."); 113 | } 114 | if (mNextSeparatorPos == -1) 115 | { 116 | findNextSeparator(); 117 | } 118 | CharSequence result = mValue.subSequence(mLastSeparatorPos + 1, mNextSeparatorPos); 119 | findNextSeparator(); 120 | return result; 121 | } 122 | 123 | 124 | /** 125 | * Move {@link #mNextSeparatorPos} to the next (unquoted) separator (or the end of the {@link CharSequence} if no other separator exists in {@link 126 | * #mValue}). 127 | */ 128 | private void findNextSeparator() 129 | { 130 | mLastSeparatorPos = mNextSeparatorPos; 131 | if (mSplitCount >= mLimit) 132 | { 133 | // "fast forward" to the last position of the CharSequence 134 | mNextSeparatorPos = mValue.length(); 135 | return; 136 | } 137 | while (++mNextSeparatorPos < mValue.length()) 138 | { 139 | char c = mValue.charAt(mNextSeparatorPos); 140 | if (c == mSeparator) 141 | { 142 | // count this split 143 | mSplitCount++; 144 | return; 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/validation/BitMapCharSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.validation; 18 | 19 | /** 20 | * A {@link CharSet} that's based on the bits set in a bitmap. 21 | */ 22 | public final class BitMapCharSet implements CharSet 23 | { 24 | private final int[] mBitmap; 25 | private final int mLength; 26 | 27 | 28 | public BitMapCharSet(int... bitmap) 29 | { 30 | mBitmap = bitmap.clone(); 31 | mLength = bitmap.length * 32; 32 | } 33 | 34 | 35 | @Override 36 | public boolean contains(char c) 37 | { 38 | return (c < mLength) && (mBitmap[c >>> 5] & (1 << (c & 0x1F))) != 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/validation/CharSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.validation; 18 | 19 | /** 20 | * The interface of a very simple set of characters. 21 | */ 22 | public interface CharSet 23 | { 24 | /** 25 | * Returns whether this CharSet contains the given character. 26 | * 27 | * @param c 28 | * The character to test. 29 | * 30 | * @return {@code true} if the given character is contained in the set, {@code false} otherwise. 31 | */ 32 | boolean contains(char c); 33 | } 34 | -------------------------------------------------------------------------------- /rfc3986-uri/src/main/java/org/dmfs/rfc3986/validation/Validated.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.validation; 18 | 19 | /** 20 | * A {@link CharSequence} that comes with a guarantee about the characters it contains. 21 | *

22 | * The characters are validated lazily on the first access to any of the methods, not up-front. 23 | */ 24 | public final class Validated implements CharSequence 25 | { 26 | private final CharSequence mDelegate; 27 | private final CharSet mCharSet; 28 | private boolean mValidated; 29 | 30 | 31 | public Validated(CharSequence delegate, CharSet charSet) 32 | { 33 | mDelegate = delegate; 34 | mCharSet = charSet; 35 | } 36 | 37 | 38 | @Override 39 | public int length() 40 | { 41 | validate(); 42 | return mDelegate.length(); 43 | } 44 | 45 | 46 | @Override 47 | public char charAt(int i) 48 | { 49 | validate(); 50 | return mDelegate.charAt(i); 51 | } 52 | 53 | 54 | @Override 55 | public CharSequence subSequence(int i, int i1) 56 | { 57 | validate(); 58 | return mDelegate.subSequence(i, i1); 59 | } 60 | 61 | 62 | @Override 63 | public String toString() 64 | { 65 | validate(); 66 | return mDelegate.toString(); 67 | } 68 | 69 | 70 | private void validate() 71 | { 72 | if (!mValidated) 73 | { 74 | CharSequence delegate = mDelegate; 75 | CharSet charSet = mCharSet; 76 | final int count = delegate.length(); 77 | for (int i = 0; i < count; ++i) 78 | { 79 | if (!charSet.contains(delegate.charAt(i))) 80 | { 81 | throw new IllegalArgumentException(String.format("Illegal char '%c' at position %d in '%s'", delegate.charAt(i), i, delegate.toString())); 82 | } 83 | } 84 | mValidated = true; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/authorities/TextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.authorities; 18 | 19 | import org.dmfs.rfc3986.encoding.Precoded; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | 25 | /** 26 | * @author marten 27 | */ 28 | public class TextTest 29 | { 30 | @Test 31 | public void testLength() throws Exception 32 | { 33 | assertEquals(0, new Text(new StructuredAuthority(new Precoded(""))).length()); 34 | assertEquals(4, new Text(new StructuredAuthority(new Precoded("host"))).length()); 35 | assertEquals(8, new Text(new StructuredAuthority(new Precoded("host"), 123)).length()); 36 | assertEquals(9, new Text(new StructuredAuthority(new Precoded("user"), new Precoded("host"))).length()); 37 | assertEquals(13, new Text(new StructuredAuthority(new Precoded("user"), new Precoded("host"), 123)).length()); 38 | assertEquals(5, new Text(new StructuredAuthority(new Precoded("user"), new Precoded(""))).length()); 39 | assertEquals(4, new Text(new StructuredAuthority(new Precoded(""), 123)).length()); 40 | assertEquals(9, new Text(new StructuredAuthority(new Precoded("user"), new Precoded(""), 123)).length()); 41 | } 42 | 43 | @Test 44 | public void testNormalized() throws Exception 45 | { 46 | assertEquals("user@host:123", new Text(new StructuredAuthority(new Precoded("user"), new Precoded("host"), 123)).normalized().toString()); 47 | assertEquals("user%40host@host:123", 48 | new Text(new StructuredAuthority(new Precoded("%75%73%65%72%40%68%6F%73%74"), new Precoded("%68%6F%73%74"), 123)).normalized().toString()); 49 | } 50 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/encoding/EncodedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class EncodedTest 27 | { 28 | 29 | @Test 30 | public void testToString() throws Exception 31 | { 32 | assertEquals("", new Encoded("").toString()); 33 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 34 | new Encoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toString()); 35 | assertEquals(".-_~", new Encoded(".-_~").toString()); 36 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 37 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 38 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 39 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20", 40 | new Encoded("%/\"&=ÜÖÄa¹²³¼½¬@æſðđŋħłł€¶ŧ←↓→øþ«¢„“”µ…·âôêàèòùâ ").toString()); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/encoding/FormEncodedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class FormEncodedTest 27 | { 28 | 29 | @Test 30 | public void testToString() throws Exception 31 | { 32 | assertEquals("", new FormEncoded("").toString()); 33 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 34 | new FormEncoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toString()); 35 | assertEquals(".-_~", new FormEncoded(".-_~").toString()); 36 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 37 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 38 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 39 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2+", 40 | new FormEncoded("%/\"&=ÜÖÄa¹²³¼½¬@æſðđŋħłł€¶ŧ←↓→øþ«¢„“”µ…·âôêàèòùâ ").toString()); 41 | assertEquals("%2B+%0D%0A", new FormEncoded("+ \n").toString()); 42 | assertEquals("%2B+%0D%0A", new FormEncoded("+ \r\n").toString()); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/encoding/FormPrecodedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class FormPrecodedTest 27 | { 28 | @Test 29 | public void normalized() throws Exception 30 | { 31 | assertEquals("", new FormPrecoded("").normalized().toString()); 32 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 33 | new FormPrecoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").normalized().toString()); 34 | assertEquals(".-_~", new FormPrecoded(".-_~").normalized().toString()); 35 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 36 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 37 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 38 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+", 39 | new FormPrecoded("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 40 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 41 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 42 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+").normalized().toString()); 43 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 44 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 45 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 46 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+ab0", 47 | new FormPrecoded("%25%2f%22%26%3D%c3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 48 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%ac%C2%B6%C5" + 49 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 50 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%c3%A0%C3%A8%C3%b2%C3%b9%c3%a2%20+%61%62%30").normalized().toString()); 51 | } 52 | 53 | 54 | @Test 55 | public void testToString() throws Exception 56 | { 57 | assertEquals("", new FormPrecoded("").decoded()); 58 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 59 | new FormPrecoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").decoded()); 60 | assertEquals(".-_~", new FormPrecoded(".-_~").decoded()); 61 | assertEquals("%/\"&=ÜÖÄa¹²³¼½¬@æſðđŋħłł€¶ŧ←↓→øþ«¢„“”µ…·âôêàèòùâ ", 62 | new FormPrecoded("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 63 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 64 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 65 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+").decoded()); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/encoding/NormalizedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class NormalizedTest 27 | { 28 | @Test 29 | public void testToString() throws Exception 30 | { 31 | assertEquals("", new Normalized(new Precoded("")).normalized().toString()); 32 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 33 | new Precoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").normalized().toString()); 34 | assertEquals(".-_~", new Normalized(new Precoded(".-_~")).normalized().toString()); 35 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 36 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 37 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 38 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+", 39 | new Normalized(new Precoded("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 40 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 41 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 42 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+")).toString()); 43 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 44 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 45 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 46 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+ab0", 47 | new Normalized(new Precoded("%25%2f%22%26%3D%c3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 48 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%ac%C2%B6%C5" + 49 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 50 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%c3%A0%C3%A8%C3%b2%C3%b9%c3%a2%20+%61%62%30")).toString()); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/encoding/PrecodedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.encoding; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class PrecodedTest 27 | { 28 | 29 | @Test 30 | public void subSequence() throws Exception 31 | { 32 | assertEquals(new Precoded("123"), new Precoded("abc123xyz").subSequence(3, 6)); 33 | assertEquals("123", new Precoded("abc123xyz").subSequence(3, 6).toString()); 34 | } 35 | 36 | 37 | @Test 38 | public void normalized() throws Exception 39 | { 40 | assertEquals("", new Precoded("").normalized().toString()); 41 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 42 | new Precoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").normalized().toString()); 43 | assertEquals(".-_~", new Precoded(".-_~").normalized().toString()); 44 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 45 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 46 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 47 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+", 48 | new Precoded("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 49 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 50 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 51 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+").normalized().toString()); 52 | assertEquals("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 53 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 54 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 55 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+ab0", 56 | new Precoded("%25%2f%22%26%3D%c3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 57 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%ac%C2%B6%C5" + 58 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 59 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%c3%A0%C3%A8%C3%b2%C3%b9%c3%a2%20+%61%62%30").normalized().toString()); 60 | } 61 | 62 | 63 | @Test 64 | public void testDecoded() throws Exception 65 | { 66 | assertEquals("", new Precoded("").decoded()); 67 | assertEquals("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 68 | new Precoded("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").decoded()); 69 | assertEquals(".-_~", new Precoded(".-_~").decoded()); 70 | assertEquals("%/\"&=ÜÖÄa¹²³¼½¬@æſðđŋħłł€¶ŧ←↓→øþ«¢„“”µ…·âôêàèòùâ +", 71 | new Precoded("%25%2F%22%26%3D%C3%9C%C3%96%C3%84a%C2%B9%C2%B2%C2%B3%C2%BC%C2%BD%C2%AC%40" + 72 | "%C3%A6%C5%BF%C3%B0%C4%91%C5%8B%C4%A7%C5%82%C5%82%E2%82%AC%C2%B6%C5" + 73 | "%A7%E2%86%90%E2%86%93%E2%86%92%C3%B8%C3%BE%C2%AB%C2%A2%E2%80%9E%E2" + 74 | "%80%9C%E2%80%9D%C2%B5%E2%80%A6%C2%B7%C3%A2%C3%B4%C3%AA%C3%A0%C3%A8%C3%B2%C3%B9%C3%A2%20+").decoded()); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/parameters/parameters/UrlEncodedParameterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.parameters; 18 | 19 | import org.dmfs.rfc3986.encoding.Precoded; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | 25 | /** 26 | */ 27 | public class UrlEncodedParameterTest 28 | { 29 | 30 | @Test 31 | public void name() throws Exception 32 | { 33 | assertEquals("test", new UrlEncodedParameter(new Precoded("test")).name().toString()); 34 | assertEquals("testa", new UrlEncodedParameter(new Precoded("test%61")).name().toString()); 35 | assertEquals("test=", new UrlEncodedParameter(new Precoded("test%3D")).name().toString()); 36 | assertEquals("test", new UrlEncodedParameter(new Precoded("test=123")).name().toString()); 37 | assertEquals("testa", new UrlEncodedParameter(new Precoded("test%61=123%34")).name().toString()); 38 | assertEquals("test=", new UrlEncodedParameter(new Precoded("test%3D=123%3D")).name().toString()); 39 | } 40 | 41 | 42 | @Test 43 | public void textValue() throws Exception 44 | { 45 | assertEquals("", new UrlEncodedParameter(new Precoded("test")).textValue().toString()); 46 | assertEquals("", new UrlEncodedParameter(new Precoded("test%61")).textValue().toString()); 47 | assertEquals("", new UrlEncodedParameter(new Precoded("test%3D")).textValue().toString()); 48 | assertEquals("123", new UrlEncodedParameter(new Precoded("test=123")).textValue().toString()); 49 | assertEquals("1234", new UrlEncodedParameter(new Precoded("test%61=123%34")).textValue().toString()); 50 | assertEquals("123=", new UrlEncodedParameter(new Precoded("test%3D=123%3D")).textValue().toString()); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/parameters/valuetypes/TextValueTypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.parameters.valuetypes; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class TextValueTypeTest 27 | { 28 | @Test 29 | public void testParsedValue() throws Exception 30 | { 31 | assertEquals("", TextValueType.INSTANCE.parsedValue("")); 32 | assertEquals("abc", TextValueType.INSTANCE.parsedValue("abc")); 33 | } 34 | 35 | 36 | @Test 37 | public void testSerializedValue() throws Exception 38 | { 39 | assertEquals("", TextValueType.INSTANCE.serializedValue("")); 40 | assertEquals("abc", TextValueType.INSTANCE.serializedValue("abc")); 41 | } 42 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/paths/EmptyPathTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | 25 | /** 26 | */ 27 | public class EmptyPathTest 28 | { 29 | @Test 30 | public void isEmpty() throws Exception 31 | { 32 | assertTrue(new EmptyPath().isEmpty()); 33 | } 34 | 35 | 36 | @Test 37 | public void isAbsolute() throws Exception 38 | { 39 | assertFalse(new EmptyPath().isAbsolute()); 40 | } 41 | 42 | 43 | @Test 44 | public void iterator() throws Exception 45 | { 46 | assertFalse(new EmptyPath().iterator().hasNext()); 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/paths/StructuredPathTest.java: -------------------------------------------------------------------------------- 1 | package org.dmfs.rfc3986.paths; 2 | 3 | import org.dmfs.rfc3986.encoding.Encoded; 4 | import org.dmfs.rfc3986.encoding.IdempotentEncoded; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertFalse; 8 | import static org.junit.jupiter.api.Assertions.assertTrue; 9 | import static org.saynotobugs.confidence.Assertion.assertThat; 10 | import static org.saynotobugs.confidence.core.quality.Iterable.emptyIterable; 11 | import static org.saynotobugs.confidence.core.quality.Iterable.iterates; 12 | 13 | 14 | /** 15 | */ 16 | public class StructuredPathTest 17 | { 18 | @Test 19 | public void testIsEmpty() throws Exception 20 | { 21 | assertTrue(new StructuredPath().isEmpty()); 22 | assertFalse(new StructuredPath(IdempotentEncoded.CURRENT).isEmpty()); 23 | assertFalse(new StructuredPath(new Encoded("abc")).isEmpty()); 24 | assertFalse(new StructuredPath(new Encoded("abc"), new Encoded("123")).isEmpty()); 25 | } 26 | 27 | 28 | @Test 29 | public void testIsAbsolute() throws Exception 30 | { 31 | assertFalse(new StructuredPath().isAbsolute()); 32 | assertFalse(new StructuredPath(IdempotentEncoded.CURRENT).isAbsolute()); 33 | assertFalse(new StructuredPath(new Encoded("abc")).isAbsolute()); 34 | assertFalse(new StructuredPath(new Encoded("abc"), new Encoded("123")).isAbsolute()); 35 | } 36 | 37 | 38 | @Test 39 | public void testIterator() throws Exception 40 | { 41 | assertThat(new StructuredPath(), emptyIterable()); 42 | assertThat(new StructuredPath(IdempotentEncoded.EMPTY), iterates(IdempotentEncoded.EMPTY)); 43 | assertThat(new StructuredPath(IdempotentEncoded.CURRENT), iterates(IdempotentEncoded.CURRENT)); 44 | assertThat(new StructuredPath(IdempotentEncoded.PARENT), iterates(IdempotentEncoded.PARENT)); 45 | assertThat(new StructuredPath(IdempotentEncoded.PARENT, IdempotentEncoded.PARENT), 46 | iterates(IdempotentEncoded.PARENT, IdempotentEncoded.PARENT)); 47 | assertThat(new StructuredPath(IdempotentEncoded.EMPTY, new Encoded("a"), new Encoded("b")), 48 | iterates(IdempotentEncoded.EMPTY, new Encoded("a"), new Encoded("b"))); 49 | assertThat(new StructuredPath(IdempotentEncoded.CURRENT, new Encoded("a"), new Encoded("b")), 50 | iterates(IdempotentEncoded.CURRENT, new Encoded("a"), new Encoded("b"))); 51 | assertThat(new StructuredPath(IdempotentEncoded.PARENT, new Encoded("a"), new Encoded("b")), 52 | iterates(IdempotentEncoded.PARENT, new Encoded("a"), new Encoded("b"))); 53 | } 54 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/paths/TextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.paths; 18 | 19 | import org.dmfs.rfc3986.encoding.Precoded; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | 25 | /** 26 | * @author Marten Gajda 27 | */ 28 | public class TextTest 29 | { 30 | @Test 31 | public void testLength() throws Exception 32 | { 33 | assertEquals(0, new Text(new EncodedPath(new Precoded(""))).length()); 34 | assertEquals(1, new Text(new EncodedPath(new Precoded("/"))).length()); 35 | assertEquals(3, new Text(new EncodedPath(new Precoded("abc"))).length()); 36 | assertEquals(7, new Text(new EncodedPath(new Precoded("abc/def"))).length()); 37 | assertEquals(12, new Text(new EncodedPath(new Precoded("../abc/./def"))).length()); 38 | } 39 | 40 | 41 | @Test 42 | public void testCharAt() throws Exception 43 | { 44 | assertEquals('/', new Text(new EncodedPath(new Precoded("/"))).charAt(0)); 45 | assertEquals('a', new Text(new EncodedPath(new Precoded("abc"))).charAt(0)); 46 | assertEquals('b', new Text(new EncodedPath(new Precoded("abc"))).charAt(1)); 47 | assertEquals('c', new Text(new EncodedPath(new Precoded("abc"))).charAt(2)); 48 | assertEquals('a', new Text(new EncodedPath(new Precoded("abc/def"))).charAt(0)); 49 | assertEquals('/', new Text(new EncodedPath(new Precoded("abc/def"))).charAt(3)); 50 | assertEquals('f', new Text(new EncodedPath(new Precoded("abc/def"))).charAt(6)); 51 | assertEquals('.', new Text(new EncodedPath(new Precoded("../abc/./def"))).charAt(0)); 52 | assertEquals('/', new Text(new EncodedPath(new Precoded("../abc/./def"))).charAt(6)); 53 | assertEquals('f', new Text(new EncodedPath(new Precoded("../abc/./def"))).charAt(11)); 54 | } 55 | 56 | 57 | @Test 58 | public void testSubSequence() throws Exception 59 | { 60 | assertEquals("", new Text(new EncodedPath(new Precoded(""))).subSequence(0, 0).toString()); 61 | assertEquals("/", new Text(new EncodedPath(new Precoded("/"))).subSequence(0, 1).toString()); 62 | assertEquals("b", new Text(new EncodedPath(new Precoded("abc"))).subSequence(1, 2).toString()); 63 | assertEquals("c/d", new Text(new EncodedPath(new Precoded("abc/def"))).subSequence(2, 5).toString()); 64 | assertEquals("bc/./d", new Text(new EncodedPath(new Precoded("../abc/./def"))).subSequence(4, 10).toString()); 65 | } 66 | 67 | 68 | @Test 69 | public void testToString() throws Exception 70 | { 71 | assertEquals("", new Text(new EncodedPath(new Precoded(""))).toString()); 72 | assertEquals("/", new Text(new EncodedPath(new Precoded("/"))).toString()); 73 | assertEquals("abc", new Text(new EncodedPath(new Precoded("abc"))).toString()); 74 | assertEquals("abc/def", new Text(new EncodedPath(new Precoded("abc/def"))).toString()); 75 | assertEquals("../abc/./def", new Text(new EncodedPath(new Precoded("../abc/./def"))).toString()); 76 | } 77 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/schemes/OptionalLazySchemeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.dmfs.rfc3986.encoding.Precoded; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import java.util.NoSuchElementException; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | import static org.saynotobugs.confidence.Assertion.assertThat; 26 | import static org.saynotobugs.confidence.core.quality.Grammar.is; 27 | import static org.saynotobugs.confidence.core.quality.Object.throwing; 28 | 29 | 30 | /** 31 | * 32 | */ 33 | public class OptionalLazySchemeTest 34 | { 35 | @Test 36 | public void isPresent() throws Exception 37 | { 38 | assertTrue(new OptionalLazyScheme(new Precoded("http://example.com")).isPresent()); 39 | assertTrue(new OptionalLazyScheme(new Precoded("http://example.com:123")).isPresent()); 40 | assertTrue(new OptionalLazyScheme(new Precoded("mailto:test@exampe.com")).isPresent()); 41 | assertTrue(new OptionalLazyScheme(new Precoded("example.com:123")).isPresent()); 42 | assertFalse(new OptionalLazyScheme(new Precoded("//example.com:123")).isPresent()); 43 | assertFalse(new OptionalLazyScheme(new Precoded("")).isPresent()); 44 | assertFalse(new OptionalLazyScheme(new Precoded(":")).isPresent()); 45 | assertFalse(new OptionalLazyScheme(new Precoded("123abc:")).isPresent()); 46 | assertFalse(new OptionalLazyScheme(new Precoded("test@example.com:123")).isPresent()); 47 | } 48 | 49 | 50 | @Test 51 | public void value() throws Exception 52 | { 53 | assertEquals("http", new OptionalLazyScheme(new Precoded("http://example.com")).value().toString()); 54 | assertEquals("http", new OptionalLazyScheme(new Precoded("http://example.com:123")).value().toString()); 55 | assertEquals("mailto", new OptionalLazyScheme(new Precoded("mailto:test@exampe.com")).value().toString()); 56 | assertEquals("example.com", new OptionalLazyScheme(new Precoded("example.com:123")).value().toString()); 57 | } 58 | 59 | 60 | @Test 61 | public void valueFail1() throws Exception 62 | { 63 | assertThat(new OptionalLazyScheme(new Precoded("//example.com:123"))::value, is(throwing(NoSuchElementException.class))); 64 | } 65 | 66 | 67 | @Test 68 | public void valueFail2() throws Exception 69 | { 70 | assertThat(new OptionalLazyScheme(new Precoded(""))::value, is(throwing(NoSuchElementException.class))); 71 | } 72 | 73 | 74 | @Test 75 | public void valueFail3() throws Exception 76 | { 77 | assertThat(new OptionalLazyScheme(new Precoded("test@example.com:123"))::value, is(throwing(NoSuchElementException.class))); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/schemes/SchemesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | 24 | /** 25 | */ 26 | public class SchemesTest 27 | { 28 | @Test 29 | public void testSchemes() 30 | { 31 | assertEquals("ftp", Schemes.FTP.toString()); 32 | assertEquals("http", Schemes.HTTP.toString()); 33 | assertEquals("https", Schemes.HTTPS.toString()); 34 | assertEquals("mailto", Schemes.MAILTO.toString()); 35 | } 36 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/schemes/StringSchemeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.schemes; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.saynotobugs.confidence.Assertion.assertThat; 23 | import static org.saynotobugs.confidence.core.quality.Grammar.is; 24 | import static org.saynotobugs.confidence.core.quality.Object.throwing; 25 | 26 | 27 | /** 28 | * 29 | */ 30 | public class StringSchemeTest 31 | { 32 | @Test 33 | public void testLength() throws Exception 34 | { 35 | assertEquals(4, new StringScheme("http").length()); 36 | } 37 | 38 | 39 | @Test 40 | public void testCharAt() throws Exception 41 | { 42 | assertEquals('h', new StringScheme("http").charAt(0)); 43 | assertEquals('t', new StringScheme("http").charAt(1)); 44 | assertEquals('t', new StringScheme("http").charAt(2)); 45 | assertEquals('p', new StringScheme("http").charAt(3)); 46 | } 47 | 48 | 49 | @Test 50 | public void testSubSequence() throws Exception 51 | { 52 | assertEquals("tt", new StringScheme("http").subSequence(1, 3).toString()); 53 | } 54 | 55 | 56 | @Test 57 | public void testToString() throws Exception 58 | { 59 | assertEquals("http", new StringScheme("http").toString()); 60 | } 61 | 62 | 63 | @Test 64 | public void testLengthIllegalChar() throws Exception 65 | { 66 | assertThat(() -> new StringScheme("http_").length(), is(throwing(IllegalArgumentException.class))); 67 | } 68 | 69 | 70 | @Test 71 | public void testCharAtIllegalChar() throws Exception 72 | { 73 | assertThat(() -> new StringScheme("http_").charAt(0), is(throwing(IllegalArgumentException.class))); 74 | } 75 | 76 | 77 | @Test 78 | public void testSubSequenceIllegalChar() throws Exception 79 | { 80 | assertThat(() -> new StringScheme("http_").subSequence(1, 2), is(throwing(IllegalArgumentException.class))); 81 | } 82 | 83 | 84 | @Test 85 | public void testToStringIllegalChar() throws Exception 86 | { 87 | assertThat(() -> new StringScheme("http_").toString(), is(throwing(IllegalArgumentException.class))); 88 | } 89 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/uris/Bench.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.rfc3986.Uri; 20 | import org.dmfs.rfc3986.encoding.Precoded; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import java.net.URI; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | 28 | /** 29 | */ 30 | public final class Bench 31 | { 32 | @Test 33 | public void bench() throws InterruptedException 34 | { 35 | String uriStr = "http://www.example.com/my/path/to/file.txt?q=search&filter=none#field1=set&field2=clear"; 36 | run(new JavaUriBench(), uriStr); 37 | run(new OurUriBench(), uriStr); 38 | run(new JavaUriBench(), uriStr); 39 | run(new OurUriBench(), uriStr); 40 | run(new JavaUriBench(), uriStr); 41 | run(new OurUriBench(), uriStr); 42 | } 43 | 44 | 45 | private void run(Benchmark b, String uriString) throws InterruptedException 46 | { 47 | List list = new ArrayList<>(10000); 48 | Runtime rt = Runtime.getRuntime(); 49 | System.gc(); 50 | Thread.sleep(1000); 51 | long total = rt.totalMemory(); 52 | long max = rt.maxMemory(); 53 | long free = rt.freeMemory(); 54 | long start = System.currentTimeMillis(); 55 | 56 | b.bench(list, 10000, uriString); 57 | 58 | int count = list.size(); 59 | start -= System.currentTimeMillis(); 60 | total -= rt.totalMemory(); 61 | max -= rt.maxMemory(); 62 | free -= rt.freeMemory(); 63 | 64 | System.out.println( 65 | String.format("Class %50s, count: %10d, dtotal %10d, dmax %10d, dfree %10d, dtime %5d, bytesperuri %5d", b.getClass().getCanonicalName(), count, 66 | -total, -max, 67 | -free, -start, free / count)); 68 | System.gc(); 69 | Thread.sleep(1000); 70 | } 71 | 72 | 73 | private interface Benchmark 74 | { 75 | void bench(List results, int count, String uriStr); 76 | } 77 | 78 | 79 | private final static class JavaUriBench implements Benchmark 80 | { 81 | 82 | @Override 83 | public void bench(List results, int count, String uriStr) 84 | { 85 | for (int i = 0; i < count; ++i) 86 | { 87 | results.add(URI.create(uriStr)); 88 | } 89 | } 90 | } 91 | 92 | 93 | private final static class OurUriBench implements Benchmark 94 | { 95 | 96 | @Override 97 | public void bench(List results, int count, String uriStr) 98 | { 99 | for (int i = 0; i < count; ++i) 100 | { 101 | Uri uri = new LazyUri(new Precoded(uriStr)); 102 | results.add(uri); 103 | uri.fragment().isPresent(); 104 | } 105 | } 106 | } 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/uris/EmptyUriTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | 25 | /** 26 | */ 27 | public class EmptyUriTest 28 | { 29 | @Test 30 | public void testScheme() throws Exception 31 | { 32 | assertFalse(new EmptyUri().scheme().isPresent()); 33 | } 34 | 35 | 36 | @Test 37 | public void testAuthority() throws Exception 38 | { 39 | assertFalse(new EmptyUri().authority().isPresent()); 40 | } 41 | 42 | 43 | @Test 44 | public void testPath() throws Exception 45 | { 46 | assertTrue(new EmptyUri().path().isEmpty()); 47 | } 48 | 49 | 50 | @Test 51 | public void testQuery() throws Exception 52 | { 53 | assertFalse(new EmptyUri().query().isPresent()); 54 | } 55 | 56 | 57 | @Test 58 | public void testFragment() throws Exception 59 | { 60 | assertFalse(new EmptyUri().fragment().isPresent()); 61 | } 62 | 63 | 64 | @Test 65 | public void testIsHierarchical() throws Exception 66 | { 67 | assertFalse(new EmptyUri().isHierarchical()); 68 | } 69 | 70 | 71 | @Test 72 | public void testIsAbsolute() throws Exception 73 | { 74 | assertFalse(new EmptyUri().isAbsolute()); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/uris/TextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.uris; 18 | 19 | import org.dmfs.rfc3986.authorities.EncodedAuthority; 20 | import org.dmfs.rfc3986.encoding.Precoded; 21 | import org.dmfs.rfc3986.fragments.SimpleFragment; 22 | import org.dmfs.rfc3986.paths.EncodedPath; 23 | import org.dmfs.rfc3986.queries.SimpleQuery; 24 | import org.dmfs.rfc3986.schemes.StringScheme; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | 30 | /** 31 | */ 32 | public class TextTest 33 | { 34 | @Test 35 | public void testToString() throws Exception 36 | { 37 | assertEquals("http://example.com/test?x=y#123", new Text( 38 | new StructuredUri(new StringScheme("http"), new EncodedAuthority(new Precoded("example.com")), new EncodedPath(new Precoded("/test")), 39 | new SimpleQuery(new Precoded("x=y")), 40 | new SimpleFragment(new Precoded("123")))).toString()); 41 | assertEquals("http://example.com/test?x=y", new Text( 42 | new StructuredUri(new StringScheme("http"), new EncodedAuthority(new Precoded("example.com")), new EncodedPath(new Precoded("/test")), 43 | new SimpleQuery(new Precoded("x=y")))).toString()); 44 | assertEquals("/test?x=y", new Text( 45 | new RelativeUri(new EncodedPath(new Precoded("/test")), new SimpleQuery(new Precoded("x=y")))).toString()); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /rfc3986-uri/src/test/java/org/dmfs/rfc3986/validation/BitMapCharSetTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc3986.validation; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | 25 | /** 26 | */ 27 | public class BitMapCharSetTest 28 | { 29 | @Test 30 | public void testContains() throws Exception 31 | { 32 | assertFalse(new BitMapCharSet().contains(' ')); 33 | assertFalse(new BitMapCharSet(0).contains(' ')); 34 | assertFalse(new BitMapCharSet(0, 0).contains(' ')); 35 | assertFalse(new BitMapCharSet(0, 0, 0).contains(' ')); 36 | assertTrue(new BitMapCharSet(0, 1).contains(' ')); 37 | assertTrue(new BitMapCharSet(0, 1, 0).contains(' ')); 38 | assertTrue(new BitMapCharSet(0, 0x80000000).contains((char) 63)); 39 | assertTrue(new BitMapCharSet(0, 0x80000000, 0).contains((char) 63)); 40 | assertFalse(new BitMapCharSet(0, 0x80000000, 0).contains((char) 62)); 41 | assertFalse(new BitMapCharSet(0, 0x80000000, 0).contains((char) 64)); 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /rfc6570-uri-templates/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | } 4 | 5 | apply from: '../jacoco.gradle' 6 | apply from: '../publish.gradle' 7 | 8 | sourceCompatibility = JavaVersion.VERSION_1_8 9 | targetCompatibility = JavaVersion.VERSION_1_8 10 | 11 | dependencies { 12 | implementation project(":rfc3986-uri") 13 | testImplementation libs.jems2.testing 14 | testImplementation libs.junit.jupiter.api 15 | testRuntimeOnly libs.junit.jupiter.engine 16 | } 17 | -------------------------------------------------------------------------------- /rfc6570-uri-templates/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_DESCRIPTION=RFC 6570 compliant URI template implementation. -------------------------------------------------------------------------------- /rfc6570-uri-templates/src/main/java/org/dmfs/rfc6570/UriTemplate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 dmfs GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.dmfs.rfc6570; 18 | 19 | import org.dmfs.rfc3986.Uri; 20 | 21 | import java.util.Map; 22 | 23 | 24 | /** 25 | */ 26 | public interface UriTemplate 27 | { 28 | UriTemplate expandedTemplate(Map context); 29 | 30 | Uri expanded(Map context); 31 | } 32 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'uri-toolkit' 2 | include 'rfc3986-uri' 3 | include 'rfc6570-uri-templates' 4 | 5 | --------------------------------------------------------------------------------