In certain situations a page can look or behave differently depending on the value of a cookie.

In those situations, the cookie would need to be respected while generating the cache file name by PHP and the .htaccess.

For example, this is necessary for the Context Breakpoint module (http://drupal.org/project/context_breakpoint), where context can change the page depending on screen resolution, which is stored in a cookie.

I already implemented this functionality and it is working fine for me.
It's pretty straight forward:

In the settings, the user can specify the cookies that should be respected.
If those cookies are present, they are added to the cache filename.
Finally, in the .htaccess generation, the required rules are added.

Attaching a patch.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Anonymous’s picture

I think this has potential. Having scan read the patch, I would have thought that it would be better to progress along the currently defined path and use

%{ENV:boostpath}

and alter it for the various cookies (in the rewrite rules and the PHP), which could also lead to a simpler total exclusion for specific cookies like

RewriteCond %{ENV:somecookie} 0
RewriteRule .* - [S=XXX]

with XXX being the calculated number of rules to skip, as a more balanced approach as it leads to the ability to disable a certain cookie and it's cache during development very quickly.

theduke’s picture

Hey Phillip.

I also at first thought that using the boostpath would be easier,
and implemented it that way.

The problem: There might be a lot of different combinations for the cookies that are considered for caching,
so you could end up with a lot of different boostpath environments (in our current usecase it could be 50+).

Also since the cookie values might not be known beforehand, on every request we would need to check if the corresponding path and the .htaccess file exist, and create them if not.
(That's not really hard, I know, but does complicate things.)

What turned me off most was the directory clutter that could result.

Anonymous’s picture

The counter argument would be that one could end up with many thousands of files in one directory each with a differing extension and much more difficulty to debug.

I would envisage that one would have three or four directories maximum as one wouldn't be trying to cater for every screen size just generics and CSS3 scaling with most people moving to a responsive theme rather than putting the stress on a cookie based solution. A few thousand pages per directory is quite common with product catalogs and I'd prefer them to be arranged in a tree structure rather than duplicated in the same folder, the mechanism for creating directories is already established for "normal" along with .htaccess creation.

theduke’s picture

Alright, here is a patch that implements the functionality with boostpath.

This patch also changed quite a few things related to supporting different boostpaths.

Just to explain what's happening:

After enterint the desired cookies in the settings, the .htaccess gets generated like this:

# Handle cookie inclusions
  RewriteCond %{HTTP_COOKIE} TESTCOOKIENAME=([^;]+) [NC]
  RewriteRule .* - [E=boostpath:%{ENV:boostpath}_TESTCOOKIENAME=%1]

So the cookie values are appended to the boostpath.

---------------------

The function boost_get_normal_cache_dir() is changed to work the same way,
it now also appends the cookie values if found.

Note that I also made it possible to overwrite the normal boost path (boost_root_cache_dir)
with the boostpath environment variable, which could be quite helpful because you can set
a custom boostpath from your htaccess, but ONLY if mod_env is enabled on the server, which is
not always the case.

That's why the cookies are still appended manually (otherwise, appending them in PHP could totally be skipped).

---------------------

In boost_exit, before writing the file, I check if the .htaccess for this base_dir exists,
and if not, it is created.

Similarily, after submitting a boost settings form, boost_htaccess_cache_dir_rebuild() is called,
which re-generates all currently existing .htaccess files.

I removed the .htaccess generation from hook_enable because it is done on the fly now anyway.
---------------------

Last, I also had to alter hook_cron() and hook_flush_cashes() to wipe all possible boostpaths.
For this, I added the $delete_root parameter to _boost_rmdir to be able to prevent the root cache dir from being deleted.

theduke’s picture

Oops, left in a debug statement ... new patch without it.

theduke’s picture

Status: Active » Needs review

Any feedback for the patch?

Anonymous’s picture

BGM's the only one with write access to the repository and I've not heard from him for a long time.

JonesUI’s picture

@theduke:

I'm trying to get your Boost patch for Context Breakpoint working.

I've successfully patched Boost (I think) and enabled it on my server and I have Context Breakpoint configured to "Save resolution in cookie"

I can see that Boost is working but I don't know what settings to modify to in Boost to preserve the Context Breakpoint cookie.

Can you point me in the right direction?

(BTW, when applying the patch file using OS X, the patcher hung unless I used the --verbose option... maybe the patch didn't actually work?)

Thanks!

JonesUI’s picture

@theduke:

Alternatively, could you send me the patched version of Boost that you have working?

skadu’s picture

Hey Duke,

Wanted to leave my experience related to this patch. I successfully applied the first patch you provided: "boost-cookie-inclusions.patch" to the dev version of boost. This was a life saver, as it has allowed boost to work in the majority of cases.

As expected, I am getting files created in my cache directory based on a "context_breakpoints" cookie that controls some changes on the website. This works great on all pages where only one context is triggered, and i see the following in my cache directory (starting from a clean cache):

  • jobs__context_breakpoints=narrow-normal-banner.html

The above file is being served, I can tell because the comment is added to the bottom of the page source when I view it.

However, I have more than one context that is triggered on some devices (and on small browser windows), so when I visit the same jobs page in that scenario (with two contexts being triggered) I see the following file being generated:

  • jobs__context_breakpoints=mobile-banner,mobile-home-layout.html

The cached file is generated without a problem, but that page is never served on subsequent page requests (no comment at the bottom of the HTML that is generated). I can visit the cached file directly in a browser without a problem.

In order to eliminate the possibility that one of those two contexts is causing the issue, I have disabled each one in turn and can confirm that the files are being created and served as expected.

However, when both are enabled, the cached file is created and not served.

The output in watchdog matches that file as well (replaced host name with abc):

Array
(
    [scheme] => http
    [host] => abc
    [path] => jobs
    [query] => 
    [full_path] => jobs
    [base_path] => /
    [query_array] => Array
        (
        )

    [url_full] => cmk.abc.com/jobs_
    [url] => http://cmk.abc.com/jobs
    [url_decoded] => /jobs_
    [base_dir] => cache/normal/cmk.abc.com/
    [filename] => cache/normal/cmk.abc.com/jobs__context_breakpoints=mobile-banner,mobile-home-layout.html
    [directory] => cache/normal/cmk.abc.com
    [normal_path] => node/7
    [path_alias] => jobs
    [args] => Array
        (
            [0] => node
            [1] => 7
            [2] => 
        )

    [menu_item] => Array
        (
            [page_type] => page
            [page_id] => 7
            [path] => node/%
            [load_functions] => Array
                (
                    [1] => node_load
                )

            [to_arg_functions] => 
            [access_callback] => node_access
            [access_arguments] => a:2:{i:0;s:4:"view";i:1;i:1;}
            [page_callback] => node
            [fit] => 2
            [number_parts] => 2
            [tab_parent] => 
            [tab_root] => node/%
            [title] => Employment
            [title_callback] => node_page_title
            [title_arguments] => a:1:{i:0;i:1;}
            [type] => 6
            [description] => 
            [position] => 
            [weight] => 0
            [include_file] => 
            [delivery_callback] => 
            [context] => 0
            [theme_callback] => 
            [theme_arguments] => Array
                (
                )

            [href] => node/7
            [tab_root_href] => node/7
            [tab_parent_href] => 
            [options] => Array
                (
                )

            [access] => 1
            [localized_options] => Array
                (
                )

            [original_map] => Array
                (
                    [0] => node
                    [1] => 7
                )

            [status] => 200
            [extra_arguments] => 
        )

    [is_cacheable] => 1
    [header_info] => Array
        (
            [status] => 200 OK
            [status-number] => 200
            [content-type] => text/html; charset=utf-8
            [content-type-basic] => text/html
            [charset] => utf-8
            [headers_sent] => 
        )

    [matched_header_info] => Array
        (
            [enabled] => 1
            [gzip] => 1
            [extension] => html
            [lifetime_max] => 1800
            [lifetime_min] => 60
            [comment_start] => <!-- 
            [comment_end] => -->
        )

)

The only difference in the file names being generated that stuck out at me is the comma that is being placed between the two context names. Could this be preventing .htaccess from matching the cached file?

Happy to provide any additional details you may need. I'm going to keep investigating, but wanted to leave this here before I forgot about.

Thanks again for your work.