[java-shib-shared] 02/02: Add some additional query string methods to URISupport.

Brent Putman putmanb at georgetown.edu
Fri Mar 21 20:25:01 UTC 2025


This is an automated email from the git hooks/post-receive script.

putmanb pushed a commit to branch main
in repository java-shib-shared.

View the commit online:
http://git.shibboleth.net/view/?p=java-shib-shared.git;a=commit;h=50f2ecdee8edd2af24da0a7d5d3fd8c5b698af07

commit 50f2ecdee8edd2af24da0a7d5d3fd8c5b698af07
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Fri Mar 21 16:22:39 2025 -0400

    Add some additional query string methods to URISupport.
---
 .../java/net/shibboleth/shared/net/URISupport.java | 54 +++++++++++++++-
 .../net/shibboleth/shared/net/URISupportTest.java  | 74 ++++++++++++++++++++++
 2 files changed, 125 insertions(+), 3 deletions(-)

diff --git a/shib-networking/src/main/java/net/shibboleth/shared/net/URISupport.java b/shib-networking/src/main/java/net/shibboleth/shared/net/URISupport.java
index 99389832..04ddac3e 100644
--- a/shib-networking/src/main/java/net/shibboleth/shared/net/URISupport.java
+++ b/shib-networking/src/main/java/net/shibboleth/shared/net/URISupport.java
@@ -24,6 +24,8 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -294,6 +296,33 @@ public final class URISupport {
         
         return null;
     }
+    
+    /**
+     * Get all raw (i.e.RFC-3968 encoded) query string components with the specified parameter name. This method
+     * assumes the common query string format of one or more 'paramName=paramValue' pairs separated by '&'.
+     * Parameters without values will be represented in the returned map as a key associated with
+     * the value <code>null</code>.
+     * 
+     * The parameter name match will be performed using the URL decoded forms of both the specified
+     * <code>paramName</code> and the candidate query string value.
+     * 
+     * @param queryString the URL encoded HTTP URL query string
+     * @param paramName the URL decoded name of the parameter to find
+     * @return the found component, or null if query string or param name is null/empty or the parameter is not found
+     */
+    @Nonnull @Live public static List<Pair<String, String>> getRawQueryStringParameters(
+            @Nullable final String queryString,
+            @Nullable final String paramName) {
+        
+        final String paramNameTrimmed = StringSupport.trimOrNull(paramName);
+        if (paramNameTrimmed == null) {
+            return CollectionSupport.emptyList();
+        }
+
+        return parseQueryString(queryString, false, false).stream()
+                .filter(p -> Objects.equals(doURLDecode(paramNameTrimmed), doURLDecode(p.getFirst())))
+                .collect(CollectionSupport.nonnullCollector(Collectors.toList())).get();
+    }
 
     /**
      * Parses a RFC-3968 encoded query string in to a set of name/value pairs. This method assumes the common query
@@ -305,7 +334,25 @@ public final class URISupport {
      * 
      * @return the parameters from the query string, never null
      */
