users@jersey.java.net

Re: [Jersey] Trailing slash redirect

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 11 Feb 2010 20:59:27 +0100

On Feb 11, 2010, at 8:56 PM, Paul Sandoz wrote:

>
> On Feb 11, 2010, at 7:20 PM, Chris Carrier wrote:
>
>> OK I turned those on and got a bit more logging.
>
> There is no Jersey logging in the log output you sent so i suspect
> you did not configure things correctly in the init parameters of the
> web.xml.
>

To be clear i mean no Jersey logging related to the options of
enabling tracing and logging of requests and responses i described in
a previous email.

Paul.

> Paul.
>
>
>> Not sure if it'll be
>> very helpful. So this is with FEATURE_REDIRECT set to true and a
>> path
>> on my GET like:
>>
>> @GET
>> @Path("/{id}/")
>>
>> It's weird looking because it seems to forward correctly to add a
>> slash at the end but still returns a 404. I can send another trace
>> with redirect turned off and no slash at the end of my Path if you
>> want. It's funny if I have the start at the end of the Path the
>> output looks very similar except no exception. It just adds the
>> slash
>> to the end and then finds my endpoint.
>>
>>
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.servlet.SpringServlet getContext
>> INFO: Using default applicationContext
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, jaxbContextResolver, of type
>> com.something.config.JaxbContextResolver as a provider class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, somethingExceptionMapper, of type
>> com.something.config.SomethingExceptionMapper as a provider class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, somethingLinkEndpoint, of type
>> com.something.something.SomethingLinkEndpoint as a root resource
>> class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, followSomethingEndpoint, of type
>> com.something.something.FollowSomethingEndpoint as a root resource
>> class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, somethingSomethingEndpoint, of type
>> com.something.something.SomethingSomethingEndpoint as a root resource
>> class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.spi.spring.container.SpringComponentProviderFactory
>> register
>> INFO: Registering Spring bean, followSomethingEndpoint, of type
>> com.something.something.FollowSomethingFastEndpoint as a root
>> resource
>> class
>> Feb 11, 2010 10:09:27 AM
>> com.sun.jersey.server.impl.application.WebApplicationImpl initiate
>> INFO: Initiating Jersey application, version 'Jersey: 1.1.5
>> 01/20/2010 04:04 PM'
>> 2010-02-11 10:09:27,682 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'jaxbContextResolver'
>> 2010-02-11 10:09:27,758 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'somethingExceptionMapper'
>> Feb 11, 2010 10:09:28 AM
>> com.sun.jersey.core.spi.component.ProviderServices getInstances
>> SEVERE: The class true could not be found. This class is ignored.
>> Feb 11, 2010 10:09:28 AM
>> com.sun.jersey.core.spi.component.ProviderServices getInstances
>> SEVERE: The class true could not be found. This class is ignored.
>> 2010-02-11 10:09:28,391 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'somethingLinkEndpoint'
>> 2010-02-11 10:09:28,395 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'followSomethingEndpoint'
>> 2010-02-11 10:09:28,397 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'somethingSomethingEndpoint'
>> 2010-02-11 10:09:28,399 DEBUG
>> org
>> .springframework.beans.factory.support.DefaultListableBeanFactory:
>> 214 Returning
>> cached instance of singleton bean 'followSomethingEndpoint'
>> 3937 [main] INFO org.mortbay.log - Started
>> SocketConnector_at_0.0.0.0:8050
>> 2010-02-11 10:09:32,733 DEBUG org.springframework.web.context.request.RequestContextListener:69
>> Bound
>> request context to thread: GET
>> /something/something-link/1.0/json/rK3dgK0g5 HTTP/1.1
>> Host: admin.localhost:8050
>> Connection: Keep-Alive
>> User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5)
>>
>>
>> 2010-02-11 10:09:32,736 DEBUG org.springframework.web.context.request.RequestContextListener:89
>> Cleared
>> thread-bound request context: GET
>> /something/something-link/1.0/json/rK3dgK0g5 HTTP/1.1
>> Host: admin.localhost:8050
>> Connection: Keep-Alive
>> User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5)
>>
>>
>> 2010-02-11 10:09:32,743 DEBUG org.springframework.web.context.request.RequestContextListener:69
>> Bound
>> request context to thread: GET
>> /something/something-link/1.0/json/rK3dgK0g5/ HTTP/1.1
>> Host: admin.localhost:8050
>> Connection: Keep-Alive
>> User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5)
>>
>>
>> Feb 11, 2010 10:09:32 AM
>> com.sun.jersey.spi.container.ContainerResponse traceException
>> INFO: Mapped exception to response: 404 (Not Found)
>> com.sun.jersey.api.NotFoundException
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl._handleRequest(WebApplicationImpl.java:991)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl.handleRequest(WebApplicationImpl.java:941)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl.handleRequest(WebApplicationImpl.java:932)
>> at
>> com
>> .sun
>> .jersey
>> .spi.container.servlet.WebComponent.service(WebComponent.java:384)
>> at
>> com
>> .sun
>> .jersey
>> .spi
>> .container.servlet.ServletContainer.service(ServletContainer.java:
>> 451)
>> at
>> com
>> .sun
>> .jersey
>> .spi
>> .container.servlet.ServletContainer.service(ServletContainer.java:
>> 632)
>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
>> at
>> org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:
>> 502)
>> at
>> org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:
>> 380)
>> at
>> org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:
>> 765)
>> at
>> org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:
>> 152)
>> at org.mortbay.jetty.Server.handle(Server.java:324)
>> at
>> org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:
>> 535)
>> at org.mortbay.jetty.HttpConnection
>> $RequestHandler.headerComplete(HttpConnection.java:865)
>> at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
>> at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
>> at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
>> at org.mortbay.jetty.bio.SocketConnector
>> $Connection.run(SocketConnector.java:228)
>> at org.mortbay.thread.QueuedThreadPool
>> $PoolThread.run(QueuedThreadPool.java:520)
>> 2010-02-11 10:09:32,905 DEBUG org.springframework.web.context.request.RequestContextListener:89
>> Cleared
>> thread-bound request context: GET
>> /something/something-link/1.0/json/rK3dgK0g5/ HTTP/1.1
>> Host: admin.localhost:8050
>> Connection: Keep-Alive
>> User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5)
>>
>>
>> On Thu, Feb 11, 2010 at 9:52 AM, Paul Sandoz <Paul.Sandoz_at_sun.com>
>> wrote:
>>> Hi Chris,
>>>
>>> Two things to help throw more light on this issue:
>>>
>>> 1) Set tracing to true:
>>>
>>> https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/core/ResourceConfig.html
>>> #FEATURE_TRACE
>>>
>>> 2) Set request and response logging on:
>>>
>>> https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/container/filter/LoggingFilter.html
>>>
>>> Feel free to send the output privately if public disclosure is an
>>> issue.
>>> And, if i still cannot work out what is wrong from the logging
>>> output then a
>>> reproducible test case will be most appreciated so i can better
>>> work out
>>> what is going wrong.
>>>
>>>
>>> On Feb 11, 2010, at 6:44 PM, Chris Carrier wrote:
>>>
>>>> My Jersey dependencies are:
>>>>
>>>> <!--Jersey-->
>>>> <dependency>
>>>> <groupId>com.sun.jersey</groupId>
>>>> <artifactId>jersey-bundle</artifactId>
>>>> <version>1.1.5</version>
>>>> </dependency>
>>>> <dependency>
>>>> <groupId>com.sun.jersey.contribs</groupId>
>>>> <artifactId>jersey-spring</artifactId>
>>>> <version>1.1.5</version>
>>>> </dependency>
>>>>
>>>> I'm using the bundle dependency because of issues I ran into with
>>>> the
>>>> META-INF/services directory clashing across dependencies (I could
>>>> also
>>>> fix this with the Maven shade plugin i think).
>>>
>>> Correct, and make sure you use the ServicesResourceTransformer to
>>> merge
>>> META-INF service files.
>>>
>>> Paul.
>>>
>>>> When I remove the star
>>>> I am left with a class level Path that looks like:
>>>>
>>>> @Path("/some/path/{version}/json/")
>>>>
>>>> And my GET like:
>>>>
>>>> @GET
>>>> @Path("/{id}/")
>>>>
>>>> But my tests then fail. And if i try without trailing slash
>>>> redirect
>>>> with a path like:
>>>>
>>>> @GET
>>>> @Path("/{id}")
>>>>
>>>> They also fail. The only way I can get GETs without trailing
>>>> slashes
>>>> to work is with the path i mentioned before:
>>>>
>>>> @GET
>>>> @Path("/{id}/*")
>>>>
>>>> And trailing slash redirect turned on.
>>>>
>>>> Chris
>>>>
>>>> On Thu, Feb 11, 2010 at 9:31 AM, Paul Sandoz
>>>> <Paul.Sandoz_at_sun.com> wrote:
>>>>>
>>>>> On Feb 11, 2010, at 6:06 PM, Chris Carrier wrote:
>>>>>
>>>>>> I seemed to have found a solution by messing with my Path. If I
>>>>>> annotate my GETs with a Path like:
>>>>>>
>>>>>> @Path("/{key}/*")
>>>>>>
>>>>>> Where before i just had:
>>>>>>
>>>>>> @Path("/{key}")
>>>>>>
>>>>>
>>>>> Not sure what is going on here as the '*' character should be
>>>>> considered
>>>>> a
>>>>> literal character that is part of the path and should not have
>>>>> the same
>>>>> syntax as that defined for regular expressions. Although that
>>>>> could be a
>>>>> bug
>>>>> in the template to regex convertor...
>>>>>
>>>>> It would help if i knew what version of Jersey you are using.
>>>>>
>>>>> In any case the @Path("/{key}/") should work as documented when
>>>>> FEATURE_REDIRECT is declared:
>>>>>
>>>>>
>>>>> https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/core/ResourceConfig.html
>>>>> #FEATURE_REDIRECT
>>>>>
>>>>> And if that value is false and you have @Path("/{key}") then it
>>>>> should
>>>>> match
>>>>> with or without a '/' present at the end of the request URL path.
>>>>>
>>>>>
>>>>>> It works. I'm not sure why i need the star at the end but that
>>>>>> seems
>>>>>> to fix it. Is that expected behavior?
>>>>>
>>>>> No.
>>>>>
>>>>>
>>>>>
>>>>>> As for the POST issue it must
>>>>>> be my client. I'm using Wiztools (Rest Client) from google
>>>>>> tools. It
>>>>>> must auto redirect even on POSTs.
>>>>>>
>>>>>
>>>>> OK.
>>>>>
>>>>>
>>>>>> It would be ideal if I didn't have this 'magic" path pattern
>>>>>> but as
>>>>>> long as it works I don't have too much to complain about. If you
>>>>>> still want to see a project that shows this behavior I could
>>>>>> pretty
>>>>>> easily strip down our code to a simple endpoint and test and
>>>>>> send it
>>>>>> over.
>>>>>>
>>>>>
>>>>> If it is something that does not take a lot of time for you to
>>>>> do then it
>>>>> would be most helpful as there might be a bug or two lurking here.
>>>>>
>>>>> Paul.
>>>>>
>>>>>
>>>>>> Chris
>>>>>>
>>>>>> On Thu, Feb 11, 2010 at 12:48 AM, Paul Sandoz <Paul.Sandoz_at_sun.com
>>>>>> >
>>>>>> wrote:
>>>>>>>
>>>>>>> Hi Chris,
>>>>>>>
>>>>>>> What version of Jersey are you using?
>>>>>>>
>>>>>>> The latest version of Jersey will work with or without a
>>>>>>> trailing '/'
>>>>>>> but
>>>>>>> by
>>>>>>> default no redirection will be performed. And you can enabled
>>>>>>> redirection
>>>>>>> as
>>>>>>> you have done with the FEATURE_REDIRECT property.
>>>>>>>
>>>>>>> I think there may be something wrong with your configuration.
>>>>>>> It is
>>>>>>> hard
>>>>>>> to
>>>>>>> tell with Jetty, Spring and Jersey in the mix what exactly is
>>>>>>> going
>>>>>>> wrong.
>>>>>>> Plus i do not know what client you are using.
>>>>>>>
>>>>>>> Note that redirection on temporary redirect responses are only
>>>>>>> meant to
>>>>>>> happen for GET and HEAD, not POST:
>>>>>>>
>>>>>>> http://greenbytes.de/tech/webdav/rfc2616.html#status.307
>>>>>>>
>>>>>>> If the 307 status code is received in response to a request
>>>>>>> other than
>>>>>>> GET
>>>>>>> or HEAD, the user agent MUST NOT
>>>>>>> automatically redirect the request unless it can be confirmed
>>>>>>> by the
>>>>>>> user,
>>>>>>> since this might change the conditions
>>>>>>> under which the request was issued.
>>>>>>>
>>>>>>> Would it be possible to send me (privately if public
>>>>>>> disclosure is an
>>>>>>> issue)
>>>>>>> a maven-based project that reproduces the issue?
>>>>>>>
>>>>>>> Paul.
>>>>>>>
>>>>>>> On Feb 10, 2010, at 8:55 PM, Chris Carrier wrote:
>>>>>>>
>>>>>>>> Hi folks,
>>>>>>>>
>>>>>>>> I've seen this topic mentioned in the archive but I am having
>>>>>>>> trouble
>>>>>>>> getting it to work. It's a pretty annoying problem. I just
>>>>>>>> want all
>>>>>>>> my calls to work whether they have a trailing slash or not.
>>>>>>>> In this
>>>>>>>> project we're using embedded Jetty that is being
>>>>>>>> programatically
>>>>>>>> configured. So in that code I added:
>>>>>>>>
>>>>>>>> Servlet servlet = new SpringServlet();
>>>>>>>> ServletHolder holder = new ServletHolder(servlet);
>>>>>>>>
>>>>>>>> Map initParams = new HashMap();
>>>>>>>> initParams.put(ResourceConfig.FEATURE_REDIRECT, "true");
>>>>>>>> holder.setInitParameters(initParams);
>>>>>>>>
>>>>>>>> But this seems to cause pretty unpredictable behavior. For
>>>>>>>> instance
>>>>>>>> after I added that I tried making a POST to my endpoint which
>>>>>>>> has a
>>>>>>>> method annotated as @POST but I get a 400 response. And the
>>>>>>>> weird
>>>>>>>> thing is the debug log shows:
>>>>>>>>
>>>>>>>> 2010-02-10 11:40:03,382 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:69
>>>>>>>> Bound
>>>>>>>> request context to thread: POST /some/path HTTP/1.1
>>>>>>>> ...
>>>>>>>>
>>>>>>>> 2010-02-10 11:40:03,383 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:89
>>>>>>>> Cleared
>>>>>>>> thread-bound request context: POST /some/path HTTP/1.1
>>>>>>>> ...
>>>>>>>>
>>>>>>>> 2010-02-10 11:40:03,384 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:69
>>>>>>>> Bound
>>>>>>>> request context to thread: GET /some/path/ HTTP/1.1
>>>>>>>> ...
>>>>>>>>
>>>>>>>> 2010-02-10 11:40:03,385 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:89
>>>>>>>> Cleared
>>>>>>>> thread-bound request context: GET /some/path/ HTTP/1.1
>>>>>>>> ...
>>>>>>>>
>>>>>>>> There isn't a GET call being made. It's like the POST is
>>>>>>>> getting
>>>>>>>> turned into a GET for some reason. This doesn't happen when
>>>>>>>> i don't
>>>>>>>> have the redirect on. Does the trailing slash thing only
>>>>>>>> apply to
>>>>>>>> GETs? If that's the case shouldn't it just ignore my POST?
>>>>>>>> If i have
>>>>>>>> a trailing slash in the original call it works fine.
>>>>>>>>
>>>>>>>> Aside from that the redirect doesn't even work for my GETs.
>>>>>>>> When i
>>>>>>>> try a GET without a trailing slash I get:
>>>>>>>>
>>>>>>>> 2010-02-10 11:47:15,344 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:69
>>>>>>>> Bound
>>>>>>>> request context to thread: GET /some/path/c4e713e HTTP/1.1
>>>>>>>>
>>>>>>>> 2010-02-10 11:47:15,346 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:89
>>>>>>>> Cleared
>>>>>>>> thread-bound request context: GET /some/path/c4e713e HTTP/1.1
>>>>>>>>
>>>>>>>> 2010-02-10 11:47:15,359 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:69
>>>>>>>> Bound
>>>>>>>> request context to thread: GET /some/path/c4e713e/ HTTP/1.1
>>>>>>>>
>>>>>>>> 2010-02-10 11:47:15,440 DEBUG
>>>>>>>> org.springframework.web.context.request.RequestContextListener:89
>>>>>>>> Cleared
>>>>>>>> thread-bound request context: GET /some/path/c4e713e/ HTTP/1.1
>>>>>>>>
>>>>>>>> Which looks like it's redirecting properly but then it
>>>>>>>> returns a 404.
>>>>>>>> In this case it doesn't matter whether i have a trailing
>>>>>>>> slash on the
>>>>>>>> original call or not it always returns a 404. Even though I
>>>>>>>> have a
>>>>>>>> GET annotated class and I've tried various combinations for
>>>>>>>> the path:
>>>>>>>>
>>>>>>>> @GET
>>>>>>>> @Path("/{id}/")
>>>>>>>>
>>>>>>>> @GET
>>>>>>>> @Path("/{id}")
>>>>>>>>
>>>>>>>> Is there something I'm missing here? For my main Path i've
>>>>>>>> tried:
>>>>>>>>
>>>>>>>> @Path("/some/path/")
>>>>>>>> @Path("/some/path")
>>>>>>>> @Path("/some/path*")
>>>>>>>>
>>>>>>>> And probably some others.
>>>>>>>>
>>>>>>>> Any ideas?
>>>>>>>>
>>>>>>>> Thanks!
>>>>>>>> Chris
>>>>>>>>
>>>>>>>> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>