users@jsr311.java.net

Re: Queries, UriBuilder.build(), UriBuilder.buildFromEncoded()

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Mon, 10 Jan 2011 09:30:31 +0100

Hi Sergey,

On Jan 7, 2011, at 6:14 PM, Sergey Beryozkin wrote:

> Hi Paul
>
> Many thanks for finding the time to reply and apologies for the the
> very late reply...
> I do believe what you're saying below makes sense to me :-), but I'm
> still not following why
>
> a '%' specified as part of queryParam() calls is not double-encoded;
> however when it is passed as part of replaceQuery() calls the it is
> double encoded. What I'm trying to say that irrespectively of how
> the query part of a given URI has been built, whether using say 5
> queryParam calls or using a single replaceQuery() call, the end
> result should be the same
>

I think you are conflating two things:

   1) the contextual encoding of literal characters; and

   2) the encoding of parameter values.

Calls to queryParam/replaceQuery are associated with 1 and calls to
build/buildFromEncoded are associated with 2.

Thus the following must produce equivalent URI values:

   1. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
"%20").build();
   2. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
"%20").buildFromEncoded();
   3. UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
%20").build();
   4. UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
%20").buildFromEncoded();

(i.e. like what Jersey does :-) )

The difference occurs when parameter names in queryParam/replaceQuery
and corresponding parameter values in build/buildFromEncoded are
declared.

The following:

   1. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
"{value}").build("%20");
   2. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
"{value}").buildFromEncoded("%20");
   3. UriBuilder.fromUri("http://localhost:
8080").replaceQuery("name={value}).build("%20");
   4. UriBuilder.fromUri("http://localhost:
8080").replaceQuery("name={value}).buildFromEncoded("%20");

Will output:

   1. http://localhost:8080?name=%2520
   2. http://localhost:8080?name=%20
   3. http://localhost:8080?name=%2520
   4. http://localhost:8080?name=%20

Hth,
Paul.

> Cheers, Sergey
>
> On Wed, Oct 20, 2010 at 9:17 AM, Paul Sandoz
> <Paul.Sandoz_at_oracle.com> wrote:
> Hi Sergey,
>
> The methods "build" and "buildFromEncoded" only apply to the
> parameter values passed to the method that replace parameter names
> declared in the strings the builder methods.
>
> The JavaDoc of the build method states:
>
> Build a URI, using the supplied values in order to replace any URI
> template parameters. Values are converted to String using their
> toString method and are then encoded to match the rules of the URI
> component to which they pertain. All '%' characters in the
> stringified values will be encoded.
>
> The JavaDoc of the buildFromEncoded method states:
>
> Build a URI. Any URI templates parameters will be replaced with the
> supplied values in order. Values are converted to String using their
> toString method and are then encoded to match the rules of the URI
> component to which they pertain. All % characters in the stringified
> values that are not followed by two hexadecimal numbers will be
> encoded.
>
>
> Note also the JavaDoc of the UriBuilder class:
>
> Builder methods perform contextual encoding of characters not
> permitted in the corresponding URI component following the rules of
> the application/x-www-form-urlencoded media type for query
> parameters and RFC 3986 for all other components. Note that only
> characters not permitted in a particular component are subject to
> encoding so, e.g., a path supplied to one of the path methods may
> contain matrix parameters or multiple path segments since the
> separators are legal characters and will not be encoded. Percent
> encoded values are also recognized where allowed and will not be
> double encoded.
>
> Hope that helps,
> Paul.
>
> On Sep 23, 2010, at 10:53 PM, Sergey Beryozkin wrote:
>
>> Just a follow-up.
>>
>> It seems wrong that UriBuilder.build() will double-encode a '%' if
>> we have used replaceQuery(), i.e, provided a query string, but
>> won't double encode if we built it one by one,
>>
>> Comments ?
>>
>> Sergey
>>
>> On Thu, Sep 23, 2010 at 9:37 PM, Sergey Beryozkin <sberyozkin_at_gmail.com
>> > wrote:
>> Hello -
>>
>> Can someone please give me an authoritative answer about the
>> differences between UriBuilder.build() and
>> UriBuilder.buildFromEncoded() and they way they have to deal with
>> quieries containing percent-encoded data.
>>
>> 1. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
>> "%20").build();
>> 2. UriBuilder.fromUri("http://localhost:8080").queryParam("name",
>> "%20").buildFromEncoded();
>> 3. UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
>> %20").build();
>> 4. UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
>> %20").buildFromEncoded();
>>
>> I'm seriously confused. Specifically, it seems totally wrong that
>> the way '%' is dealt with depends on how a query is built (i.e,
>> from individual parameters or from a ready string).
>>
>> I'd appreciate if you can give the answers to 1-4 above.
>> Besides, what is the way in UriBuilder to have a literal '%' passed
>> on ? Example, should it be :
>>
>> UriBuilder.fromUri("http://localhost:8080").queryParam("name",
>> "%2520").buildFromEncoded();
>>
>> or
>>
>> UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
>> %2520").build();
>>
>> How about
>>
>> UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
>> %2520").buildFromEncoded();
>>
>> versus
>>
>> UriBuilder.fromUri("http://localhost:8080").replaceQuery("name=
>> %2520").build();
>>
>> Thanks !
>>
>> Sergey
>>
>
>