-    @Nonnull @Live public static List<Pair<String, String>> parseQueryString(final String queryString) {
+    @Nonnull @Live public static List<Pair<String, String>> parseQueryString(@Nullable final String queryString) {
+        return parseQueryString(queryString, true, true);
+    }
+
+    /**
+     * Parses a RFC-3968 encoded query string in to a set of name/value pairs. This method assumes the common query
+     * string format of one or more 'paramName=paramValue' pairs separate by '&'. URL decoding of parameter names and values
+     * is determined by the relevant arguments. Parameters without values will be represented in the returned map as a key associated with
+     * the value <code>null</code>.
+     * 
+     * @param queryString URL encoded query string
+     * @param decodeName whether the parameter names should be URL decoded in the returned list
+     * @param decodeValue whether the parameter values should be URL decoded in the returned list
+     * 
+     * @return the parameters from the query string, never null
+     */
+    @Nonnull @Live public static List<Pair<String, String>> parseQueryString(@Nullable final String queryString,
+            final boolean decodeName, final boolean decodeValue) {
+
         final String trimmedQuery = trimOrNullQuery(queryString);
         if (trimmedQuery == null) {
             return new LazyList<>();
@@ -317,9 +364,10 @@ public final class URISupport {
         for (final String paramPair : paramPairs) {
             param = paramPair.split("=");
             if (param.length == 1) {
-                queryParams.add(new Pair<>(doURLDecode(param[0]), (String) null));
+                queryParams.add(new Pair<>(decodeName ? doURLDecode(param[0]) : param[0], (String) null));
             } else {
-                queryParams.add(new Pair<>(doURLDecode(param[0]), doURLDecode(param[1])));
+                queryParams.add(new Pair<>(decodeName ? doURLDecode(param[0]) : param[0],
+                        decodeValue ? doURLDecode(param[1]) : param[1]));
             }
         }
 
diff --git a/shib-networking/src/test/java/net/shibboleth/shared/net/URISupportTest.java b/shib-networking/src/test/java/net/shibboleth/shared/net/URISupportTest.java
index f1486f9c..90fdc099 100644
--- a/shib-networking/src/test/java/net/shibboleth/shared/net/URISupportTest.java
+++ b/shib-networking/src/test/java/net/shibboleth/shared/net/URISupportTest.java
@@ -244,4 +244,78 @@ public class URISupportTest {
         Assert.assertTrue(params.contains(new Pair<>("paramName=", "paramValue&")));
         Assert.assertTrue(params.contains(new Pair<>("paramName2", null)));
     }
+    
+    @Test public void testParseQueryStringWithArgs() {
+        List<Pair<String, String>> params = URISupport.parseQueryString(null, false, false);
+        Assert.assertTrue(params.isEmpty());
+
+        params = URISupport.parseQueryString("");
+        Assert.assertTrue(params.isEmpty());
+
+        String queryString = "paramName1=paramValue1&paramName%3D=paramValue%26&paramName%32";
+        params = URISupport.parseQueryString(queryString, false, false);
+        Assert.assertTrue(params.contains(new Pair<>("paramName1", "paramValue1")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName%3D", "paramValue%26")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName%32", null)));
+
+        queryString = "paramName1=paramValue1&paramName%3D=paramValue%26&paramName%32";
+        params = URISupport.parseQueryString(queryString, true, false);
+        Assert.assertTrue(params.contains(new Pair<>("paramName1", "paramValue1")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName=", "paramValue%26")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName2", null)));
+
+        queryString = "paramName1=paramValue1&paramName%3D=paramValue%26&paramName%32";
+        params = URISupport.parseQueryString(queryString, false, true);
+        Assert.assertTrue(params.contains(new Pair<>("paramName1", "paramValue1")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName%3D", "paramValue&")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName%32", null)));
+
+        queryString = "paramName1=paramValue1&paramName%3D=paramValue%26&paramName%32";
+        params = URISupport.parseQueryString(queryString, true, true);
+        Assert.assertTrue(params.contains(new Pair<>("paramName1", "paramValue1")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName=", "paramValue&")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName2", null)));
+
+        queryString = "?paramName1=paramValue1&paramName%3D=paramValue%26&paramName%32#";
+        params = URISupport.parseQueryString(queryString, true, true);
+        Assert.assertTrue(params.contains(new Pair<>("paramName1", "paramValue1")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName=", "paramValue&")));
+        Assert.assertTrue(params.contains(new Pair<>("paramName2", null)));
+    }
+    
+    @Test public void testGetRawQueryStringParameters() {
+        List<Pair<String, String>> params = URISupport.getRawQueryStringParameters(null, "Foo");
+        Assert.assertTrue(params.isEmpty());
+
+        params = URISupport.getRawQueryStringParameters("", "Foo");
+        Assert.assertTrue(params.isEmpty());
+        
+        params = URISupport.getRawQueryStringParameters("Foo=123", "");
+        Assert.assertTrue(params.isEmpty());
+        
+        String queryString = "XXX=blah&Foo=123&Foo=456&XXX=blah&Foo=789";
+        params = URISupport.getRawQueryStringParameters(queryString, "Foo");
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "123")));
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "456")));
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "789")));
+
+        queryString = "XXX=blah&Foo=123&Foo=456&XXX=blah&Foo=789";
+        params = URISupport.getRawQueryStringParameters(queryString, "F%6F%6F");
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "123")));
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "456")));
+        Assert.assertTrue(params.contains(new Pair<>("Foo", "789")));
+        
+        queryString = "XXX=blah&F%6Fo=1%323&F%6F%6F=4%356&XXX=blah&Fo%6F=7%389";
+        params = URISupport.getRawQueryStringParameters(queryString, "Foo");
+        Assert.assertTrue(params.contains(new Pair<>("F%6Fo", "1%323")));
+        Assert.assertTrue(params.contains(new Pair<>("F%6F%6F", "4%356")));
+        Assert.assertTrue(params.contains(new Pair<>("Fo%6F", "7%389")));
+
+        queryString = "XXX=blah&F%6Fo=1%323&F%6F%6F=4%356&XXX=blah&Fo%6F=7%389";
+        params = URISupport.getRawQueryStringParameters(queryString, "F%6F%6F");
+        Assert.assertTrue(params.contains(new Pair<>("F%6Fo", "1%323")));
+        Assert.assertTrue(params.contains(new Pair<>("F%6F%6F", "4%356")));
+        Assert.assertTrue(params.contains(new Pair<>("Fo%6F", "7%389")));
+    }
+
 }
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list