users@jersey.java.net

Re: [Jersey] Trailing slash redirect

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

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.

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
>