encodeURL invokes Operations

Splash Forums Rewrite Users encodeURL invokes Operations

This topic contains 6 replies, has 2 voices, and was last updated by  Christian Kaltepoth 2 years, 10 months ago.

Viewing 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • #24884

    RedShadow
    Participant

    Hey guys, I am having a strange issue with rewrite regarding the HttpServletResponse.encodeURL method.

    I am using a JSF h:outputLink with a value that points to an URL like “/file/add”
    Furthermore I have a Configuration, which in this case should not be related but unfortunately is, like the following:

    return ConfigurationBuilder
                .begin()
                .addRule()
                .when(Path.matches("/file/{fileId}"))
                .perform(serveFile)
                .where("fileId").matches("[^\\/]+")
                .addRule()
                .when(Path.matches("/file/{fileId}/"))
                .perform(serveFile)
                .where("fileId").matches("[^\\/]+");
    

    When rendering the outputLink, JSF calls the encodeURL method which also causes the HttpOperation serveFile to be invoked. In my opinion this should not happen. I found that out because I got an exception. Here is the relevant part of the stacktrace:

    
    	at org.ocpsoft.rewrite.servlet.config.HttpOperation.perform(HttpOperation.java:42) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.config.DefaultOperationBuilder$DefaultCompositeOperation.perform(DefaultOperationBuilder.java:56) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.config.RuleBuilder.perform(RuleBuilder.java:121) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.config.DefaultOperationBuilder$DefaultCompositeOperation.perform(DefaultOperationBuilder.java:56) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.config.RuleBuilder.perform(RuleBuilder.java:121) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.servlet.impl.DefaultHttpRewriteProvider.rewriteHttp(DefaultHttpRewriteProvider.java:182) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.servlet.http.HttpRewriteProvider.rewrite(HttpRewriteProvider.java:43) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.servlet.impl.HttpRewriteWrappedResponse.rewrite(HttpRewriteWrappedResponse.java:430) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at org.ocpsoft.rewrite.servlet.impl.HttpRewriteWrappedResponse.encodeURL(HttpRewriteWrappedResponse.java:389) [rewrite-servlet-2.0.0.Final.jar:2.0.0.Final]
    	at com.sun.faces.context.ExternalContextImpl.encodeResourceURL(ExternalContextImpl.java:544) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
    	at com.sun.faces.renderkit.html_basic.OutputLinkRenderer.renderAsActive(OutputLinkRenderer.java:239) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
    	at com.sun.faces.renderkit.html_basic.OutputLinkRenderer.encodeBegin(OutputLinkRenderer.java:107) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
    	...
    

    I am using JBoss EAP 6.1.0.Final and Rewrite 2.0.0.Final

    • This topic was modified 2 years, 10 months ago by  RedShadow. Reason: typo
    • This topic was modified 2 years, 10 months ago by  RedShadow.
    #24888

    This is intended behavior. There are two types of rewrites that are supported by Rewrite:

    • Inbound: Incoming requests from the browser (like the downloads you are implementing)
    • Outbound: Links rendered to the page (like the h:outputLink you are using)

    As you don’t specify which of the two types you want to address with your rule, the rule will match both.

    To fix this issue, you should do something like this:

    .addRule()
    .when( Direction.isInbound().and( Path.matches("/file/{fileId}") ) )
    .perform(serveFile)
    
    #24889

    BTW: I strongly recommend to update Rewrite to 2.0.5.Final as we fixed many many bugs since 2.0.0.Final.

    #24892

    RedShadow
    Participant

    I guess I misunderstood the concept then. Regarding inbound requests it makes total sense to me that the serveFile is invoked.
    Still I am trying to figure out how the outbound rewriting is supposed to work. Is it somewhere documented how that works?
    Am I right that when using somehting like a Join, that it is just the reverse mapping.

    For example if I have the rule:

    .addRule(Join.path("/test/page").to("/test_page.xhtml"))

    and call encodeURL("/test_page.xhtml") the result should be “/test/page” right?
    Well and for me, everything beyound a Join Rule does not make sense to be outbound rewritten. Could you give me a use case?

    PS: I am just about to update rewrite ­čÖé

    #24893

    Actually a Join is a special rule which consists of an inbound and an outbound part. Take this for an example:

    Join.path("/home").to("/faces/home.xhtml")
    

    This is basically the same as:

    .addRule()
    .when(Direction.isInbound().and(Path.matches("/home")))
    .perform(Forward.to("/faces/home.xhtml"))
    .addRule()
    .when(Direction.isOutbound().and(Path.matches("/faces/home.xhtml")))
    .perform(Substitute.with("/home"))
    

    And there are other use cases for outbound rewriting. Take CDNs for an example. Let’s imagine you want to achieve that clients don’t fetch jQuery from your local server but instead from a CDN. You can do this with Rewrite, even for stuff like JSF resources:

    .addRule()
    .when( Direction.isOutbound().and(Path.matches("/faces/javax.faces.resource/jquery.js")) )
    .perform( Substitute.with("http://dh8sm43.cloudfront.net/jquery.js") )
    

    If you want to learn a bit more about these basics, you could have a look at the slides of my Rewrite talk on JAX13:

    #24894

    RedShadow
    Participant

    Thanks for the explanation, the slides are really helpful! You should consider merging some pictures from there into the manual ­čśë

    Now a last question. Wouldn’t it be better if the default outbound rewriting is only done for specific Operations like Substitute? I can’t think of an use case that uses a custom Operation that supports outbound rewriting. Maybe you could introduce a marker interface or so and only do outbound rewriting by default if every element in the operation chain implements that marker interface?

    #24895

    I think it is a very common use case to use a custom operation with outbound rewriting. Especially if you want more control over the outcome of the rewriting process. For example if you want to build the substitute URL dynamically.

    BTW: There is another way for you to simplify your use case. Instead of implementing Operation or HttpOperation, you could also implement InboundOperation. This one will only be executed for inbound rewrites.

Viewing 7 posts - 1 through 7 (of 7 total)

You must be logged in to reply to this topic.

Comments are closed.