JRuby (please use github issues at http://bugs.jruby.org)
  1. JRuby (please use github issues at http://bugs.jruby.org)
  2. JRUBY-2832

Rails static page caching won't generally work with Java ServletFilter unless some serious hack with the cache directory is found

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Critical Critical
    • Resolution: Won't Fix
    • Affects Version/s: JRuby 1.1.3
    • Fix Version/s: None
    • Component/s: Rails WAR Deployment
    • Labels:
      None
    • Environment:
      JRuby 1.1.3, Ubuntu Hardy Heron, last Java 6, Tomcat 6 or Glassfish v2
    • Number of attachments :
      2

      Description

      NB: you don't even need a Rails application to understand why things won't work properly. A simple custom ServletFilter logging something when called would prove you we need to find an other solution with JRuby-Rack.

      So suppose you adhere to Rails Restful conventions (like resources) and you have a 'topics' resources for instance.
      Then, in a normal Rails application (like served by Mongrel) if you do

      POST /topics -> that creates a new topic using the create method of TopicsController
      GET /topics -> that read the topics index and list all the topics, using the index method of TopicsController
      GET /topics/:id -> renders the topic with the provided :id using the show method in TopicController

      Now suppose you want to cache the /topics/:id show page with the cache_page :show statement inside your TopicsController
      Normally, the first time you request a topic, a /topics/:id.html file will be created inside your RAILS_ROOT/public directory. This is true as well when deploying as a WAR.
      ( good explanations about page caching to be found here: http://www.railsenvy.com/2007/2/28/rails-caching-tutorial#pagecaching )

      BUT, as soon as the 'topics' directory gets created inside your Java webapp RAILS_ROOT/public directory, any attempt to create a new topic will fail, both on Tomcat6 and Glassfish v2 at least!

      Why? Because at least on those Java servers, if you do;
      POST /topics while a "/topics" directory exists inside your RAILS_ROOT/public directory
      then the server will answer an empty content with the following HTTP headers:
      HTTP/1.1 302 Moved Temporarily
      Server: Apache-Coyote/1.1
      Location: http://localhost:8080/topics/
      Transfer-Encoding: chunked
      Date: Sun, 20 Jul 2008 00:16:39 GMT

      But the thing is that the server answers this without even calling any ServletFilter! Also notice that the ServletFilters are usually called even when requesting a static content. What screws it up here is the presence of a '/topics' directory which isn't a file but matches the request path. Same thing happens when performing a GET on paths having a corresponding public directory.

      So the RackFilter isn't even called when doing so. So you have no chance to answer properly to the request at all!
      You can easily reproduce that behavior with that command line:
      >curl -d "" http://localhost:8080/topics
      (try both: with and without a '/topics' directory inside your RAILS_ROOT/public directory)

      Moreover, to screw things a bit more, using Firefox3 at least, the browser send a GET /topics/ after the POST /topics returned a 302 header with the Location: http://localhost:8080/topics/ (notice the '/' at the end of the path) . Then the GET /topics/ will might be served but that would generally not do what you would expect with the POST /topics action. In the Restful case, you'll be redirected to the topics list instead of creating a resource!

      Since the RackFilter isn't even called, static page caching on Java servers won't generally work out of the box.

      I see two solutions now:
      1) append '/' at the end of your post (or get) request where there could exist a public directory: doing POST /topics/ works while POST /topics will fail. But this is not the nice default Rails behavior so you'll need to be hack your POST urls in the forms of your Rails application. Not very nice.

      2) configure your Rails application to put the cached files elsewhere, like in your environment.rb:
      config.action_controller.page_cache_directory = RAILS_ROOT + "/public/my_cache_path/"
      Then, inside the RackFilter, we should prefix request path with the my_cache_path inside the maybeAppendHtmlToPath method. I'll try that to see were I get.

      Hope this helps. Don't hesitate to ask me more details if required. Best regards,

      RaphaŽl Valyi.

      1. jruby-rack0.patch
        5 kB
        Raphael Valyi
      2. warbler0.patch
        0.4 kB
        Raphael Valyi

        Activity

        Hide
        Raphael Valyi added a comment -

        Hi Nick,

        So yes the public page caching out of the box is broken if you want to make any J2EE web container to serve the static cache (by far the fastest Rails caching system).

        Yes, putting an Apache (or may be and other) front end would just work as usual and serve your static cache properly from where rails saves it as JRuby on Rails just saves the cache properly; it's just that J2EE web container can't serve that cache later properly as they will send HTTP 302 without even calling any servletfilter (so you have no opportunity to fix the behavior once the cache is saved) as I said.

        But I think that the promise of J2EE war deployment is that you can say bye bye to Apache and having only Glassfish would also be faster than 2 chained servers. So I hope you follow my patch proposal (jruby-rack0.patch) or something similar.

        By the way. I'm palying with my first patch for this and it seems working fine for me at least

        BUT my other second patch (warbler0.patch ; meant to add common mime types in the web.xml, especially for the static caches) don't work properly on Glassfish (only with Tomcat). it looks like the generated web.xml isn't 100% correct and Glasfish doesn't like it. You can have a look to the generated web.xml once the patch applied and may be you have an idea to make it work 100% correctly. Still you don't need it it apply the fisrt patch, it's just that some common mime types (such as .atom .xml .rss) might be missing just like they are already missing now for static caches.

        Regards,

        RaphaŽl Valyi.

        Show
        Raphael Valyi added a comment - Hi Nick, So yes the public page caching out of the box is broken if you want to make any J2EE web container to serve the static cache (by far the fastest Rails caching system). Yes, putting an Apache (or may be and other) front end would just work as usual and serve your static cache properly from where rails saves it as JRuby on Rails just saves the cache properly; it's just that J2EE web container can't serve that cache later properly as they will send HTTP 302 without even calling any servletfilter (so you have no opportunity to fix the behavior once the cache is saved) as I said. But I think that the promise of J2EE war deployment is that you can say bye bye to Apache and having only Glassfish would also be faster than 2 chained servers. So I hope you follow my patch proposal (jruby-rack0.patch) or something similar. By the way. I'm palying with my first patch for this and it seems working fine for me at least BUT my other second patch (warbler0.patch ; meant to add common mime types in the web.xml, especially for the static caches) don't work properly on Glassfish (only with Tomcat). it looks like the generated web.xml isn't 100% correct and Glasfish doesn't like it. You can have a look to the generated web.xml once the patch applied and may be you have an idea to make it work 100% correctly. Still you don't need it it apply the fisrt patch, it's just that some common mime types (such as .atom .xml .rss) might be missing just like they are already missing now for static caches. Regards, RaphaŽl Valyi.
        Hide
        Raphael Valyi added a comment -

        Oh by the way, one correction: I said that one static cache look up takes less than 1 micro second. I meant 1 millisec of course!

        Show
        Raphael Valyi added a comment - Oh by the way, one correction: I said that one static cache look up takes less than 1 micro second. I meant 1 millisec of course!
        Hide
        Charles Oliver Nutter added a comment -

        This is getting pretty old...anyone know if it's still valid?

        Show
        Charles Oliver Nutter added a comment - This is getting pretty old...anyone know if it's still valid?
        Hide
        Nick Sieger added a comment -

        It's probably still an issue with Java appservers, and somewhat unfortunate, but I don't see an easy fix other than the workarounds that RaphaŽl describes.

        Show
        Nick Sieger added a comment - It's probably still an issue with Java appservers, and somewhat unfortunate, but I don't see an easy fix other than the workarounds that RaphaŽl describes.
        Hide
        Raphael Valyi added a comment -

        Hi Charles,

        It has been a long time since I tested. I'm afraid, I think I can't easily test it before the next 15 days. But may be a little latter. The thing is that this 'bug' doesn't seem related to Rack or JRuby, but really to the fact the J2EE servers seems to behave differently than Apache here, so it won't work like static file caching with Rails behind Apache. So I guess the bug is still here, but I'll try to confirm as soon as I can.

        Show
        Raphael Valyi added a comment - Hi Charles, It has been a long time since I tested. I'm afraid, I think I can't easily test it before the next 15 days. But may be a little latter. The thing is that this 'bug' doesn't seem related to Rack or JRuby, but really to the fact the J2EE servers seems to behave differently than Apache here, so it won't work like static file caching with Rails behind Apache. So I guess the bug is still here, but I'll try to confirm as soon as I can.

          People

          • Assignee:
            Nick Sieger
            Reporter:
            Raphael Valyi
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: