users@jersey.java.net

Re: [Jersey] UriComponent.validate does not allow brackets []?

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Wed, 23 Jul 2008 10:22:22 +0200

Martin Grotzke wrote:
> Hi Paul,
>
> thanx for your feedback! Now I changed the URI for my test to use
> URLCodec and it works :)
>
> "/products?q=foo&fq=price:" + new URLCodec().encode( "[10 TO 100]" );
>

You can also use UriBuilder:

   UriBuilder.fromUri("/products").
     queryParam("q", "foo").
     queryParam("fq", "price:[10 TO 100]").
     build();

or

   UriBuilder.fromUri("/products").
     replaceQueryParams("q=foo&fq=price:[10 TO 100]").
     build();

Paul.

> Cheers,
> Martin
>
>
> On Tue, 2008-07-22 at 13:19 +0200, Paul Sandoz wrote:
>> Martin Grotzke wrote:
>>> Hi,
>>>
>>> we have a resource method that accepts some query parameter named fq
>>> (filter query). The fq param accepts ranges for e.g. a price filter, so
>>> that the value for the fq param might be "price:[160%20TO%20200]".
>>>
>> According to the URI ABNF:
>>
>> sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
>> / "*" / "+" / "," / ";" / "="
>>
>> unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
>> pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
>> query = *( pchar / "/" / "?" )
>>
>> '[' and ']' characters are not valid characters of a URI query component.
>>
>>
>>> When a client performs a request with such a param value, the
>>> UriComponent.validate says that this is not valid:
>>>
>>> [ERROR] 17 Jul 2008 15:50:45,166 btpool0-1 com.sun.jersey.spi.spring.container.servlet.SpringServlet.service:
>>> Caught exception.
>>>
>>> java.lang.IllegalArgumentException: The string 'q=foo&fq=price:[160%20TO%20200]' for the URI component QUERY contains an invalid character, '[', at index 15
>>> at com.sun.jersey.api.uri.UriComponent.validate(UriComponent.java:95)
>>> at com.sun.jersey.impl.uri.UriBuilderImpl.encode(UriBuilderImpl.java:353)
>>> at com.sun.jersey.impl.uri.UriBuilderImpl.replaceQueryParams(UriBuilderImpl.java:286)
>>> at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:273)
>>>
>>> I think this should be valid, even UriComponent.decode handles this
>>> correctly.
>>>
>> The JavaDoc states:
>>
>> /**
>> * Decodes characters of a string that are percent-encoded octets using
>> * UTF-8 decoding (if needed).
>> * <p>
>> * It is assumed that the string is valid according to an (unspecified)
>> URI
>> * component type. If a sequence of contiguous percent-encoded octets is
>> * not a valid UTF-8 character then the octets are replaced with '\uFFFD'.
>> * <p>
>> * If the URI component is of type HOST then any "%" found between "[]" is
>> * left alone. It is an IPv6 literal with a scope_id.
>> * <p>
>> * @param s the string to be decoded.
>> * @param t the URI component type, may be null.
>> * @return the decoded string.
>> * @throws IllegalArgumentException if a malformed percent-encoded octet is
>> * detected
>> */
>>
>> Paul.
>>
>>> One possible patch I can think of is in
>>> UriComponent.creatingEncodingTables:
>>>
>>> Index: src/api/com/sun/jersey/api/uri/UriComponent.java
>>> ===================================================================
>>> --- src/api/com/sun/jersey/api/uri/UriComponent.java (revision 1166)
>>> +++ src/api/com/sun/jersey/api/uri/UriComponent.java (working copy)
>>> @@ -243,6 +243,8 @@
>>> tables[Type.PATH.ordinal()] = creatingEncodingTable(l);
>>>
>>> l.add("?");
>>> + l.add("[");
>>> + l.add("]");
>>>
>>> tables[Type.QUERY.ordinal()] = creatingEncodingTable(l);
>>> tables[Type.FRAGMENT.ordinal()] = tables[Type.QUERY.ordinal()];
>>>
>>> This test goes through then:
>>>
>>> Index: test/com/sun/jersey/impl/UriComponentValidateTest.java
>>> ===================================================================
>>> --- test/com/sun/jersey/impl/UriComponentValidateTest.java (revision 1166)
>>> +++ test/com/sun/jersey/impl/UriComponentValidateTest.java (working copy)
>>> @@ -54,4 +54,8 @@
>>> assertEquals(true, UriComponent.valid("/x20y", UriComponent.Type.PATH));
>>> assertEquals(true, UriComponent.valid("/x%20y", UriComponent.Type.PATH));
>>> }
>>> +
>>> + public void testQuery() {
>>> + assertEquals(true, UriComponent.valid("fq=price:[1%20TO%20100]", UriComponent.Type.QUERY));
>>> + }
>>> }
>>>
>>> Please notice that I took this diff in a branch, so line numbers might
>>> be wrong.
>>>
>>> Any thoughts on this?
>>>
>>> Thanx && cheers,
>>> Martin
>>>
>>>
>

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109