Reputation: 5656
I have the following Uri: http://host/path?param1=1¶m2[]=2¶m3[1]=3
uri.getQueryParameterNames() returns an array with values ["param1", "param2[]", "param3[1]"] which is expected.
But when passing this values into getQueryParameter I get: uri.getQueryParameter("param1") == "1" uri.getQueryParameter("param2[]") == null uri.getQueryParameter("param3[1]") == null
I have tried passing the name of the parameter without the bracket part and it also does not work. Also calling getQueryParameters() doesn't work.
Thank you for help!
Upvotes: 3
Views: 10699
Reputation: 1030
I was facing the same problem. Thanks to MH.'s answer I found a quick solution.
Instead of using Uri.getQueryParameter()
, use UrlQuerySanitizer.getParameterList()
This method, encode the necessary parameters and get the values correctly.
Here's a quick example:
HashMap<String,String> queryMap = new HashMap<>();
UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(urlString);
List<UrlQuerySanitizer.ParameterValuePair> sanitizerParameterList = sanitizer.getParameterList();
for (UrlQuerySanitizer.ParameterValuePair valuePair : sanitizerParameterList) {
queryMap.put(valuePair.mParameter, valuePair.mValue);
}
Upvotes: 2
Reputation: 45493
As stated in the documentation, Uri
builds and parses URI references which conform to RFC 2396.
If you scroll down to section 2.4.3 in the specification, you'll find the following:
Other characters are excluded because gateways and other transport
agents are known to sometimes modify such characters, or they are
used as delimiters.
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "
"`Data corresponding to excluded characters must be escaped in order to be properly represented within a URI.
From a code point of view, Uri
has a private method that determines whether a character is allowed or not - if it is not allowed, it will be encoded. In theory, this should return false
for brackets and other special characters.
/**
* Returns true if the given character is allowed.
*
* @param c character to check
* @param allow characters to allow
* @return true if the character is allowed or false if it should be
* encoded
*/
private static boolean isAllowed(char c, String allow) {
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| "_-!.~'()*".indexOf(c) != NOT_FOUND
|| (allow != null && allow.indexOf(c) != NOT_FOUND);
}
That being said, now we get to the interesting part. It appears Uri.parse()
is rather 'lazy' because it doesn't actually encode the uri you give it. In your scenario, you were probably constructing the Uri
by calling:
Uri uri = Uri.parse("http://host/path?param1=1¶m2[]=2¶m3[1]=3");
When you then start calling getQueryParameter()
on the resulting Uri
, what happens is that the backing data (a String
) is 'unencoded', but the parameter name you supply to these methods does get encoded. For example:
uri.getQueryParameter("param2[]")
Is in fact:
uri.getQueryParameter("param2%5B%5D")
An a query parameter with key param2%5B%5D
is obviously not present in the Uri
.
The solution is to make sure the brackets are escaped in the first place, or to use the Uri.Builder
. For example:
Uri uri = Uri.parse("http://host/path").buildUpon()
.appendQueryParameter("param1", "1")
.appendQueryParameter("param2[]", "2")
.appendQueryParameter("param3[1]", "3")
.build();
This will lead to the following underlying uri:
http://host/path?param1=1¶m2%5B%5D=2¶m3%5B1%5D=3
You can then call uri.getQueryParameter("param3[1]")
without a problem: it will return 3
.
Edit: I take back what I said about Uri.parse()
being lazy. It's intended to be this way. As is clearly mentioned in the Javadoc:
Creates a Uri which parses the given encoded URI string.
In other words: the string you supply for parsing should already be encoded properly.
Upvotes: 15