0

My WordPress website runs on a shared Apache webserver. I use a commercial plugin to record client bookings. This plugin registers a custom WordPress feed with add_feed() in plugin init. When requested with its link, the server feed response contains an inline .ics calendar file: the plugin sets a few header lines for 'Content-type: text/calendar; charset=utf-8' and 'Content-Disposition: inline; filename=' . $filename ). It then generates VEvents by looping through its table with bookings. So this feed is not in any way linked to normal posts, etc. Also important to note is that the plugin does not output a last-modified date in the header. This feed works fine for most devices and external sites requesting the web calendar file.

One of my devices (iPhone on iOS 14) could not refresh this calendar subscription. The initial subscription resulted in a valid web calendar on the device, but updates would not come through. Upon examining the headers it became clear that the iPhone was the only device that sent an if-modified-since in its request header when trying to refresh/update the calendar. The web server responded with a 304 Not Modified and did not send the feed / file.

I now have a workaround in .htaccess that eliminates if-modified-since in request headers for .ics files, but this does not solve the root cause.

The issue is that the web server compares the if-modified-since date with another date, possibly the last-modified date that it sends for the original file. As specified, the last-modified is not generated by the plugin, but the server outputs it every time. The plugin author has no idea where that last-modified date for that feed is derived from. They say WordPress does not offer hooks or actions to set/modify the date of a feed, as it is generated dynamically. Testing with a feed from their server: that feed is always delivered, although the last-modified contained in the header of the feed is later than the if-modified-since in the iPhone's request header.

Any suggestions which date comparison my Apache server or WordPress configuration could be performing when returning the 304 response for this WordPress feed? Any ideas on how to solve this?

0
0

I believe your server's replies include an Etag, which the client then uses to make the request. If you remove this header from the answer, then the client will not set the If-None-Match header when making a request, and the server will send the correct reply to the client. So, adding the following lines in .htaccess should solve the problem:

# Disable ETags
<IfModule mod_headers.c>
    Header unset ETag
</IfModule>
FileETag None

Correction

The plugin replies include a last-modified header, as in

last-modified: Wed, 21 Apr 2021 18:22:20 GMT

which is a good thing by itself, except when it's not. For some unknown to me reason (bug?) the date in this header stays always the same, regardless of what has changed in the calendar since. Some mobile clients include in their request the If-Modified-Since header, as in

If-Modified-Since:Thu, 27 May 2021 13:23:28 GMT

and if this date is more recent than the last-modified date, the server sends a 304, otherwise a 200. Since the last-modified date is stuck in the past, the server always sends a 304. The least intrusive thing to do is ask the server to ignore the If-Modified-Since header, which can be easily achieved with the RequestHeader directive like this:

# Disable ETags from replies and If-Modified-Since from requests
<IfModule mod_headers.c>
    Header unset ETag
    RequestHeader unset If-Modified-Since
</IfModule>
FileETag None

This has the extra cost of downloading the calendar on every request, not taking into account wether anything has actually changed, but in my case this was an acceptable cost.

7
  • These lines were already included in .htaccess and unfortunately did not solve the issue. For the time being, the workaround I described above is the only thing that I've found. – puzzledbeginner May 27 at 21:23
  • The ETag header seems to solve the desktop devices problem, but not the mobiles. I had the same problem yesterday and solved it by removing the If-Modified-Since header, as I describe above in my edit to the answer. Basically the Etag does not change because the last-modified stays the same, but I'm short of time to dig into the plugin's code to fix this. – gmelis May 28 at 9:02
  • Exactly, I also used this workaround to unset if-modified-since headers from requests. I limited it to requests for .ics : – puzzledbeginner May 29 at 10:21
  • <If "%{QUERY_STRING} =~ /\.ics$/"> <IfModule mod_headers.c> RequestHeader unset If-Modified-Since </IfModule> </If> – puzzledbeginner May 29 at 10:21
  • I don't think they're being entirely truthful. If you dump the TCP port of the php-fpm process serving the site, you will notice the following headers in the reply from php: Content-Type, Last-Modified, ETag, Link. The Last-Modified header is right there, and this is before apache takes over. It's the answer from php-fpm and it's obviously something on the WP side. Maybe a cache manager or something, or even the hbook plugin. – gmelis May 29 at 11:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.