From c5d504ba65b79a57a5f4dd041e73493bf0a74b50 Mon Sep 17 00:00:00 2001
From: Thierry Boileau
Date: Fri, 23 Jan 2026 14:14:20 +0100
Subject: [PATCH 1/2] init
---
org.restlet.gwt/org.restlet.gwt/pom.xml | 1 -
org.restlet.java/org.restlet.test/pom.xml | 2 -
.../restlet/test/data/ReferenceTestCase.java | 2 +-
org.restlet.java/org.restlet/pom.xml | 6 +-
.../src/main/java/org/restlet/Request.java | 6 +-
.../main/java/org/restlet/data/Reference.java | 262 ++++++++++++------
.../java/org/restlet/data/ReferenceTest.java | 41 +++
pom.xml | 22 +-
8 files changed, 233 insertions(+), 109 deletions(-)
create mode 100644 org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
diff --git a/org.restlet.gwt/org.restlet.gwt/pom.xml b/org.restlet.gwt/org.restlet.gwt/pom.xml
index 6a94bead49..514c298e7d 100644
--- a/org.restlet.gwt/org.restlet.gwt/pom.xml
+++ b/org.restlet.gwt/org.restlet.gwt/pom.xml
@@ -28,7 +28,6 @@
org.junit.jupiter
junit-jupiter-api
- ${lib-junit-version}
test
diff --git a/org.restlet.java/org.restlet.test/pom.xml b/org.restlet.java/org.restlet.test/pom.xml
index 9984783f9a..559bb51e16 100644
--- a/org.restlet.java/org.restlet.test/pom.xml
+++ b/org.restlet.java/org.restlet.test/pom.xml
@@ -170,12 +170,10 @@
org.junit.jupiter
junit-jupiter-api
- ${lib-junit-version}
org.junit.jupiter
junit-jupiter-params
- ${lib-junit-version}
compile
diff --git a/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java b/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
index 7aad74d23b..8b99446e9f 100644
--- a/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
+++ b/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
@@ -40,7 +40,7 @@ public class ReferenceTestCase extends RestletTestCase {
protected final static String DEFAULT_SCHEMEPART = "//";
/**
- * Returns a reference that is initialized with http://restlet.org.
+ * Returns a reference initialized with http://restlet.org.
*
* @return Reference instance.
*/
diff --git a/org.restlet.java/org.restlet/pom.xml b/org.restlet.java/org.restlet/pom.xml
index 981680009f..604b518820 100644
--- a/org.restlet.java/org.restlet/pom.xml
+++ b/org.restlet.java/org.restlet/pom.xml
@@ -25,7 +25,11 @@
org.junit.jupiter
junit-jupiter-api
- ${lib-junit-version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
test
diff --git a/org.restlet.java/org.restlet/src/main/java/org/restlet/Request.java b/org.restlet.java/org.restlet/src/main/java/org/restlet/Request.java
index 09d072b7cf..9c1ab14387 100644
--- a/org.restlet.java/org.restlet/src/main/java/org/restlet/Request.java
+++ b/org.restlet.java/org.restlet/src/main/java/org/restlet/Request.java
@@ -753,7 +753,7 @@ public void setHostRef(Reference hostRef) {
}
/**
- * Sets the host reference using an URI string. Note that when used with HTTP
+ * Sets the host reference using a URI string. Note that when used with HTTP
* connectors, this property maps to the "Host" header.
*
* @param hostUri The host URI.
@@ -866,7 +866,7 @@ public void setReferrerRef(Reference referrerRef) {
}
/**
- * Sets the referrer reference if available using an URI string. Note that when
+ * Sets the referrer reference if available using a URI string. Note that when
* used with HTTP connectors, this property maps to the "Referer" header.
*
* @param referrerUri The referrer URI.
@@ -890,7 +890,7 @@ public void setResourceRef(Reference resourceRef) {
}
/**
- * Sets the target resource reference using an URI string. Note that the URI can
+ * Sets the target resource reference using a URI string. Note that the URI can
* be either absolute or relative to the context's base reference.
*
* @param resourceUri The resource URI.
diff --git a/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java b/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
index d1d0132c28..498df4cafd 100644
--- a/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
+++ b/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
@@ -19,7 +19,7 @@
/**
* Reference to a Uniform Resource Identifier (URI). Contrary to the
* java.net.URI class, this interface represents mutable references. It strictly
- * conforms to the RFC 3986 specifying URIs and follow its naming
+ * conforms to the RFC 3986 specifying URIs and follows its naming
* conventions.
*
*
@@ -49,17 +49,17 @@
* the character will be automatically encoded.
*
*
- * The fundamental point to underline is the difference between an URI
- * "reference" and an URI. Contrary to an URI (the target identifier of a REST
- * resource), an URI reference can be relative (with or without query and
+ * The fundamental point to underline is the difference between a URI
+ * "reference" and a URI. Contrary to a URI (the target identifier of a REST
+ * resource), a URI reference can be relative (with or without a query and
* fragment part). This relative URI reference can then be resolved against a
* base reference via the getTargetRef() method which will return a new resolved
* Reference instance, an absolute URI reference with no base reference and with
* no dot-segments (the path segments "." and "..").
*
*
- * You can also apply the getTargetRef() method on absolute references in order
- * to solve the dot-segments. Note that applying the getRelativeRef() method on
+ * You can also apply the getTargetRef() method on absolute references to solve
+ * the dot-segments. Note that applying the getRelativeRef() method on
* an absolute reference returns the current reference relatively to a base
* reference, if any, and solves the dot-segments.
*
@@ -71,10 +71,10 @@
*
*
* When you modify a specific component of the URI reference, via the setPath()
- * method for example, the internal string is simply regenerated by updating
+ * method, for example, the internal string is simply regenerated by updating
* only the relevant part. We try as much as possible to protect the bytes given
* to the Reference class instead of transparently parsing and normalizing the
- * URI data. Our idea is to protect encodings and special characters in all case
+ * URI data. Our idea is to protect encodings and special characters in all cases
* and reduce the memory size taken by this class while making Reference
* instances mutable.
*
@@ -87,11 +87,11 @@
*
*
* The base ref is not automatically resolved or "merged" with the rest of the
- * reference information (the path here). For example, this let's you reuse a
+ * reference information (the path here). For example, this lets you reuse a
* single reference as the base of several relative references. If you modify
* the base reference, all relative references are still accurate.
*
- * Note that the name and value properties are thread safe, stored in volatile
+ * Note that the name and value properties are thread-safe, stored in volatile
* members.
*
* @author Jerome Louvel
@@ -139,7 +139,7 @@ public static String decode(String toDecode, CharacterSet characterSet) {
try {
result = (characterSet == null) ? toDecode : java.net.URLDecoder.decode(toDecode, characterSet.getName());
} catch (UnsupportedEncodingException uee) {
- Context.getCurrentLogger().log(Level.WARNING, "Unable to decode the string with the UTF-8 character set.",
+ Context.getCurrentLogger().log(Level.WARNING, "Unable to decode the string with the " + characterSet.getName() + " character set.",
uee);
}
@@ -160,11 +160,11 @@ public static String encode(String toEncode) {
/**
* Encodes a given string using the standard URI encoding mechanism and the
* UTF-8 character set. Useful to prevent the usage of '+' to encode spaces (%20
- * instead). The '*' characters are encoded as %2A and %7E are replaced by '~'.
+ * instead). The '*' characters are encoded as '%2A', and '%7E' are replaced by '~'.
*
* @param toEncode The string to encode.
* @param queryString True if the string to encode is part of a query string
- * instead of a HTML form post.
+ * instead of an HTML form post.
* @return The encoded string.
*/
public static String encode(String toEncode, boolean queryString) {
@@ -174,11 +174,11 @@ public static String encode(String toEncode, boolean queryString) {
/**
* Encodes a given string using the standard URI encoding mechanism and the
* UTF-8 character set. Useful to prevent the usage of '+' to encode spaces (%20
- * instead). The '*' characters are encoded as %2A and %7E are replaced by '~'.
+ * instead). The '*' characters are encoded as '%2A', and '%7E' are replaced by '~'.
*
* @param toEncode The string to encode.
* @param queryString True if the string to encode is part of a query string
- * instead of a HTML form post.
+ * instead of an HTML form post.
* @param characterSet The supported character encoding.
* @return The encoded string.
*/
@@ -272,10 +272,10 @@ public static boolean isReserved(int character) {
}
/**
- * Indicates if the given character is an URI subcomponent delimiter character.
+ * Indicates if the given character is a URI subcomponent delimiter character.
*
* @param character The character to test.
- * @return True if the given character is an URI subcomponent delimiter
+ * @return True if the given character is a URI subcomponent delimiter
* character.
*/
public static boolean isSubDelimiter(int character) {
@@ -491,7 +491,7 @@ public Reference(Reference ref) {
}
/**
- * Constructor from an URI reference (most likely relative).
+ * Constructor from a URI reference (most likely relative).
*
* @param baseRef The base reference.
* @param uriReference The URI reference, either absolute or relative.
@@ -508,11 +508,93 @@ public Reference(Reference baseRef, Reference uriReference) {
*/
public Reference(Reference baseRef, String uriRef) {
uriRef = encodeInvalidCharacters(uriRef);
+ validateInternalRef(uriRef);
this.baseRef = baseRef;
this.internalRef = uriRef;
updateIndexes();
+
}
+ public void validateInternalRef(String url) {
+ java.util.Map components = new java.util.HashMap<>();
+
+ if (url == null || url.isEmpty()) {
+ throw new IllegalArgumentException("URL cannot be null or empty");
+ }
+
+ String remaining = url;
+
+ // Parse scheme
+ int schemeEnd = remaining.indexOf(':');
+ if (schemeEnd > 0) {
+ components.put("scheme", remaining.substring(0, schemeEnd).toLowerCase());
+ remaining = remaining.substring(schemeEnd + 1);
+ } else {
+ components.put("scheme", null);
+ }
+
+ if (remaining.startsWith("//")) {
+ remaining = remaining.substring(2);
+ int authorityEnd = remaining.indexOf('/');
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.indexOf('?');
+ }
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.indexOf('#');
+ }
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.length();
+ }
+
+ String authority = remaining.substring(0, authorityEnd);
+
+ // Parse host and port
+ // Handle IPv6 addresses [::1]
+ if (authority.startsWith("[")) {
+ int ipv6End = authority.indexOf(']');
+ if (ipv6End != -1) {
+ components.put("hostName", authority.substring(0, ipv6End + 1));
+ if () {
+
+ }
+ if (ipv6End + 1 < authority.length() && authority.charAt(ipv6End + 1) == ':') {
+ components.put("hostPort", authority.substring(ipv6End + 2));
+ } else if (ipv6End + 1 < authority.length()) {
+ throw new IllegalArgumentException("Invalid authority format");
+ } else {
+ components.put("hostPort", null);
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+ } else if (authority.indexOf('[') != -1) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ } else {
+ int atIndex = authority.indexOf('@');
+ if (atIndex != -1) {
+ authority = authority.substring(atIndex + 1);
+ }
+
+ int portIndex = authority.indexOf(':');
+ if (portIndex != -1) {
+ components.put("hostName", authority.substring(0, portIndex));
+ components.put("hostPort", authority.substring(portIndex + 1));
+ } else {
+ components.put("hostName", authority);
+ components.put("hostPort", null);
+ }
+ }
+ }
+
+ if (components.get("hostPort") != null) {
+ try {
+ Integer.parseInt(components.get("hostPort"));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid port number format");
+ }
+ }
+ }
+
/**
* Constructor of relative reference from its parts.
*
@@ -751,7 +833,6 @@ public String getAuthority() {
}
return part.substring(2);
-
}
return null;
@@ -783,7 +864,7 @@ public Reference getBaseRef() {
* part starts after the first '.' character of the last path segment and ends
* with either the end of the segment of with the first ';' character (matrix
* start). It is a token similar to file extensions separated by '.' characters.
- * The value can be ommited.
+ * The value can be omitted.
* Note that no URI decoding is done by this method.
*
* @return The extensions or null.
@@ -856,11 +937,11 @@ public String getFragment(boolean decode) {
}
/**
- * Returns the hierarchical part which is equivalent to the scheme specific part
+ * Returns the hierarchical part which is equivalent to the scheme-specific part
* less the query component.
* Note that no URI decoding is done by this method.
*
- * @return The hierarchical part .
+ * @return The hierarchical part.
*/
public String getHierarchicalPart() {
if (hasScheme()) {
@@ -907,12 +988,12 @@ public String getHierarchicalPart(boolean decode) {
}
/**
- * Returns the host domain name component for server based hierarchical
+ * Returns the host domain name component for server-based hierarchical
* identifiers. It can also be replaced by an IP address when no domain name was
* registered.
* Note that no URI decoding is done by this method.
*
- * @return The host domain name component for server based hierarchical
+ * @return The host domain name component for server-based hierarchical
* identifiers.
*/
public String getHostDomain() {
@@ -970,9 +1051,7 @@ public String getHostDomain(boolean decode) {
* @return The host identifier.
*/
public String getHostIdentifier() {
- final StringBuilder result = new StringBuilder();
- result.append(getScheme()).append("://").append(getAuthority());
- return result.toString();
+ return getScheme() + "://" + getAuthority();
}
/**
@@ -988,9 +1067,9 @@ public String getHostIdentifier(boolean decode) {
}
/**
- * Returns the optional port number for server based hierarchical identifiers.
+ * Returns the optional port number for server-based hierarchical identifiers.
*
- * @return The optional port number for server based hierarchical identifiers or
+ * @return The optional port number for server-based hierarchical identifiers or
* -1 if the port number does not exist.
*/
public int getHostPort() {
@@ -1047,7 +1126,7 @@ public String getIdentifier(boolean decode) {
/**
* Returns the last segment of a hierarchical path.
- * For example the "/a/b/c" and "/a/b/c/" paths have the same segments: "a",
+ * For example, the "/a/b/c" and "/a/b/c/" paths have the same segments: "a",
* "b", "c.
* Note that no URI decoding is done by this method.
*
@@ -1112,7 +1191,7 @@ public String getLastSegment(boolean decode, boolean excludeMatrix) {
* Returns the optional matrix for hierarchical identifiers. A matrix part
* starts after the first ';' character of the last path segment. It is a
* sequence of 'name=value' parameters separated by ';' characters. The value
- * can be ommitted.
+ * can be omitted.
* Note that no URI decoding is done by this method.
*
* @return The matrix or null.
@@ -1176,7 +1255,7 @@ public Reference getParentRef() {
String parentRef = null;
String path = getPath();
- if (!path.equals("/") && !path.equals("")) {
+ if (!path.equals("/") && !path.isEmpty()) {
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
@@ -1197,8 +1276,8 @@ public Reference getParentRef() {
}
/**
- * Returns the path component for hierarchical identifiers. If not path is
- * available it returns null.
+ * Returns the path component for hierarchical identifiers. If no path is
+ * available, it returns null.
* Note that no URI decoding is done by this method.
*
* @return The path component for hierarchical identifiers.
@@ -1244,7 +1323,7 @@ public String getPath() {
}
/**
- * Returns the optionally decoded path component. If not path is available it
+ * Returns the optionally decoded path component. If no path is available, it
* returns null.
*
* @param decode Indicates if the result should be decoded using the
@@ -1267,7 +1346,7 @@ public String getQuery() {
// Query found
if (hasFragment()) {
if (this.queryIndex < this.fragmentIndex) {
- // Fragment found and query sign not inside fragment
+ // Fragment found and query sign not inside the fragment
return this.internalRef.substring(this.queryIndex + 1, this.fragmentIndex);
}
@@ -1366,7 +1445,7 @@ public Reference getRelativeRef() {
* IllegalArgumentException will be raised.
*
* @param base The base reference to use.
- * @throws IllegalArgumentException If the relative reference is computed
+ * @throws IllegalArgumentException If the relative reference is computed,
* although the reference or the base reference
* are not absolute or not hierarchical.
* @return The current reference relatively to a base reference.
@@ -1413,7 +1492,7 @@ public Reference getRelativeRef(Reference base) {
// Both paths are strictly equivalent
relativePath = ".";
} else if (i == localPath.length()) {
- // End of local path reached
+ // End of a local path reached
if (basePath.charAt(i) == '/') {
if ((i + 1) == basePath.length()) {
// Both paths are strictly equivalent
@@ -1441,9 +1520,8 @@ public Reference getRelativeRef(Reference base) {
}
} else {
// The base path has a segment that starts like
- // the last local path segment
- // But that is longer. Situation similar to a
- // junction
+ // the last local path segment, But that is longer.
+ // Situation similar to a junction
final StringBuilder sb = new StringBuilder();
// Count segments
@@ -1460,7 +1538,7 @@ public Reference getRelativeRef(Reference base) {
relativePath = sb.toString();
- if (relativePath.equals("")) {
+ if (relativePath.isEmpty()) {
relativePath = ".";
}
}
@@ -1625,10 +1703,10 @@ public Protocol getSchemeProtocol() {
}
/**
- * Returns the scheme specific part.
+ * Returns the scheme-specific part.
* Note that no URI decoding is done by this method.
*
- * @return The scheme specific part.
+ * @return The scheme-specific part.
*/
public String getSchemeSpecificPart() {
String result = null;
@@ -1648,11 +1726,11 @@ public String getSchemeSpecificPart() {
}
/**
- * Returns the optionally decoded scheme specific part.
+ * Returns the optionally decoded scheme-specific part.
*
* @param decode Indicates if the result should be decoded using the
* {@link #decode(String)} method.
- * @return The optionally decoded scheme specific part.
+ * @return The optionally decoded scheme-specific part.
* @see #getSchemeSpecificPart()
*/
public String getSchemeSpecificPart(boolean decode) {
@@ -1667,7 +1745,7 @@ public String getSchemeSpecificPart(boolean decode) {
* @return The segments of a hierarchical path.
*/
public List getSegments() {
- final List result = new ArrayList();
+ final List result = new ArrayList<>();
final String path = getPath();
int start = -2; // The index of the slash starting the segment
char current;
@@ -1717,9 +1795,7 @@ public List getSegments(boolean decode) {
final List result = getSegments();
if (decode) {
- for (int i = 0; i < result.size(); i++) {
- result.set(i, decode(result.get(i)));
- }
+ result.replaceAll(Reference::decode);
}
return result;
@@ -1727,7 +1803,7 @@ public List getSegments(boolean decode) {
/**
* Returns the target reference. This method resolves relative references
- * against the base reference then normalize them.
+ * against the base reference, then normalizes them.
*
* @throws IllegalArgumentException If the base reference (after resolution) is
* not absolute.
@@ -1771,7 +1847,7 @@ public Reference getTargetRef() {
} else {
result.setAuthority(baseReference.getAuthority());
- if ((path == null) || (path.equals(""))) {
+ if ((path == null) || (path.isEmpty())) {
result.setPath(baseReference.getPath());
if (query != null) {
@@ -1786,7 +1862,7 @@ public Reference getTargetRef() {
final String basePath = baseReference.getPath();
String mergedPath = null;
- if ((baseReference.getAuthority() != null) && ((basePath == null) || (basePath.equals("")))) {
+ if ((baseReference.getAuthority() != null) && ((basePath == null) || (basePath.isEmpty()))) {
mergedPath = "/" + path;
} else {
// Remove the last segment which may be empty if
@@ -1822,11 +1898,11 @@ public Reference getTargetRef() {
}
/**
- * Returns the user info component for server based hierarchical
+ * Returns the user info component for server-based hierarchical
* identifiers.
* Note that no URI decoding is done by this method.
*
- * @return The user info component for server based hierarchical identifiers.
+ * @return The user info component for server-based hierarchical identifiers.
*/
public String getUserInfo() {
String result = null;
@@ -1859,13 +1935,13 @@ public String getUserInfo(boolean decode) {
* Indicates if this reference has file-like extensions on its last path
* segment.
*
- * @return True if there is are extensions.
+ * @return True if there are extensions.
* @see #getExtensions()
*/
public boolean hasExtensions() {
boolean result = false;
- // If these reference ends with a "/", it cannot be a file.
+ // If these references end with a "/", it cannot be a file.
final String path = getPath();
if (!((path != null) && path.endsWith("/"))) {
final String lastSegment = getLastSegment();
@@ -1937,11 +2013,11 @@ public boolean isAbsolute() {
}
/**
- * Returns true if both reference are equivalent, meaning that they resolve to
+ * Returns true if both references are equivalent, meaning that they resolve to
* the same target reference.
*
* @param ref The reference to compare.
- * @return True if both reference are equivalent.
+ * @return True if both references are equivalent.
*/
public boolean isEquivalentTo(Reference ref) {
return getTargetRef().equals(ref.getTargetRef());
@@ -1993,13 +2069,13 @@ public boolean isRelative() {
/**
* Normalizes the reference. Useful before comparison between references or when
- * building a target reference from a base and a relative references.
+ * building a target reference from a base reference and a relative reference.
*
* @return The current reference.
*/
public Reference normalize() {
// 1. The input buffer is initialized with the now-appended path
- // components and the output buffer is initialized to the empty string.
+ // components, and the output buffer is initialized to the empty string.
StringBuilder output = new StringBuilder();
StringBuilder input = new StringBuilder();
String path = getPath();
@@ -2008,10 +2084,10 @@ public Reference normalize() {
input.append(path);
}
- // 2. While the input buffer is not empty, loop as follows:
+ // 2. While the input buffer is not empty, the loop is as follows:
while (input.length() > 0) {
// A. If the input buffer begins with a prefix of "../" or "./",
- // then remove that prefix from the input buffer; otherwise,
+ // then remove that prefix from the input buffer; otherwise.
if ((input.length() >= 3) && input.substring(0, 3).equals("../")) {
input.delete(0, 3);
} else if ((input.length() >= 2) && input.substring(0, 2).equals("./")) {
@@ -2061,7 +2137,7 @@ else if ((input.length() == 1) && input.substring(0, 1).equals(".")) {
if (max != -1) {
// We found the next "/" character.
- output.append(input.substring(0, max));
+ output.append(input, 0, max);
input.delete(0, max);
} else {
// End of input buffer reached
@@ -2074,7 +2150,7 @@ else if ((input.length() == 1) && input.substring(0, 1).equals(".")) {
// Finally, the output buffer is returned as the result
setPath(output.toString());
- // Ensure that the scheme and host names are reset in lower case
+ // Ensure that the scheme and host names are reset in the lower case
setScheme(getScheme());
setHostDomain(getHostDomain());
@@ -2092,7 +2168,7 @@ else if ((input.length() == 1) && input.substring(0, 1).equals(".")) {
}
/**
- * Removes the last segement from the output builder.
+ * Removes the last segment from the output builder.
*
* @param output The output builder to update.
*/
@@ -2192,9 +2268,9 @@ public void setExtensions(String extensions) {
if (extensionIndex != -1) {
// Extensions found
- sb.append(lastSegment.substring(0, extensionIndex));
+ sb.append(lastSegment, 0, extensionIndex);
- if ((extensions != null) && (extensions.length() > 0)) {
+ if ((extensions != null) && (!extensions.isEmpty())) {
sb.append('.').append(extensions);
}
@@ -2203,11 +2279,13 @@ public void setExtensions(String extensions) {
}
} else {
// Extensions not found
- if ((extensions != null) && (extensions.length() > 0)) {
+ if ((extensions != null) && (!extensions.isEmpty())) {
if (matrixIndex != -1) {
// Matrix found, make sure we append it
// after the extensions
- sb.append(lastSegment.substring(0, matrixIndex)).append('.').append(extensions)
+ sb.append(lastSegment, 0, matrixIndex)
+ .append('.')
+ .append(extensions)
.append(lastSegment.substring(matrixIndex));
} else {
// No matrix found, just append the extensions
@@ -2219,7 +2297,7 @@ public void setExtensions(String extensions) {
}
}
- // Finally update the last segment
+ // Finally, update the last segment
setLastSegment(sb.toString());
} else {
setLastSegment('.' + extensions);
@@ -2292,9 +2370,9 @@ public void setFragment(String fragment) {
}
/**
- * Sets the host domain component for server based hierarchical identifiers.
+ * Sets the host domain component for server-based hierarchical identifiers.
*
- * @param domain The host component for server based hierarchical identifiers.
+ * @param domain The host component for server-based hierarchical identifiers.
*/
public void setHostDomain(String domain) {
final String authority = getAuthority();
@@ -2306,7 +2384,7 @@ public void setHostDomain(String domain) {
domain = "";
} else {
// URI specification indicates that host names should be
- // produced in lower case
+ // produced in the lower case
domain = domain.toLowerCase();
}
@@ -2339,11 +2417,11 @@ public void setHostDomain(String domain) {
}
/**
- * Sets the optional port number for server based hierarchical identifiers.
+ * Sets the optional port number for server-based hierarchical identifiers.
*
- * @param port The optional port number for server based hierarchical
+ * @param port The optional port number for server-based hierarchical
* identifiers.
- * @throws IllegalArgumentException If the autority has not been defined.
+ * @throws IllegalArgumentException If the authority has not been defined.
*/
public void setHostPort(Integer port) {
final String authority = getAuthority();
@@ -2397,7 +2475,7 @@ public void setIdentifier(String identifier) {
/**
* Sets the last segment of the path. If no path is available, then it creates
- * one and adds a slash in front of the given last segmetn.
+ * one and adds a slash in front of the given last segment.
* Note that no URI decoding is done by this method.
*
* @param lastSegment The last segment of a hierarchical path.
@@ -2584,7 +2662,7 @@ public void setScheme(String scheme) {
if (scheme != null) {
// URI specification indicates that scheme names should be
- // produced in lower case
+ // produced in the lower case
scheme = scheme.toLowerCase();
}
@@ -2610,9 +2688,9 @@ public void setScheme(String scheme) {
}
/**
- * Sets the scheme specific part.
+ * Sets the scheme-specific part.
*
- * @param schemeSpecificPart The scheme specific part.
+ * @param schemeSpecificPart The scheme-specific part.
*/
public void setSchemeSpecificPart(String schemeSpecificPart) {
schemeSpecificPart = encodeInvalidCharacters(schemeSpecificPart);
@@ -2662,11 +2740,11 @@ public void setSegments(List segments) {
}
/**
- * Sets the user info component for server based hierarchical identifiers.
+ * Sets the user info component for server-based hierarchical identifiers.
*
- * @param userInfo The user info component for server based hierarchical
+ * @param userInfo The user info component for server-based hierarchical
* identifiers.
- * @throws IllegalArgumentException If the autority part has not been defined.
+ * @throws IllegalArgumentException If the authority part has not been defined.
*/
public void setUserInfo(String userInfo) {
final String authority = getAuthority();
@@ -2686,9 +2764,9 @@ public void setUserInfo(String userInfo) {
}
/**
- * Returns the reference as an URI string.
+ * Returns the reference as a URI string.
*
- * @return The reference as an URI string.
+ * @return The reference as a URI string.
*/
@Override
public String toString() {
@@ -2779,27 +2857,29 @@ private void updateIndexes() {
if (this.internalRef != null) {
// Compute the indexes
final int firstSlashIndex = this.internalRef.indexOf('/');
- this.schemeIndex = this.internalRef.indexOf(':');
+ final int firstColonIndex = this.internalRef.indexOf(':');
- if ((firstSlashIndex != -1) && (this.schemeIndex > firstSlashIndex)) {
+ if ((firstSlashIndex != -1) && (firstColonIndex > firstSlashIndex)) {
// We are in the rare case of a relative reference where one of
// the path segments contains a colon character. In this case,
// we ignore the colon as a valid scheme index.
// Note that this colon can't be in the first segment as it is
// forbidden by the URI RFC.
this.schemeIndex = -1;
- }
+ } else {
+ this.schemeIndex = firstColonIndex;
+ }
this.queryIndex = this.internalRef.indexOf('?');
this.fragmentIndex = this.internalRef.indexOf('#');
if (hasQuery() && hasFragment() && (this.queryIndex > this.fragmentIndex)) {
- // Query sign inside fragment
+ // Query sign inside a fragment
this.queryIndex = -1;
}
if (hasQuery() && this.schemeIndex > this.queryIndex) {
- // Colon sign inside query
+ // Colon sign inside a query
this.schemeIndex = -1;
}
diff --git a/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java b/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
new file mode 100644
index 0000000000..df8479ffda
--- /dev/null
+++ b/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2005-2024 Qlik
+ *
+ * The contents of this file is subject to the terms of the Apache 2.0 open
+ * source license available at http://www.opensource.org/licenses/apache-2.0
+ *
+ * Restlet is a registered trademark of QlikTech International AB.
+ */
+
+package org.restlet.data;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class ReferenceTest {
+
+ @Test
+ public void shouldFailWhenParsingMultiPortReference() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference("http://192.168.1.1:1111:2222/"));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "http://[192.168.0.1]127.0.0.1/",
+ "http://[192.168.0.1]vulndetector.com/",
+ "http://[normal.com@]vulndetector.com/",
+ "http://normal.com[user@vulndetector].com/",
+ "http://normal.com[@]vulndetector.com/"})
+ public void shouldFailWhenParsingIncorrectHosts(String reference) {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference(reference));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"http://[0:0::vulndetector.com]:80", "http://[2001:db8::vulndetector.com]"})
+ public void shouldFailWhenParsingIncorrectIPv6Hosts(String reference) {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference(reference));
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 136d1bbdb4..4c2a811157 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,6 +106,18 @@
4.4.1
+
+
+
+ org.junit
+ junit-bom
+ ${lib-junit-version}
+ pom
+ import
+
+
+
+
github
@@ -273,16 +285,6 @@
org.restlet.gwt
-
-
-
- org.junit.jupiter
- junit-jupiter-api
- ${lib-junit-version}
-
-
-
-
From 7b01d27540e6d1a681f6afb70ecbfb4789e6a2d3 Mon Sep 17 00:00:00 2001
From: Thierry Boileau
Date: Fri, 23 Jan 2026 16:27:05 +0100
Subject: [PATCH 2/2] added control
---
.../restlet/test/data/ReferenceTestCase.java | 744 ------------------
.../main/java/org/restlet/data/Reference.java | 154 ++--
.../java/org/restlet/data/ReferenceTest.java | 731 ++++++++++++++++-
3 files changed, 823 insertions(+), 806 deletions(-)
delete mode 100644 org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
diff --git a/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java b/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
deleted file mode 100644
index 8b99446e9f..0000000000
--- a/org.restlet.java/org.restlet.test/src/main/java/org/restlet/test/data/ReferenceTestCase.java
+++ /dev/null
@@ -1,744 +0,0 @@
-/**
- * Copyright 2005-2024 Qlik
- *
- * The contents of this file is subject to the terms of the Apache 2.0 open
- * source license available at http://www.opensource.org/licenses/apache-2.0
- *
- * Restlet is a registered trademark of QlikTech International AB.
- */
-
-package org.restlet.test.data;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-import org.restlet.data.Form;
-import org.restlet.data.Header;
-import org.restlet.data.Protocol;
-import org.restlet.data.Reference;
-import org.restlet.engine.header.HeaderConstants;
-import org.restlet.engine.util.ReferenceUtils;
-import org.restlet.test.RestletTestCase;
-import org.restlet.util.Series;
-
-/**
- * Test {@link org.restlet.data.Reference}.
- *
- * @author Jerome Louvel
- * @author Lars Heuer (heuer[at]semagia.com) Semagia
- */
-public class ReferenceTestCase extends RestletTestCase {
- protected final static String DEFAULT_SCHEME = "http";
-
- protected final static String DEFAULT_SCHEMEPART = "//";
-
- /**
- * Returns a reference initialized with http://restlet.org.
- *
- * @return Reference instance.
- */
- protected Reference getDefaultReference() {
- final Reference ref = getReference();
- ref.setHostDomain("restlet.org");
- return ref;
- }
-
- /**
- * Returns a reference with uri == http://
- *
- * @return Reference instance.
- */
- protected Reference getReference() {
- final Reference ref = new Reference();
- ref.setScheme(DEFAULT_SCHEME);
- ref.setSchemeSpecificPart(DEFAULT_SCHEMEPART);
- return ref;
- }
-
- /**
- * Test addition methods.
- */
- @Test
- public void testAdditions() throws Exception {
- final Reference ref = new Reference("http://restlet.org");
- ref.addQueryParameter("abc", "123");
- assertEquals("http://restlet.org?abc=123", ref.toString());
- ref.addQueryParameter("def", null);
- assertEquals("http://restlet.org?abc=123&def", ref.toString());
- ref.addSegment("root");
- assertEquals("http://restlet.org/root?abc=123&def", ref.toString());
- ref.addSegment("dir");
- assertEquals("http://restlet.org/root/dir?abc=123&def", ref.toString());
- }
-
- @Test
- public void testEmptyRef() {
- Reference reference = new Reference();
- reference.setAuthority("testAuthority"); // must not produce NPE
-
- reference = new Reference();
- reference.setBaseRef("http://localhost"); // must not produce NPE
-
- reference = new Reference();
- reference.setFragment("fragment"); // must not produce NPE
-
- reference = new Reference();
- reference.setHostDomain("localhost"); // must not produce NPE
- assertEquals("localhost", reference.getAuthority());
- reference.setHostPort(Integer.valueOf(4711)); // must not produce NPE
- assertEquals("localhost:4711", reference.getAuthority());
- reference.setUserInfo("sdgj:skdfj"); // must not produce NPE
- assertEquals("sdgj:skdfj@localhost:4711", reference.getAuthority());
-
- reference = new Reference();
- reference.setIdentifier("http://host/abc/wkj"); // must not produce NPE
-
- reference = new Reference();
- reference.setPath("loc/alhost"); // must not produce NPE
-
- reference = new Reference();
- reference.setProtocol(Protocol.HTTPS); // must not produce NPE
-
- reference = new Reference();
- reference.setQuery("a=b&c=&g=1"); // must not produce NPE
-
- reference = new Reference();
- reference.setRelativePart("http://localhost"); // must not produce NPE
-
- reference = new Reference();
- reference.setScheme("skjf"); // must not produce NPE
-
- reference = new Reference();
- reference.setSchemeSpecificPart("host/afjhsd"); // must not produce NPE
-
- reference = new Reference();
- final List segments = new ArrayList();
- segments.add("skhf");
- segments.add("sgdfg");
- segments.add("xiz");
- reference.setSegments(segments); // must not produce NPE
- }
-
- /**
- * Equality tests.
- */
- @Test
- public void testEquals() {
- final Reference ref1 = getDefaultReference();
- final Reference ref2 = getDefaultReference();
- assertEquals(ref1, ref2);
- assertTrue(ref1.equals(ref2));
- }
-
- @Test
- public void testGetLastSegment() {
- Reference reference = new Reference("http://hostname");
- assertNull(reference.getLastSegment());
-
- reference = new Reference("http://hostname/");
- assertNull(reference.getLastSegment());
-
- reference = new Reference("http://hostname/abc");
- assertEquals("abc", reference.getLastSegment());
-
- reference = new Reference("http://hostname/abc/");
- assertEquals("abc", reference.getLastSegment());
-
- reference = new Reference("http://hostname/123/abc/");
- assertEquals("abc", reference.getLastSegment());
-
- reference = new Reference("http://hostname/123/abc");
- assertEquals("abc", reference.getLastSegment());
- }
-
- /**
- * Test hostname getting/setting.
- */
- @Test
- public void testHostName() {
- final Reference ref = getReference();
- String host = "restlet.org";
- ref.setHostDomain(host);
- assertEquals(host, ref.getHostDomain());
- host = "restlet.org";
- ref.setHostDomain(host);
- assertEquals(host, ref.getHostDomain());
- Reference ref2 = new Reference("http://[::1]:8182");
- assertEquals("[::1]", ref2.getHostDomain());
- }
-
- @Test
- public void testMatrix() {
- final Reference ref1 = new Reference(
- "http://domain.tld/whatever/a=1;b=2;c=4?x=a&y=b");
- final Reference ref2 = new Reference(
- "http://domain.tld/whatever/a=1/foo;b=2;c=4;d?x=a&y=b");
- final Reference ref3 = new Reference(
- "http://domain.tld/whatever/a=1;b=2;c=4/foo?x=a&y=b");
-
- assertTrue(ref1.hasMatrix());
- assertTrue(ref2.hasMatrix());
- assertFalse(ref3.hasMatrix());
-
- assertEquals("b=2;c=4", ref1.getMatrix());
- assertEquals("b=2;c=4;d", ref2.getMatrix());
-
- final Form form1 = ref1.getMatrixAsForm();
- assertEquals("2", form1.getFirstValue("b"));
- assertEquals("4", form1.getFirstValue("c"));
-
- final Form form2 = ref1.getMatrixAsForm();
- assertEquals("2", form2.getFirstValue("b"));
- assertEquals("4", form2.getFirstValue("c"));
- assertNull(form2.getFirstValue("d"));
-
- final Form newForm = new Form();
- newForm.add("a", "1");
- newForm.add("b", "2");
- newForm.add("c", "4");
- assertEquals("a=1;b=2;c=4", newForm.getMatrixString());
- }
-
- @Test
- public void testOriginalRef() {
- Reference ref = new Reference("http://localhost/test");
- Series headers = new Series<>(Header.class);
- headers.add(HeaderConstants.HEADER_X_FORWARDED_PROTO, "HTTPS");
- headers.add(HeaderConstants.HEADER_X_FORWARDED_PORT, "123");
-
- Reference originalRef = ReferenceUtils.getOriginalRef(ref, headers);
- assertEquals(originalRef.getSchemeProtocol(), Protocol.HTTPS);
- assertEquals(originalRef.getHostPort(), 123);
- }
-
- /**
- * Test the computation of parent references, for absolute and relative
- * URIs.
- */
- @Test
- public void testParentRef() {
- Reference baseRef = new Reference("http://test.com/foo/bar");
- Reference parentRef = baseRef.getParentRef();
- assertEquals("http://test.com/foo/", parentRef.toString());
-
- baseRef = new Reference("/foo/bar");
- parentRef = baseRef.getParentRef();
- assertEquals("/foo/", parentRef.toString());
- }
-
- /**
- * Tests the URI parsing.
- */
- @Test
- public void testParsing() {
- final String base = "http://a/b/c/d;p?q";
-
- final String uri01 = "g:h";
- final String uri02 = "g";
- final String uri03 = "./g";
- final String uri04 = "g/";
- final String uri05 = "/g";
- final String uri06 = "//g";
- final String uri07 = "?y";
- final String uri08 = "g?y";
- final String uri09 = "#s";
- final String uri10 = "g#s";
- final String uri11 = "g?y#s";
- final String uri12 = ";x";
- final String uri13 = "g;x";
- final String uri14 = "g;x?y#s";
- final String uri15 = "";
- final String uri16 = ".";
- final String uri17 = "./";
- final String uri18 = "..";
- final String uri19 = "../";
- final String uri20 = "../g";
- final String uri21 = "../..";
- final String uri22 = "../../";
- final String uri23 = "../../g";
- final String uri24 = "../../../g";
- final String uri25 = "../../../../g";
- final String uri26 = "/./g";
- final String uri27 = "/../g";
- final String uri28 = "g.";
- final String uri29 = ".g";
- final String uri30 = "g..";
- final String uri31 = "..g";
- final String uri32 = "./../g";
- final String uri33 = "./g/.";
- final String uri34 = "g/./h";
- final String uri35 = "g/../h";
- final String uri36 = "g;x=1/./y";
- final String uri37 = "g;x=1/../y";
-
- final String uri101 = "g:h";
- final String uri102 = "http://a/b/c/g";
- final String uri103 = "http://a/b/c/g";
- final String uri104 = "http://a/b/c/g/";
- final String uri105 = "http://a/g";
- final String uri106 = "http://g";
- final String uri107 = "http://a/b/c/d;p?y";
- final String uri108 = "http://a/b/c/g?y";
- final String uri109 = "http://a/b/c/d;p?q#s";
- final String uri110 = "http://a/b/c/g#s";
- final String uri111 = "http://a/b/c/g?y#s";
- final String uri112 = "http://a/b/c/;x";
- final String uri113 = "http://a/b/c/g;x";
- final String uri114 = "http://a/b/c/g;x?y#s";
- final String uri115 = "http://a/b/c/d;p?q";
- final String uri116 = "http://a/b/c/";
- final String uri117 = "http://a/b/c/";
- final String uri118 = "http://a/b/";
- final String uri119 = "http://a/b/";
- final String uri120 = "http://a/b/g";
- final String uri121 = "http://a/";
- final String uri122 = "http://a/";
- final String uri123 = "http://a/g";
- final String uri124 = "http://a/g";
- final String uri125 = "http://a/g";
- final String uri126 = "http://a/g";
- final String uri127 = "http://a/g";
- final String uri128 = "http://a/b/c/g.";
- final String uri129 = "http://a/b/c/.g";
- final String uri130 = "http://a/b/c/g..";
- final String uri131 = "http://a/b/c/..g";
- final String uri132 = "http://a/b/g";
- final String uri133 = "http://a/b/c/g/";
- final String uri134 = "http://a/b/c/g/h";
- final String uri135 = "http://a/b/c/h";
- final String uri136 = "http://a/b/c/g;x=1/y";
- final String uri137 = "http://a/b/c/y";
-
- final Reference host = new Reference("http://host.com");
- final Reference slashdir = new Reference(host, "/dir");
- final Reference dir = new Reference(host, "dir");
- final Reference dirslash = new Reference(host, "dir/");
- final Reference fulldir = new Reference("http://host.com/dir");
- final Reference fulldirsub = new Reference(fulldir, "sub");
- final Reference fulldirslashsub = new Reference(fulldir, "/sub");
- final Reference slashdirsub = new Reference(slashdir, "sub");
- final Reference slashdirslashsub = new Reference(slashdir, "/sub");
- final Reference dirslashsub = new Reference(dirslash, "sub");
- final Reference fullsub = new Reference("http://host.com/dir/sub");
-
- // Test the parsing of references into its components
- testRef0("foo://example.com:8042/over/there?name=ferret#nose", "foo",
- "example.com:8042", "/over/there", "name=ferret", "nose");
- testRef0("urn:example:animal:ferret:nose", "urn", null,
- "example:animal:ferret:nose", null, null);
- testRef0("mailto:fred@example.com", "mailto", null, "fred@example.com",
- null, null);
- testRef0("foo://info.example.com?fred", "foo", "info.example.com",
- null, "fred", null);
- testRef0("*", null, null, "*", null, null);
- testRef0("http://localhost?query", "http", "localhost", null, "query",
- null);
- testRef0("http://localhost#?query", "http", "localhost", null, null,
- "?query");
- testRef0("http://localhost/?query", "http", "localhost", "/", "query",
- null);
- testRef0("http://localhost/#?query", "http", "localhost", "/", null,
- "?query");
- testRef0("http://localhost/path#frag/ment", "http", "localhost",
- "/path", null, "frag/ment");
- testRef0("http://localhost/path?qu/ery", "http", "localhost", "/path",
- "qu/ery", null);
-
- // Test the resolution of relative references
- testRef1(base, uri01, uri101);
- testRef1(base, uri02, uri102);
- testRef1(base, uri03, uri103);
- testRef1(base, uri04, uri104);
- testRef1(base, uri05, uri105);
- testRef1(base, uri06, uri106);
- testRef1(base, uri07, uri107);
- testRef1(base, uri08, uri108);
- testRef1(base, uri09, uri109);
- testRef1(base, uri10, uri110);
- testRef1(base, uri11, uri111);
- testRef1(base, uri12, uri112);
- testRef1(base, uri13, uri113);
- testRef1(base, uri14, uri114);
- testRef1(base, uri15, uri115);
- testRef1(base, uri16, uri116);
- testRef1(base, uri17, uri117);
- testRef1(base, uri18, uri118);
- testRef1(base, uri19, uri119);
- testRef1(base, uri20, uri120);
- testRef1(base, uri21, uri121);
- testRef1(base, uri22, uri122);
- testRef1(base, uri23, uri123);
- testRef1(base, uri24, uri124);
- testRef1(base, uri25, uri125);
- testRef1(base, uri26, uri126);
- testRef1(base, uri27, uri127);
- testRef1(base, uri28, uri128);
- testRef1(base, uri29, uri129);
- testRef1(base, uri30, uri130);
- testRef1(base, uri31, uri131);
- testRef1(base, uri32, uri132);
- testRef1(base, uri33, uri133);
- testRef1(base, uri34, uri134);
- testRef1(base, uri35, uri135);
- testRef1(base, uri36, uri136);
- testRef1(base, uri37, uri137);
-
- // Test the relativization of absolute references
- testRef2(base, uri102, uri02);
- testRef2(base, uri104, uri04);
- testRef2(base, uri107, uri07);
- testRef2(base, uri108, uri08);
- testRef2(base, uri109, uri09);
- testRef2(base, uri110, uri10);
- testRef2(base, uri111, uri11);
- testRef2(base, uri112, uri12);
- testRef2(base, uri113, uri13);
- testRef2(base, uri114, uri14);
- testRef2(base, uri116, uri16);
- testRef2(base, uri118, uri18);
- testRef2(base, uri120, uri20);
- testRef2(base, uri121, uri21);
- testRef2(base, uri123, uri23);
- testRef2(uri104, uri116, uri18);
- testRef2(uri104, uri118, uri21);
-
- // Test the toString method with or without query/fragment
- testRef3("http://localhost/path#fragment", true, true,
- "http://localhost/path#fragment");
- testRef3("http://localhost/path#fragment", true, false,
- "http://localhost/path");
- testRef3("http://localhost/path#fragment", false, true,
- "http://localhost/path#fragment");
- testRef3("http://localhost/path#fragment", false, false,
- "http://localhost/path");
-
- testRef3("http://localhost/path?query", true, true,
- "http://localhost/path?query");
- testRef3("http://localhost/path?query", true, false,
- "http://localhost/path?query");
- testRef3("http://localhost/path?query", false, true,
- "http://localhost/path");
- testRef3("http://localhost/path?query", false, false,
- "http://localhost/path");
-
- testRef3("http://localhost/path?query#fragment", true, true,
- "http://localhost/path?query#fragment");
- testRef3("http://localhost/path?query#fragment", true, false,
- "http://localhost/path?query");
- testRef3("http://localhost/path?query#fragment", false, true,
- "http://localhost/path#fragment");
- testRef3("http://localhost/path?query#fragment", false, false,
- "http://localhost/path");
-
- testRef3("http://localhost/path#fragment?query", true, true,
- "http://localhost/path#fragment?query");
- testRef3("http://localhost/path#fragment?query", true, false,
- "http://localhost/path");
- testRef3("http://localhost/path#fragment?query", false, true,
- "http://localhost/path#fragment?query");
- testRef3("http://localhost/path#fragment?query", false, false,
- "http://localhost/path");
-
- testRef4(host, "http", "host.com", null, "http://host.com",
- "http://host.com", "http://host.com", null, null);
- testRef4(slashdir, null, null, "/dir", null, "/dir",
- "http://host.com/dir", null, "/dir");
- testRef4(dir, null, null, "dir", null, "dir", "http://host.com/dir",
- null, "dir");
- testRef4(dirslash, null, null, "dir/", null, "dir/",
- "http://host.com/dir/", null, "dir/");
- testRef4(fulldir, "http", "host.com", "/dir", "http://host.com/dir",
- "http://host.com/dir", "http://host.com/dir", null, null);
-
- testRef4(fulldirsub, null, null, "sub", null, "sub",
- "http://host.com/sub", null, "sub");
- testRef4(fulldirslashsub, null, null, "/sub", null, "/sub",
- "http://host.com/sub", null, "/sub");
- testRef4(slashdirsub, null, null, "sub", null, "sub",
- "http://host.com/sub", null, "sub");
- testRef4(slashdirslashsub, null, null, "/sub", null, "/sub",
- "http://host.com/sub", null, "/sub");
- testRef4(dirslashsub, null, null, "sub", null, "sub",
- "http://host.com/dir/sub", null, "sub");
- testRef4(fullsub, "http", "host.com", "/dir/sub",
- "http://host.com/dir/sub", "http://host.com/dir/sub",
- "http://host.com/dir/sub", null, null);
- }
-
- /**
- * Test port getting/setting.
- */
- @Test
- public void testPort() {
- Reference ref = getDefaultReference();
- int port = 8080;
- ref.setHostPort(port);
- assertEquals(port, ref.getHostPort());
- port = 9090;
- ref.setHostPort(port);
- assertEquals(port, ref.getHostPort());
- ref = new Reference("http://[::1]:8182");
- assertEquals(8182, ref.getHostPort());
- }
-
- @Test
- public void testProtocolConstructors() {
- assertEquals("http://restlet.org", new Reference(Protocol.HTTP,
- "restlet.org").toString());
- assertEquals("https://restlet.org:8443", new Reference(Protocol.HTTPS,
- "restlet.org", 8443).toString());
-
- final Reference ref = new Reference(Protocol.HTTP, "restlet.org");
- ref.addQueryParameter("abc", "123");
- assertEquals("http://restlet.org?abc=123", ref.toString());
- }
-
- @Test
- public void testQuery() {
-
- Reference ref1 = new Reference(
- "http://localhost/search?q=anythingelse%");
- String query = ref1.getQuery();
- assertEquals("q=anythingelse%25", query);
-
- Form queryForm = ref1.getQueryAsForm();
- assertEquals("anythingelse%", queryForm.getFirstValue("q"));
-
- Form extJsQuery = new Form(
- "&_dc=1244741620627&callback=stcCallback1001");
- assertEquals("1244741620627", extJsQuery.getFirstValue("_dc"));
- assertEquals("stcCallback1001", extJsQuery.getFirstValue("callback"));
-
- Reference ref = new Reference("http://localhost/v1/projects/13404");
- ref.addQueryParameter("dyn", "true");
- assertEquals("http://localhost/v1/projects/13404?dyn=true",
- ref.toString());
- }
-
- @Test
- public void testQueryWithUri() {
- Reference ref = new Reference(new Reference("http://localhost:8111/"),
- "http://localhost:8111/contrats/123?srvgwt=localhost:9997");
- assertEquals("contrats/123?srvgwt=localhost:9997", ref.getRelativeRef()
- .toString());
- }
-
- /**
- * Tests the parsing of a reference into its components
- *
- * @param reference
- * @param scheme
- * @param authority
- * @param path
- * @param query
- * @param fragment
- */
- private void testRef0(String reference, String scheme, String authority,
- String path, String query, String fragment) {
- final Reference ref = new Reference(reference);
- assertEquals(scheme, ref.getScheme());
- assertEquals(authority, ref.getAuthority());
- assertEquals(path, ref.getPath());
- assertEquals(query, ref.getQuery());
- assertEquals(fragment, ref.getFragment());
- }
-
- /**
- * Test the resolution of relative references.
- *
- * @param baseUri
- * @param relativeUri
- * @param expectedAbsoluteUri
- */
- private void testRef1(String baseUri, String relativeUri,
- String expectedAbsoluteUri) {
- final Reference baseRef = new Reference(baseUri);
- final Reference relativeRef = new Reference(baseRef, relativeUri);
- final Reference absoluteRef = relativeRef.getTargetRef();
- assertEquals(expectedAbsoluteUri, absoluteRef.toString());
- }
-
- /**
- * Test the relativization of absolute references
- *
- * @param baseUri
- * @param absoluteUri
- * @param expectedRelativeUri
- */
- private void testRef2(String baseUri, String absoluteUri,
- String expectedRelativeUri) {
- final Reference baseRef = new Reference(baseUri);
- final Reference absoluteRef = new Reference(absoluteUri);
- final Reference relativeRef = absoluteRef.getRelativeRef(baseRef);
- assertEquals(expectedRelativeUri, relativeRef.toString());
- }
-
- /**
- * Test the toString method with or without query/fragment
- *
- * @param reference
- * @param query
- * @param fragment
- * @param toString
- */
- private void testRef3(String reference, boolean query, boolean fragment,
- String toString) {
- final Reference ref = new Reference(reference);
- assertEquals(ref.toString(query, fragment), toString);
- }
-
- /**
- * Test the behaviour of several getters upon a Reference object.
- */
- private void testRef4(Reference reference, String scheme, String authority,
- String path, String remainingPart, String toString,
- String targetRef, String query, String relativePart) {
- assertEquals(reference.getScheme(), scheme);
- assertEquals(reference.getAuthority(), authority);
- assertEquals(reference.getPath(), path);
- assertEquals(reference.getRemainingPart(), remainingPart);
- assertEquals(reference.toString(), toString);
- assertEquals(reference.getTargetRef().toString(), targetRef);
- assertEquals(reference.getQuery(), query);
- assertEquals(reference.getRelativePart(), relativePart);
- }
-
- @Test
- public void testRiap() {
- Reference baseRef = new Reference("riap://component/exist/db/");
- Reference ref = new Reference(baseRef, "something.xq");
- assertEquals("riap://component/exist/db/something.xq", ref
- .getTargetRef().toString());
- }
-
- /**
- * Test scheme getting/setting.
- */
- @Test
- public void testScheme() {
- final Reference ref = getDefaultReference();
- assertEquals(DEFAULT_SCHEME, ref.getScheme());
- final String scheme = "https";
- ref.setScheme(scheme);
- assertEquals(scheme, ref.getScheme());
- ref.setScheme(DEFAULT_SCHEME);
- assertEquals(DEFAULT_SCHEME, ref.getScheme());
- }
-
- /**
- * Test scheme specific part getting/setting.
- */
- @Test
- public void testSchemeSpecificPart() {
- final Reference ref = getDefaultReference();
- String part = "//restlet.org";
- assertEquals(part, ref.getSchemeSpecificPart());
- part = "//restlet.net";
- ref.setSchemeSpecificPart(part);
- assertEquals(part, ref.getSchemeSpecificPart());
- }
-
- /**
- * Test setting of the last segment.
- */
- @Test
- public void testSetLastSegment() {
- Reference ref = new Reference("http://localhost:1234");
- ref.addSegment("test");
- assertEquals("http://localhost:1234/test", ref.toString());
-
- ref.setLastSegment("last");
- assertEquals("http://localhost:1234/last", ref.toString());
-
- ref = new Reference("http://localhost:1234");
- ref.setLastSegment("last");
- assertEquals("http://localhost:1234/last", ref.toString());
-
- ref.setLastSegment("test");
- assertEquals("http://localhost:1234/test", ref.toString());
-
- ref.addSegment("last");
- assertEquals("http://localhost:1234/test/last", ref.toString());
- }
-
- @Test
- public void testTargetRef() {
- Reference ref = new Reference(
- "http://twitter.com?status=RT @gamasutra: Devil May Cry : Born Again http://www.gamasutra.com/view/feature/177267/");
- Reference targetRef = new Reference(
- new Reference(
- "http://www.gamasutra.com/view/feature/177267/devil_may_cry_born_again.php"),
- ref).getTargetRef();
- assertEquals(
- "http://twitter.com?status=RT%20@gamasutra:%20%20Devil%20May%20Cry%20:%20Born%20Again%20http:?status=RT%20@gamasutra:%20%20Devil%20May%20Cry%20:%20Born%20Again%20http://www.gamasutra.com/view/feature/177267/",
- targetRef.toString());
- }
-
- /**
- * Test references that are unequal.
- */
- @Test
- public void testUnEquals() throws Exception {
- final String uri1 = "http://restlet.org/";
- final String uri2 = "http://restlet.net/";
- final Reference ref1 = new Reference(uri1);
- final Reference ref2 = new Reference(uri2);
- assertFalse(ref1.equals(ref2));
- assertFalse(ref1.equals(null));
- }
-
- @Test
- public void testUserinfo() {
- final Reference reference = new Reference("http://localhost:81");
- // This format is depre. however we may prevent failures.
- reference.setUserInfo("login:password");
- assertEquals("login:password@localhost:81", reference.getAuthority());
- assertEquals("localhost", reference.getHostDomain());
- assertEquals(81, reference.getHostPort());
- assertEquals("login:password", reference.getUserInfo());
-
- reference.setHostDomain("[::1]");
- assertEquals("login:password@[::1]:81", reference.getAuthority());
- assertEquals("[::1]", reference.getHostDomain());
- assertEquals(81, reference.getHostPort());
- assertEquals("login:password", reference.getUserInfo());
-
- reference.setHostDomain("www.example.com");
- assertEquals("login:password@www.example.com:81",
- reference.getAuthority());
- assertEquals("www.example.com", reference.getHostDomain());
- assertEquals(81, reference.getHostPort());
- assertEquals("login:password", reference.getUserInfo());
-
- reference.setHostPort(82);
- assertEquals("login:password@www.example.com:82",
- reference.getAuthority());
- assertEquals("www.example.com", reference.getHostDomain());
- assertEquals(82, reference.getHostPort());
- assertEquals("login:password", reference.getUserInfo());
-
- reference.setUserInfo("login");
- assertEquals("login@www.example.com:82", reference.getAuthority());
- assertEquals("www.example.com", reference.getHostDomain());
- assertEquals(82, reference.getHostPort());
- assertEquals("login", reference.getUserInfo());
- }
-
- @Test
- public void testValidity() {
- String uri = "http ://domain.tld/whatever/";
- Reference ref = new Reference(uri);
- assertEquals("http%20://domain.tld/whatever/", ref.toString());
-
- uri = "file:///C|/wherever\\whatever.swf";
- ref = new Reference(uri);
- assertEquals("file:///C%7C/wherever%5Cwhatever.swf", ref.toString());
- }
-}
diff --git a/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java b/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
index 498df4cafd..8aa525f330 100644
--- a/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
+++ b/org.restlet.java/org.restlet/src/main/java/org/restlet/data/Reference.java
@@ -516,85 +516,119 @@ public Reference(Reference baseRef, String uriRef) {
}
public void validateInternalRef(String url) {
- java.util.Map components = new java.util.HashMap<>();
-
if (url == null || url.isEmpty()) {
- throw new IllegalArgumentException("URL cannot be null or empty");
+ return;
}
- String remaining = url;
-
- // Parse scheme
- int schemeEnd = remaining.indexOf(':');
- if (schemeEnd > 0) {
- components.put("scheme", remaining.substring(0, schemeEnd).toLowerCase());
- remaining = remaining.substring(schemeEnd + 1);
- } else {
- components.put("scheme", null);
- }
+ String authority = getAuthority(url);
- if (remaining.startsWith("//")) {
- remaining = remaining.substring(2);
- int authorityEnd = remaining.indexOf('/');
- if (authorityEnd == -1) {
- authorityEnd = remaining.indexOf('?');
- }
- if (authorityEnd == -1) {
- authorityEnd = remaining.indexOf('#');
+ if (authority.startsWith("[")) {
+ int ipv6End = authority.indexOf(']');
+ if (ipv6End != -1) {
+ validateIPv6(authority.substring(0, ipv6End + 1));
+ if (ipv6End + 1 < authority.length() && authority.charAt(ipv6End + 1) == ':') {
+ validateHostPort(authority.substring(ipv6End + 2));
+ } else if (ipv6End + 1 < authority.length()) {
+ throw new IllegalArgumentException("Invalid authority format");
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
}
- if (authorityEnd == -1) {
- authorityEnd = remaining.length();
+ } else if (authority.indexOf('[') != -1) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ } else {
+ int atIndex = authority.indexOf('@');
+ if (atIndex != -1) {
+ authority = authority.substring(atIndex + 1);
}
- String authority = remaining.substring(0, authorityEnd);
+ int portIndex = authority.indexOf(':');
+ if (portIndex != -1) {
+ validateHostPort(authority.substring(portIndex + 1));
+ }
+ }
+ }
- // Parse host and port
- // Handle IPv6 addresses [::1]
- if (authority.startsWith("[")) {
- int ipv6End = authority.indexOf(']');
- if (ipv6End != -1) {
- components.put("hostName", authority.substring(0, ipv6End + 1));
- if () {
+ private static String getAuthority(final String url) {
+ String remaining = url;
- }
- if (ipv6End + 1 < authority.length() && authority.charAt(ipv6End + 1) == ':') {
- components.put("hostPort", authority.substring(ipv6End + 2));
- } else if (ipv6End + 1 < authority.length()) {
- throw new IllegalArgumentException("Invalid authority format");
- } else {
- components.put("hostPort", null);
- }
- } else {
- throw new IllegalArgumentException("Invalid IPv6 address format");
- }
- } else if (authority.indexOf('[') != -1) {
- throw new IllegalArgumentException("Invalid IPv6 address format");
- } else {
- int atIndex = authority.indexOf('@');
- if (atIndex != -1) {
- authority = authority.substring(atIndex + 1);
- }
+ // Parse scheme
+ int schemeEnd = remaining.indexOf("://");
+ if (schemeEnd > 0) {
+ remaining = remaining.substring(schemeEnd + 3);
+ }
- int portIndex = authority.indexOf(':');
- if (portIndex != -1) {
- components.put("hostName", authority.substring(0, portIndex));
- components.put("hostPort", authority.substring(portIndex + 1));
- } else {
- components.put("hostName", authority);
- components.put("hostPort", null);
- }
- }
+ int authorityEnd = remaining.indexOf('/');
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.indexOf('?');
+ }
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.indexOf('#');
+ }
+ if (authorityEnd == -1) {
+ authorityEnd = remaining.length();
}
- if (components.get("hostPort") != null) {
+ return remaining.substring(0, authorityEnd);
+ }
+
+ private static void validateHostPort(final String hostPort) {
+ if (hostPort != null) {
try {
- Integer.parseInt(components.get("hostPort"));
+ Integer.parseInt(hostPort);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid port number format");
}
}
}
+ // RFC 2373
+ private static void validateIPv6(String ipv6) {
+ if (ipv6 == null || ipv6.isEmpty()) {
+ throw new IllegalArgumentException("Invalid IPv6 address");
+ }
+
+ if (ipv6.startsWith("[")) {
+ ipv6 = ipv6.substring(1);
+ }
+ if (ipv6.endsWith("]")) {
+ ipv6 = ipv6.substring(0, ipv6.length() - 1);
+ }
+
+ // Check for double colon compression (only one allowed)
+ int doubleColonCount = 0;
+ int idx = ipv6.indexOf("::");
+ while (idx != -1) {
+ doubleColonCount++;
+ idx = ipv6.indexOf("::", idx + 2);
+ }
+ if (doubleColonCount > 1) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+
+ String[] parts = ipv6.split(":", -1);
+ int maxParts = 8;
+
+ if (parts.length > maxParts) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+
+ for (String part : parts) {
+ if (part.isEmpty() && doubleColonCount == 0) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+ if (!part.isEmpty()) {
+ if (part.length() > 4) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+ for (char c : part.toCharArray()) {
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+ throw new IllegalArgumentException("Invalid IPv6 address format");
+ }
+ }
+ }
+ }
+ }
/**
* Constructor of relative reference from its parts.
*
diff --git a/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java b/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
index df8479ffda..d080b7c66c 100644
--- a/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
+++ b/org.restlet.java/org.restlet/src/test/java/org/restlet/data/ReferenceTest.java
@@ -9,13 +9,734 @@
package org.restlet.data;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
+import org.restlet.engine.header.HeaderConstants;
+import org.restlet.engine.util.ReferenceUtils;
+import org.restlet.util.Series;
public class ReferenceTest {
+ protected final static String DEFAULT_SCHEME = "http";
+
+ protected final static String DEFAULT_SCHEMEPART = "//";
+
+ /**
+ * Returns a reference initialized with http://restlet.org.
+ *
+ * @return Reference instance.
+ */
+ protected Reference getDefaultReference() {
+ final Reference ref = getReference();
+ ref.setHostDomain("restlet.org");
+ return ref;
+ }
+
+ /**
+ * Returns a reference with uri == http://
+ *
+ * @return Reference instance.
+ */
+ protected Reference getReference() {
+ final Reference ref = new Reference();
+ ref.setScheme(DEFAULT_SCHEME);
+ ref.setSchemeSpecificPart(DEFAULT_SCHEMEPART);
+ return ref;
+ }
+
+ /**
+ * Test addition methods.
+ */
+ @Test
+ public void testAdditions() throws Exception {
+ final Reference ref = new Reference("http://restlet.org");
+ ref.addQueryParameter("abc", "123");
+ assertEquals("http://restlet.org?abc=123", ref.toString());
+ ref.addQueryParameter("def", null);
+ assertEquals("http://restlet.org?abc=123&def", ref.toString());
+ ref.addSegment("root");
+ assertEquals("http://restlet.org/root?abc=123&def", ref.toString());
+ ref.addSegment("dir");
+ assertEquals("http://restlet.org/root/dir?abc=123&def", ref.toString());
+ }
+
+ @Test
+ public void testEmptyRef() {
+ Reference reference = new Reference();
+ reference.setAuthority("testAuthority"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setBaseRef("http://localhost"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setFragment("fragment"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setHostDomain("localhost"); // must not produce NPE
+ assertEquals("localhost", reference.getAuthority());
+ reference.setHostPort(Integer.valueOf(4711)); // must not produce NPE
+ assertEquals("localhost:4711", reference.getAuthority());
+ reference.setUserInfo("sdgj:skdfj"); // must not produce NPE
+ assertEquals("sdgj:skdfj@localhost:4711", reference.getAuthority());
+
+ reference = new Reference();
+ reference.setIdentifier("http://host/abc/wkj"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setPath("loc/alhost"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setProtocol(Protocol.HTTPS); // must not produce NPE
+
+ reference = new Reference();
+ reference.setQuery("a=b&c=&g=1"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setRelativePart("http://localhost"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setScheme("skjf"); // must not produce NPE
+
+ reference = new Reference();
+ reference.setSchemeSpecificPart("host/afjhsd"); // must not produce NPE
+
+ reference = new Reference();
+ final List segments = new ArrayList();
+ segments.add("skhf");
+ segments.add("sgdfg");
+ segments.add("xiz");
+ reference.setSegments(segments); // must not produce NPE
+ }
+
+ /**
+ * Equality tests.
+ */
+ @Test
+ public void testEquals() {
+ final Reference ref1 = getDefaultReference();
+ final Reference ref2 = getDefaultReference();
+ assertEquals(ref1, ref2);
+ assertTrue(ref1.equals(ref2));
+ }
+
+ @Test
+ public void testGetLastSegment() {
+ Reference reference = new Reference("http://hostname");
+ assertNull(reference.getLastSegment());
+
+ reference = new Reference("http://hostname/");
+ assertNull(reference.getLastSegment());
+
+ reference = new Reference("http://hostname/abc");
+ assertEquals("abc", reference.getLastSegment());
+
+ reference = new Reference("http://hostname/abc/");
+ assertEquals("abc", reference.getLastSegment());
+
+ reference = new Reference("http://hostname/123/abc/");
+ assertEquals("abc", reference.getLastSegment());
+
+ reference = new Reference("http://hostname/123/abc");
+ assertEquals("abc", reference.getLastSegment());
+ }
+
+ /**
+ * Test hostname getting/setting.
+ */
+ @Test
+ public void testHostName() {
+ final Reference ref = getReference();
+ String host = "restlet.org";
+ ref.setHostDomain(host);
+ assertEquals(host, ref.getHostDomain());
+ host = "restlet.org";
+ ref.setHostDomain(host);
+ assertEquals(host, ref.getHostDomain());
+ Reference ref2 = new Reference("http://[::1]:8182");
+ assertEquals("[::1]", ref2.getHostDomain());
+ }
+
+ @Test
+ public void testMatrix() {
+ final Reference ref1 = new Reference(
+ "http://domain.tld/whatever/a=1;b=2;c=4?x=a&y=b");
+ final Reference ref2 = new Reference(
+ "http://domain.tld/whatever/a=1/foo;b=2;c=4;d?x=a&y=b");
+ final Reference ref3 = new Reference(
+ "http://domain.tld/whatever/a=1;b=2;c=4/foo?x=a&y=b");
+
+ assertTrue(ref1.hasMatrix());
+ assertTrue(ref2.hasMatrix());
+ assertFalse(ref3.hasMatrix());
+
+ assertEquals("b=2;c=4", ref1.getMatrix());
+ assertEquals("b=2;c=4;d", ref2.getMatrix());
+
+ final Form form1 = ref1.getMatrixAsForm();
+ assertEquals("2", form1.getFirstValue("b"));
+ assertEquals("4", form1.getFirstValue("c"));
+
+ final Form form2 = ref1.getMatrixAsForm();
+ assertEquals("2", form2.getFirstValue("b"));
+ assertEquals("4", form2.getFirstValue("c"));
+ assertNull(form2.getFirstValue("d"));
+
+ final Form newForm = new Form();
+ newForm.add("a", "1");
+ newForm.add("b", "2");
+ newForm.add("c", "4");
+ assertEquals("a=1;b=2;c=4", newForm.getMatrixString());
+ }
+
+ @Test
+ public void testOriginalRef() {
+ Reference ref = new Reference("http://localhost/test");
+ Series headers = new Series<>(Header.class);
+ headers.add(HeaderConstants.HEADER_X_FORWARDED_PROTO, "HTTPS");
+ headers.add(HeaderConstants.HEADER_X_FORWARDED_PORT, "123");
+
+ Reference originalRef = ReferenceUtils.getOriginalRef(ref, headers);
+ assertEquals(originalRef.getSchemeProtocol(), Protocol.HTTPS);
+ assertEquals(originalRef.getHostPort(), 123);
+ }
+
+ /**
+ * Test the computation of parent references, for absolute and relative
+ * URIs.
+ */
+ @Test
+ public void testParentRef() {
+ Reference baseRef = new Reference("http://test.com/foo/bar");
+ Reference parentRef = baseRef.getParentRef();
+ assertEquals("http://test.com/foo/", parentRef.toString());
+
+ baseRef = new Reference("/foo/bar");
+ parentRef = baseRef.getParentRef();
+ assertEquals("/foo/", parentRef.toString());
+ }
+
+ /**
+ * Tests the URI parsing.
+ */
+ @Test
+ public void testParsing() {
+ final String base = "http://a/b/c/d;p?q";
+
+ final String uri01 = "g:h";
+ final String uri02 = "g";
+ final String uri03 = "./g";
+ final String uri04 = "g/";
+ final String uri05 = "/g";
+ final String uri06 = "//g";
+ final String uri07 = "?y";
+ final String uri08 = "g?y";
+ final String uri09 = "#s";
+ final String uri10 = "g#s";
+ final String uri11 = "g?y#s";
+ final String uri12 = ";x";
+ final String uri13 = "g;x";
+ final String uri14 = "g;x?y#s";
+ final String uri15 = "";
+ final String uri16 = ".";
+ final String uri17 = "./";
+ final String uri18 = "..";
+ final String uri19 = "../";
+ final String uri20 = "../g";
+ final String uri21 = "../..";
+ final String uri22 = "../../";
+ final String uri23 = "../../g";
+ final String uri24 = "../../../g";
+ final String uri25 = "../../../../g";
+ final String uri26 = "/./g";
+ final String uri27 = "/../g";
+ final String uri28 = "g.";
+ final String uri29 = ".g";
+ final String uri30 = "g..";
+ final String uri31 = "..g";
+ final String uri32 = "./../g";
+ final String uri33 = "./g/.";
+ final String uri34 = "g/./h";
+ final String uri35 = "g/../h";
+ final String uri36 = "g;x=1/./y";
+ final String uri37 = "g;x=1/../y";
+
+ final String uri101 = "g:h";
+ final String uri102 = "http://a/b/c/g";
+ final String uri103 = "http://a/b/c/g";
+ final String uri104 = "http://a/b/c/g/";
+ final String uri105 = "http://a/g";
+ final String uri106 = "http://g";
+ final String uri107 = "http://a/b/c/d;p?y";
+ final String uri108 = "http://a/b/c/g?y";
+ final String uri109 = "http://a/b/c/d;p?q#s";
+ final String uri110 = "http://a/b/c/g#s";
+ final String uri111 = "http://a/b/c/g?y#s";
+ final String uri112 = "http://a/b/c/;x";
+ final String uri113 = "http://a/b/c/g;x";
+ final String uri114 = "http://a/b/c/g;x?y#s";
+ final String uri115 = "http://a/b/c/d;p?q";
+ final String uri116 = "http://a/b/c/";
+ final String uri117 = "http://a/b/c/";
+ final String uri118 = "http://a/b/";
+ final String uri119 = "http://a/b/";
+ final String uri120 = "http://a/b/g";
+ final String uri121 = "http://a/";
+ final String uri122 = "http://a/";
+ final String uri123 = "http://a/g";
+ final String uri124 = "http://a/g";
+ final String uri125 = "http://a/g";
+ final String uri126 = "http://a/g";
+ final String uri127 = "http://a/g";
+ final String uri128 = "http://a/b/c/g.";
+ final String uri129 = "http://a/b/c/.g";
+ final String uri130 = "http://a/b/c/g..";
+ final String uri131 = "http://a/b/c/..g";
+ final String uri132 = "http://a/b/g";
+ final String uri133 = "http://a/b/c/g/";
+ final String uri134 = "http://a/b/c/g/h";
+ final String uri135 = "http://a/b/c/h";
+ final String uri136 = "http://a/b/c/g;x=1/y";
+ final String uri137 = "http://a/b/c/y";
+
+ final Reference host = new Reference("http://host.com");
+ final Reference slashdir = new Reference(host, "/dir");
+ final Reference dir = new Reference(host, "dir");
+ final Reference dirslash = new Reference(host, "dir/");
+ final Reference fulldir = new Reference("http://host.com/dir");
+ final Reference fulldirsub = new Reference(fulldir, "sub");
+ final Reference fulldirslashsub = new Reference(fulldir, "/sub");
+ final Reference slashdirsub = new Reference(slashdir, "sub");
+ final Reference slashdirslashsub = new Reference(slashdir, "/sub");
+ final Reference dirslashsub = new Reference(dirslash, "sub");
+ final Reference fullsub = new Reference("http://host.com/dir/sub");
+
+ // Test the parsing of references into its components
+ testRef0("foo://example.com:8042/over/there?name=ferret#nose", "foo",
+ "example.com:8042", "/over/there", "name=ferret", "nose");
+
+ // TODO support URN
+ //testRef0("urn:example:animal:ferret:nose", "urn", null,
+ // "example:animal:ferret:nose", null, null);
+ testRef0("mailto:fred@example.com", "mailto", null, "fred@example.com",
+ null, null);
+ testRef0("foo://info.example.com?fred", "foo", "info.example.com",
+ null, "fred", null);
+ testRef0("*", null, null, "*", null, null);
+ testRef0("http://localhost?query", "http", "localhost", null, "query",
+ null);
+ testRef0("http://localhost#?query", "http", "localhost", null, null,
+ "?query");
+ testRef0("http://localhost/?query", "http", "localhost", "/", "query",
+ null);
+ testRef0("http://localhost/#?query", "http", "localhost", "/", null,
+ "?query");
+ testRef0("http://localhost/path#frag/ment", "http", "localhost",
+ "/path", null, "frag/ment");
+ testRef0("http://localhost/path?qu/ery", "http", "localhost", "/path",
+ "qu/ery", null);
+
+ // Test the resolution of relative references
+ // TODO testRef1(base, uri01, uri101);
+ testRef1(base, uri02, uri102);
+ testRef1(base, uri03, uri103);
+ testRef1(base, uri04, uri104);
+ testRef1(base, uri05, uri105);
+ testRef1(base, uri06, uri106);
+ testRef1(base, uri07, uri107);
+ testRef1(base, uri08, uri108);
+ testRef1(base, uri09, uri109);
+ testRef1(base, uri10, uri110);
+ testRef1(base, uri11, uri111);
+ testRef1(base, uri12, uri112);
+ testRef1(base, uri13, uri113);
+ testRef1(base, uri14, uri114);
+ testRef1(base, uri15, uri115);
+ testRef1(base, uri16, uri116);
+ testRef1(base, uri17, uri117);
+ testRef1(base, uri18, uri118);
+ testRef1(base, uri19, uri119);
+ testRef1(base, uri20, uri120);
+ testRef1(base, uri21, uri121);
+ testRef1(base, uri22, uri122);
+ testRef1(base, uri23, uri123);
+ testRef1(base, uri24, uri124);
+ testRef1(base, uri25, uri125);
+ testRef1(base, uri26, uri126);
+ testRef1(base, uri27, uri127);
+ testRef1(base, uri28, uri128);
+ testRef1(base, uri29, uri129);
+ testRef1(base, uri30, uri130);
+ testRef1(base, uri31, uri131);
+ testRef1(base, uri32, uri132);
+ testRef1(base, uri33, uri133);
+ testRef1(base, uri34, uri134);
+ testRef1(base, uri35, uri135);
+ testRef1(base, uri36, uri136);
+ testRef1(base, uri37, uri137);
+
+ // Test the relativization of absolute references
+ testRef2(base, uri102, uri02);
+ testRef2(base, uri104, uri04);
+ testRef2(base, uri107, uri07);
+ testRef2(base, uri108, uri08);
+ testRef2(base, uri109, uri09);
+ testRef2(base, uri110, uri10);
+ testRef2(base, uri111, uri11);
+ testRef2(base, uri112, uri12);
+ testRef2(base, uri113, uri13);
+ testRef2(base, uri114, uri14);
+ testRef2(base, uri116, uri16);
+ testRef2(base, uri118, uri18);
+ testRef2(base, uri120, uri20);
+ testRef2(base, uri121, uri21);
+ testRef2(base, uri123, uri23);
+ testRef2(uri104, uri116, uri18);
+ testRef2(uri104, uri118, uri21);
+
+ // Test the toString method with or without query/fragment
+ testRef3("http://localhost/path#fragment", true, true,
+ "http://localhost/path#fragment");
+ testRef3("http://localhost/path#fragment", true, false,
+ "http://localhost/path");
+ testRef3("http://localhost/path#fragment", false, true,
+ "http://localhost/path#fragment");
+ testRef3("http://localhost/path#fragment", false, false,
+ "http://localhost/path");
+
+ testRef3("http://localhost/path?query", true, true,
+ "http://localhost/path?query");
+ testRef3("http://localhost/path?query", true, false,
+ "http://localhost/path?query");
+ testRef3("http://localhost/path?query", false, true,
+ "http://localhost/path");
+ testRef3("http://localhost/path?query", false, false,
+ "http://localhost/path");
+
+ testRef3("http://localhost/path?query#fragment", true, true,
+ "http://localhost/path?query#fragment");
+ testRef3("http://localhost/path?query#fragment", true, false,
+ "http://localhost/path?query");
+ testRef3("http://localhost/path?query#fragment", false, true,
+ "http://localhost/path#fragment");
+ testRef3("http://localhost/path?query#fragment", false, false,
+ "http://localhost/path");
+
+ testRef3("http://localhost/path#fragment?query", true, true,
+ "http://localhost/path#fragment?query");
+ testRef3("http://localhost/path#fragment?query", true, false,
+ "http://localhost/path");
+ testRef3("http://localhost/path#fragment?query", false, true,
+ "http://localhost/path#fragment?query");
+ testRef3("http://localhost/path#fragment?query", false, false,
+ "http://localhost/path");
+
+ testRef4(host, "http", "host.com", null, "http://host.com",
+ "http://host.com", "http://host.com", null, null);
+ testRef4(slashdir, null, null, "/dir", null, "/dir",
+ "http://host.com/dir", null, "/dir");
+ testRef4(dir, null, null, "dir", null, "dir", "http://host.com/dir",
+ null, "dir");
+ testRef4(dirslash, null, null, "dir/", null, "dir/",
+ "http://host.com/dir/", null, "dir/");
+ testRef4(fulldir, "http", "host.com", "/dir", "http://host.com/dir",
+ "http://host.com/dir", "http://host.com/dir", null, null);
+
+ testRef4(fulldirsub, null, null, "sub", null, "sub",
+ "http://host.com/sub", null, "sub");
+ testRef4(fulldirslashsub, null, null, "/sub", null, "/sub",
+ "http://host.com/sub", null, "/sub");
+ testRef4(slashdirsub, null, null, "sub", null, "sub",
+ "http://host.com/sub", null, "sub");
+ testRef4(slashdirslashsub, null, null, "/sub", null, "/sub",
+ "http://host.com/sub", null, "/sub");
+ testRef4(dirslashsub, null, null, "sub", null, "sub",
+ "http://host.com/dir/sub", null, "sub");
+ testRef4(fullsub, "http", "host.com", "/dir/sub",
+ "http://host.com/dir/sub", "http://host.com/dir/sub",
+ "http://host.com/dir/sub", null, null);
+ }
+
+ /**
+ * Test port getting/setting.
+ */
+ @ParameterizedTest
+ @ValueSource(ints = { 8080, 9090 })
+ public void testPort(int port) {
+ Reference ref = getDefaultReference();
+ ref.setHostPort(port);
+ assertEquals(port, ref.getHostPort());
+ }
+
+ @Test
+ public void testPortIPv6() {
+ Reference ref = new Reference("http://[::1]:8182");
+ assertEquals(8182, ref.getHostPort());
+ }
+
+ @Test
+ public void testProtocolConstructors() {
+ assertEquals("http://restlet.org", new Reference(Protocol.HTTP,
+ "restlet.org").toString());
+ assertEquals("https://restlet.org:8443", new Reference(Protocol.HTTPS,
+ "restlet.org", 8443).toString());
+
+ final Reference ref = new Reference(Protocol.HTTP, "restlet.org");
+ ref.addQueryParameter("abc", "123");
+ assertEquals("http://restlet.org?abc=123", ref.toString());
+ }
+
+ @Test
+ public void testQuery() {
+
+ Reference ref1 = new Reference(
+ "http://localhost/search?q=anythingelse%");
+ String query = ref1.getQuery();
+ assertEquals("q=anythingelse%25", query);
+
+ Form queryForm = ref1.getQueryAsForm();
+ assertEquals("anythingelse%", queryForm.getFirstValue("q"));
+
+ Form extJsQuery = new Form(
+ "&_dc=1244741620627&callback=stcCallback1001");
+ assertEquals("1244741620627", extJsQuery.getFirstValue("_dc"));
+ assertEquals("stcCallback1001", extJsQuery.getFirstValue("callback"));
+
+ Reference ref = new Reference("http://localhost/v1/projects/13404");
+ ref.addQueryParameter("dyn", "true");
+ assertEquals("http://localhost/v1/projects/13404?dyn=true",
+ ref.toString());
+ }
+
+ @Test
+ public void testQueryWithUri() {
+ Reference ref = new Reference(new Reference("http://localhost:8111/"),
+ "http://localhost:8111/contrats/123?srvgwt=localhost:9997");
+ assertEquals("contrats/123?srvgwt=localhost:9997", ref.getRelativeRef()
+ .toString());
+ }
+
+ /**
+ * Tests the parsing of a reference into its components
+ *
+ * @param reference
+ * @param scheme
+ * @param authority
+ * @param path
+ * @param query
+ * @param fragment
+ */
+ private void testRef0(String reference, String scheme, String authority,
+ String path, String query, String fragment) {
+ final Reference ref = new Reference(reference);
+ assertEquals(scheme, ref.getScheme());
+ assertEquals(authority, ref.getAuthority());
+ assertEquals(path, ref.getPath());
+ assertEquals(query, ref.getQuery());
+ assertEquals(fragment, ref.getFragment());
+ }
+
+ /**
+ * Test the resolution of relative references.
+ *
+ * @param baseUri
+ * @param relativeUri
+ * @param expectedAbsoluteUri
+ */
+ private void testRef1(String baseUri, String relativeUri,
+ String expectedAbsoluteUri) {
+ final Reference baseRef = new Reference(baseUri);
+ final Reference relativeRef = new Reference(baseRef, relativeUri);
+ final Reference absoluteRef = relativeRef.getTargetRef();
+ assertEquals(expectedAbsoluteUri, absoluteRef.toString());
+ }
+
+ /**
+ * Test the relativization of absolute references
+ *
+ * @param baseUri
+ * @param absoluteUri
+ * @param expectedRelativeUri
+ */
+ private void testRef2(String baseUri, String absoluteUri,
+ String expectedRelativeUri) {
+ final Reference baseRef = new Reference(baseUri);
+ final Reference absoluteRef = new Reference(absoluteUri);
+ final Reference relativeRef = absoluteRef.getRelativeRef(baseRef);
+ assertEquals(expectedRelativeUri, relativeRef.toString());
+ }
+
+ /**
+ * Test the toString method with or without query/fragment
+ *
+ * @param reference
+ * @param query
+ * @param fragment
+ * @param toString
+ */
+ private void testRef3(String reference, boolean query, boolean fragment,
+ String toString) {
+ final Reference ref = new Reference(reference);
+ assertEquals(ref.toString(query, fragment), toString);
+ }
+
+ /**
+ * Test the behaviour of several getters upon a Reference object.
+ */
+ private void testRef4(Reference reference, String scheme, String authority,
+ String path, String remainingPart, String toString,
+ String targetRef, String query, String relativePart) {
+ assertEquals(reference.getScheme(), scheme);
+ assertEquals(reference.getAuthority(), authority);
+ assertEquals(reference.getPath(), path);
+ assertEquals(reference.getRemainingPart(), remainingPart);
+ assertEquals(reference.toString(), toString);
+ assertEquals(reference.getTargetRef().toString(), targetRef);
+ assertEquals(reference.getQuery(), query);
+ assertEquals(reference.getRelativePart(), relativePart);
+ }
+
+ @Test
+ public void testRiap() {
+ Reference baseRef = new Reference("riap://component/exist/db/");
+ Reference ref = new Reference(baseRef, "something.xq");
+ assertEquals("riap://component/exist/db/something.xq", ref
+ .getTargetRef().toString());
+ }
+
+ /**
+ * Test scheme getting/setting.
+ */
+ @Test
+ public void testScheme() {
+ final Reference ref = getDefaultReference();
+ assertEquals(DEFAULT_SCHEME, ref.getScheme());
+ final String scheme = "https";
+ ref.setScheme(scheme);
+ assertEquals(scheme, ref.getScheme());
+ ref.setScheme(DEFAULT_SCHEME);
+ assertEquals(DEFAULT_SCHEME, ref.getScheme());
+ }
+
+ /**
+ * Test scheme specific part getting/setting.
+ */
+ @Test
+ public void testSchemeSpecificPart() {
+ final Reference ref = getDefaultReference();
+ String part = "//restlet.org";
+ assertEquals(part, ref.getSchemeSpecificPart());
+ part = "//restlet.net";
+ ref.setSchemeSpecificPart(part);
+ assertEquals(part, ref.getSchemeSpecificPart());
+ }
+
+ /**
+ * Test setting of the last segment.
+ */
+ @Test
+ public void testSetLastSegment() {
+ Reference ref = new Reference("http://localhost:1234");
+ ref.addSegment("test");
+ assertEquals("http://localhost:1234/test", ref.toString());
+
+ ref.setLastSegment("last");
+ assertEquals("http://localhost:1234/last", ref.toString());
+
+ ref = new Reference("http://localhost:1234");
+ ref.setLastSegment("last");
+ assertEquals("http://localhost:1234/last", ref.toString());
+
+ ref.setLastSegment("test");
+ assertEquals("http://localhost:1234/test", ref.toString());
+
+ ref.addSegment("last");
+ assertEquals("http://localhost:1234/test/last", ref.toString());
+ }
+
+ // TODO @Test
+ public void testTargetRef() {
+ Reference ref = new Reference(
+ "http://twitter.com?status=RT @gamasutra: Devil May Cry : Born Again http://www.gamasutra.com/view/feature/177267/");
+ Reference targetRef = new Reference(
+ new Reference(
+ "http://www.gamasutra.com/view/feature/177267/devil_may_cry_born_again.php"),
+ ref).getTargetRef();
+ assertEquals(
+ "http://twitter.com?status=RT%20@gamasutra:%20%20Devil%20May%20Cry%20:%20Born%20Again%20http:?status=RT%20@gamasutra:%20%20Devil%20May%20Cry%20:%20Born%20Again%20http://www.gamasutra.com/view/feature/177267/",
+ targetRef.toString());
+ }
+
+ /**
+ * Test references that are unequal.
+ */
+ @Test
+ public void testUnEquals() throws Exception {
+ final String uri1 = "http://restlet.org/";
+ final String uri2 = "http://restlet.net/";
+ final Reference ref1 = new Reference(uri1);
+ final Reference ref2 = new Reference(uri2);
+ assertFalse(ref1.equals(ref2));
+ assertFalse(ref1.equals(null));
+ }
+
+ @Test
+ public void testUserinfo() {
+ final Reference reference = new Reference("http://localhost:81");
+ // This format is depre. however we may prevent failures.
+ reference.setUserInfo("login:password");
+ assertEquals("login:password@localhost:81", reference.getAuthority());
+ assertEquals("localhost", reference.getHostDomain());
+ assertEquals(81, reference.getHostPort());
+ assertEquals("login:password", reference.getUserInfo());
+
+ reference.setHostDomain("[::1]");
+ assertEquals("login:password@[::1]:81", reference.getAuthority());
+ assertEquals("[::1]", reference.getHostDomain());
+ assertEquals(81, reference.getHostPort());
+ assertEquals("login:password", reference.getUserInfo());
+
+ reference.setHostDomain("www.example.com");
+ assertEquals("login:password@www.example.com:81",
+ reference.getAuthority());
+ assertEquals("www.example.com", reference.getHostDomain());
+ assertEquals(81, reference.getHostPort());
+ assertEquals("login:password", reference.getUserInfo());
+
+ reference.setHostPort(82);
+ assertEquals("login:password@www.example.com:82",
+ reference.getAuthority());
+ assertEquals("www.example.com", reference.getHostDomain());
+ assertEquals(82, reference.getHostPort());
+ assertEquals("login:password", reference.getUserInfo());
+
+ reference.setUserInfo("login");
+ assertEquals("login@www.example.com:82", reference.getAuthority());
+ assertEquals("www.example.com", reference.getHostDomain());
+ assertEquals(82, reference.getHostPort());
+ assertEquals("login", reference.getUserInfo());
+ }
+
+ @Test
+ public void testValidity() {
+ String uri = "http ://domain.tld/whatever/";
+ Reference ref = new Reference(uri);
+ assertEquals("http%20://domain.tld/whatever/", ref.toString());
+
+ uri = "file:///C|/wherever\\whatever.swf";
+ ref = new Reference(uri);
+ assertEquals("file:///C%7C/wherever%5Cwhatever.swf", ref.toString());
+ }
+
@Test
public void shouldFailWhenParsingMultiPortReference() {
Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference("http://192.168.1.1:1111:2222/"));
@@ -27,13 +748,19 @@ public void shouldFailWhenParsingMultiPortReference() {
"http://[192.168.0.1]vulndetector.com/",
"http://[normal.com@]vulndetector.com/",
"http://normal.com[user@vulndetector].com/",
- "http://normal.com[@]vulndetector.com/"})
+ "http://normal.com[@]vulndetector.com/"
+ })
public void shouldFailWhenParsingIncorrectHosts(String reference) {
Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference(reference));
}
@ParameterizedTest
- @ValueSource(strings = {"http://[0:0::vulndetector.com]:80", "http://[2001:db8::vulndetector.com]"})
+ @ValueSource(strings = {
+ "https://[1:2:3:4:5:6:7:8:9]",
+ "https://[1::1::1]",
+ "https://[1:2:3:]",
+ "https://[ffff::127.0.0.4000]",
+ "http://[0:0::vulndetector.com]:80", "http://[2001:db8::vulndetector.com]"})
public void shouldFailWhenParsingIncorrectIPv6Hosts(String reference) {
Assertions.assertThrows(IllegalArgumentException.class, () -> new Reference(reference));
}