users@jersey.java.net

Re: [Jersey] handling urls with {

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 09 Mar 2009 14:07:20 +0100

HI Bill, James,

I definitely think there is a bug, but i need some more information,
to better understand what is going on. I do not understand where the
URIs are getting built, so some help identifying that area will help
me understand how to fix things.

I think i can make some guesses. The method:

   UriComponent.contextualEncode("start=^%|{rndstart}",
UriComponent.Type.QUERY, true)

is utilized by the UriBuilder. The "true" means that the string
contains templates and the braces should not be encoded because they
will be needed later, so that template names can be replaced with
template values, when
the URI is built. However, when the URI is built with no templates
declared, for example:

   UriBuilder.fromUri(...).queryParam("start", "%|{rndstart}").build();

   https://jsr311.dev.java.net/nonav/javadoc/javax/ws/rs/core/UriBuilder.html
#build(java.lang.Object...)

Note that i think we have specified the build method to be too strict
since it rules out the building of URIs with legitimate templates that
are not meant to be replaced by template values.

It appears the error is occurring before the request is passed off to
the Jersey Web application, implying it is in the ServletContainer
(see code at end of email) which uses UriBuilder.

Paul.



     @Override
     public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
         /**
          * There is an annoying edge case where the service method is
          * invoked for the case when the URI is equal to the
deployment URL
          * minus the '/', for example http://locahost:8080/HelloWorldWebApp
          */
         if (request.getPathInfo() != null &&
                 request.getPathInfo().equals("/") && !
request.getRequestURI().endsWith("/")) {
             response.setStatus(404);
             return;
         }

         /**
          * The HttpServletRequest.getRequestURL() contains the
complete URI
          * minus the query and fragment components.
          */
         UriBuilder absoluteUriBuilder = UriBuilder.fromUri(
                 request.getRequestURL().toString());

         /**
          * The HttpServletRequest.getPathInfo() and
          * HttpServletRequest.getServletPath() are in decoded form.
          *
          * On some servlet implementations the getPathInfo() removed
          * contiguous '/' characters. This is problematic if URIs
          * are embedded, for example as the last path segment.
          * We need to work around this and not use getPathInfo
          * for the decodedPath.
          */
         final String decodedBasePath = (request.getPathInfo() != null)
                 ? request.getContextPath() + request.getServletPath()
+ "/"
                 : request.getContextPath() + "/";

         final String encodedBasePath =
UriComponent.encode(decodedBasePath,
                 UriComponent.Type.PATH);

         if (!decodedBasePath.equals(encodedBasePath)) {
             throw new ContainerException("The servlet context path
and/or the " +
                     "servlet path contain characters that are percent
enocded");
         }

         final URI baseUri =
absoluteUriBuilder.replacePath(encodedBasePath).
                 build();

         String queryParameters = request.getQueryString();
         if (queryParameters == null) {
             queryParameters = "";
         }

         final URI requestUri =
absoluteUriBuilder.replacePath(request.getRequestURI()).
                 replaceQuery(queryParameters).
                 build();

         service(baseUri, requestUri, request, response);
     }


On Mar 3, 2009, at 10:52 PM, James Strachan wrote:

> 2009/3/3 Bill de hOra <bill_at_dehora.net>:
>> Jersey (1.0.2) throws a java.net.URISyntaxException when it
>> encounters a URL
>> with a {. Trying an ExceptionMapper does not catch
>> UriBuilderException (t
>> appears that the exception is thrown before the ExceptionMappers
>> are in
>> place).
>>
>> The exception looks like this
>>
>> [[[
>> Caused by: java.net.URISyntaxException: Illegal character in query
>> at index
>> 56:
>> http://192.168.3.200:8080/svc/data/user?fmt=pbuf&start=$
>> {rndstart}&count=50
>> at java.net.URI$Parser.fail(URI.java:2809)
>> at java.net.URI$Parser.checkChars(URI.java:2982)
>> at java.net.URI$Parser.parseHierarchical(URI.java:3072)
>> at java.net.URI$Parser.parse(URI.java:3014)
>> at java.net.URI.<init>(URI.java:578)
>> ]]]
>>
>> I thought it was something goofy in java.net.URI, but debugging
>> this call it
>> seems like there is a method in UriComponent class that is not fully
>> encoding the query string, ie calling,
>>
>> UriComponent.contextualEncode("start=^%|{rndstart}",
>> UriComponent.Type.QUERY, true)
>>
>> returns start=%5E%25%7C{rndstart} leaving '{', '}' not encoded.
>>
>> Does anyone else agrees this is a bug? If so I'll file a ticket and
>> submit a
>> patch anon.
>
> Spooky I've just hit this too today Bill! :) Yeah it looks like a
> bug to me.
>
> BTW the main reason I hit it is the user navigable auto-generated HTML
> representation of the REST API tends to use expressions like {id}
> inside the URIs. More background here..
>
> http://n2.nabble.com/-PATCH--to-allow-the-API-of-RESTful-services-to-be-rendered-using--hierarchial-Implicit-Views-tt2353447.html
>
> --
> James
> -------
> http://macstrac.blogspot.com/
>
> Open Source Integration
> http://fusesource.com/
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>