How to Guide for Using CacheRight

CacheRight helps you make the most effective possible use of HTTP caching, by making it easy to control, in a granular way, how browser and proxy caches cache the different resources that make up your site.

Installation and Activation

CacheRight consists of the following major program components:

  • An ISAPI filter (cr_isapi.dll) which is installed in %SystemRoot%\System32\inetsrv, and mapped to the service (W3SVC) node in the Internet Information Services (IIS) metabase. The component implements all CacheRight functionality within IIS.
  • A graphical user interface called the CacheRight Settings Manager (CacheRight.exe), which is installed in the CacheRight installation directory (by default C:\Program Files\Port80\CacheRight). The CacheRight Settings Manager provides a way for users with server administrator rights to configure those few high-level CacheRight settings that are not managed through the CacheRight rules files.
  • One or more CacheRight rules files ( This file stores most of the CacheRight configuration for a given Web site. It can be edited directly (e.g., using a text editor such as notepad) or via the CacheRight user interface. A sample file, containing extensively-commented examples of various types and uses of CacheRight rules, is stored in the CacheRight installation directory. In addition, when one uses the CacheRight user interface to edit the rules for a Web site that does not yet have a file of its own, CacheRight will offer to create a sample file in that site's home directory.
  • A rule syntax validator (SyntaxCheckerGUI.exe) that is used to check the syntax of files after they have been edited, to make sure they will load correctly. Although this component can be launched from within the CacheRight Settings Manager, it can also run as a standalone application, so it can be distributed to anyone who is responsible for writing and/or deploying CacheRight rules.
  • In Server 2008 deployments only: A pair of assemblies (CacheRightServer and CacheRightClient) that allow CacheRight to be activated and configured entirely from within the IIS user interface (IIS Manager)--including remotely connected IIS Manager instances running under a user account that has been granted the appropriate administrative permissions in IIS.

More: Installing CacheRight »

Using the Settings Manager

The Settings Manager can be launched from the Port80/CacheRight program group in the Start menu, or directly by running CacheRight.exe. The Settings Manager controls the general operation of CacheRight for any Web site (virtual server) provisioned on the computer.

You will find that the configuration options in the Settings Manager are quite limited. This is because CacheRight is primarily controlled via its site-specific rules files ( It is these rules files which allow non-administrators to author and maintain CacheRight rules on a per-site basis. Configuration options that can only be accessed by system administrators (or those with access to the Settings Manager) are kept to a bare minimum.

On the left side of the Settings Manager is a list of all the Web Sites (virtual servers) that are available on the computer. Use this list to select the Web site whose settings you want to change.

Here are some basic administration tasks that can be handled through the CacheRight Settings Manager:

  • To configure settings for a single Web site: Select the site from the Web Sites list. The controls on the Settings Manager will reflect the current settings for that Web site. Any changes you make will take effect only for the site that is selected.
  • To configure default settings for newly-created Web sites: Select Default Settings from the Web Sites list. The controls on the Settings Manager will reflect the current default settings. Any changes you make will take effect for any new Web sites that are added in IIS.
  • To configure settings for two or more Web sites: Select the sites from the Web Sites list (optionally including Default Settings) using the Shift key (for two or more contiguous Web sites) or the Control key (for two or more discontinuous Web sites). In this case, the controls on the Settings Manager will reflect the current settings for the first Web site selected -- which will also be the one pointed to by the arrow indicator. Any changes you make will take effect for all the sites that are selected.
  • To replicate settings from one site to another: To propagate the settings of one site (or the Default Settings) to one or more additional sites, use the multiselect feature to select both (or all) of the sites, making sure that the first site selected is the one whose settings you wish to propagate (verify this by seeing that the arrow indicator is pointing to the source site). Without making any configuration changes, simply click Apply to propagate the settings to the target site(s).
  • To replicate settings from one physical server to another: To migrate all configuration settings (including Default Settings) from one server to another, use the File/Export Settings menu option on the source machine to save out a .zeg file (Port80 Registration file) to disk. Next, copy this file to the target machine(s) and then use the File/Import Settings menu option to select the .zeg file. All existing settings on the target machine will be erased. Close and reopen the Settings Manager to display the new settings.
  • To enable or disable CacheRight for a given Web site: Select the site to enable (or disable) from the Web sites list and check (or uncheck) the checkbox labeled Enable CacheRight for [Web site name]. This checkbox is located above the general settings tab, on the right side of the interface.
  • To configure how CacheRight will deal with existing cache control headers: Select the site to configure and check (or uncheck) the checkbox labeled Override existing cache control headers.
  • To edit the CacheRight rules file ( for the currently-selected site: Click the Edit button to bring up the file in Notepad.
  • To check the syntax of the rules file for the currently-selected site: Click the Validate button to launch the local copy of the CacheRight syntax checker (cr_syntax.exe). The syntax checker will be launched with the path to the file for the currently-selected site pre-loaded in the File text field.

More: Saving Changes »

Understanding HTTP Cache Control

Ideally, HTTP cache control lets you make the most of browser and proxy caching, thereby reducing network connections, saving bandwidth, and increasing page load times. Here is how it should work under ideal conditions:

  1. A client makes an initial request a set of resources (for example, an HTML page with linked image, script and style sheet files).
  2. The server responds by sending the requested resources, together with a set of special HTTP headers that tell how long each resource should be considered fresh.
  3. From this point on, subsequent requests for these same resources are mediated by a caching mechanism, as shown in the following diagram:

    Caching Diagram

  4. As long as a given resource is still fresh, subsequent requests by the client for that resource are served from the cache, saving both the time and bandwidth of a roundtrip to the server. (Case A in the diagram.)
  5. When the cache needs to display a resource that has expired or gone "stale," it polls the server to find out if that resource has changed. (Case B in the diagram.)
  6. In a perfect world, whenever a client does one of these checks, the resource it is asking about will in fact have been changed, and the server will respond with the newest version. (Case C in the diagram.)

The above scenario represents how HTTP caching should work, thanks to expiration-based cache control. In reality, the difficulty of implementing and maintaining cache control policies for all the different objects or resources in your site, often creates problems that prevent HTTP caching from working as smoothly as it should--and to often prevent expiration-based cache control from being used altogether.

In a less-than-perfect world, a lot can go wrong with the attempt to use expiration-based cache control to manage how your site's resources are cached. For example:

  • Problem: The server never sends the right cache control headers.
    Result: The client keeps requesting files from the server that it could have cached instead.
  • Problem: The server sends cache control headers for some resources (like the HTML file), but not for others (like the image files).
    Result: The HTML file will be served out of the cache, but the image files will constantly be re-fetched from the server, when they could have been cached.
  • Problem: The server does send cache control headers for the images, but the expiration times are much too short. (Suppose for example that the image files change rarely. This is often the case when images are used as navigational elements, uniform page headers and backgrounds, and so on.)
    Result: When the client sees that an image file in its cache is "stale," it will start checking with the server every time it needs to display that image, to find out if the file has changed. Since the image won't have changed, every one of these "conditional requests" from the client, and the corresponding "304" or "Not Modified" responses from the server, represents wasted bandwidth and unnecessary delay. The image ends up being served out of the client's cache anyway, but only after a round trip to the server.

These are the kinds of problems that cause site operators to give up on expiration-based cache control, and fall back on the much-less-efficient, default caching behavior of browsers and proxies, with the result that most sites force revalidation round-trips for every cached entity on every return visit. Fortunately, these are also the same problems that CacheRight helps solve, by making the process of implementing and maintaining accurate, up-to-date cache control policies, for every type of resource on your site, as easy as possible.

The CacheRight Rules File

The main means of configuring CacheRight is through the CacheRight rules file ( This is simply a text file that contains one or more valid CacheRight rules. These rules can then control all the cache control headers that are sent out for a particular site. To work properly, this rules file only needs to meet a few basic requirements. Specifically, it must:

  • be named
  • be located in your website's home (or root) directory
  • contain only valid CacheRight rules or comments (the latter being enclosed in curly braces).

An important feature of CacheRight is that you do not have to be logged into the server, or have administrator rights on it, in order to be able to add or edit CacheRight rules for a particular site. All you need is the ability to edit a text file in that site's home directory, or else to transfer a local copy of your file to that directory after making your changes.

CacheRight Rule Syntax

CacheRight rules themselves are nothing but short statements that declare how a resource should be cached. These statements have a very simple syntax, the general form of which is as follows:

Rule-Type Selector : Expiration-Clause Directives

Below is a brief explanation of each of the four parts of a CacheRight rule. To jump to a detailed discussion of each part, just click its name.

Rule-Type: CacheRight provides four different types of rule to choose from: ExpiresDefault, ExpiresByType, ExpiresByPath and BlockByPath. Each type has a different use, and you can combine the rule types in a variety of ways, in order to cover all the resources in a given site.

Selector: This is the part of a rule that picks out one or more resources to which the rule will apply. It varies with the type of the rule. For ExpiresByType rules it is a MIME type. For ExpiresByPath and BlockByPath rules, it is a URL path. All of these rule types can also takes lists of multiple selectors (separated by commas), as well as selectors that use wildcards (asterisks) to match any number of characters. The ExpiresDefault rule is the only one that doesn't require a selector.

Expiration Clause: This is a clause stating when the resource(s) to which the rule applies should expire -- in other words, when any cached copies should be considered stale by the cached that is retaining them. There are many options for how to write this clause: an interval from when the file was modified, or from when it was accessed by the end-user, or even a particular date-and-time.

Directives: These are additional keywords that appear at the end of rule, causing additional cache control directives to be included in the headers along with expiration time.

Rule Precedence

A nice feature of CacheRight rules is that they can appear in any order in your file, without affecting the results (that is, which cache control headers get written out for which resources in the site). When two or more rules overlap or collide--in other words, when two or more rules would apply to the same resource--CacheRight decides which rule takes precedence based on the principle that the most specific rule applies. For more on how rule precedence works, see the topics Rule Details: Type and Rule Details: Selector.

Validating the Rules File

If there is an error in the syntax of one or more of the rules in your file, CacheRight will not load the file and none of the rules in it will have any effect. Requests to the Web server will not be interrupted in any way, but they won't have the proper cache control headers either.

To avoid this, we highly recommend that you validate your file every time you make a change to it. CacheRight comes with a utility called SyntaxCheckerGUI.exe that validates files and displays any syntax errors they may contain.

The SyntaxCheckerGUI.exe utility is installed together with CacheRight. It can be launched from the CacheRight Settings Manager (using the Validate button) for use on the server locally. You can also run a version of the syntax checker from within the CacheRight page in the IIS 7.x Manager.

Since it is a standalone utility, the syntax checker can also be redistributed to developers or site managers for remote use. This allows users who may not be authorized to administer IIS on the server machine, to nevertheless validate their changes to the file, before uploading it to their Web site's home directory.

Reloading the Rules File

Beginning with version 4.1.0, any changes made to the CacheRight rules should now take effect immediately. More specifically, CacheRight reloads the file in memory when the first request is made to IIS following any change to that file.

This means that, unlike previous versions of CacheRight, there is no longer any need to click Apply or OK in the CacheRight Settings Manager, or pass the cr_reset query string parameter, or recycle the IIS application pool--although all of these methods of reloading the file will also still work.

Example CacheRight Rules

In order to examine CacheRight rules in more detail, it is useful to have some concrete examples to work with. Here are four example rules. They could be the entire contents of a file for a simple website:

ExpiresDefault : immediately public

ExpiresByType image/jpeg : 2 weeks after access public

ExpiresByPath /navimages/* : 6 months after access public

BlockByPath /images/tempimages/* :

The next four sections of this document will repeatedly refer back to these examples, as they cover in detail the various parts that make up a CacheRight rule. If you read them through in order, by the end of the fourth section you will know all there is know about writing CacheRight rules.

Alternatively, if you are looking for details about how a specific part of a CacheRight rule works, you can just click on the relevant part in any of the above examples, to jump directly to the information you need.

Rule Details: Rule Type

Looking at the four example rules given in the previous topic, you will notice that each begins with a different keyword. This is because each of these four example rules demonstrates one of the four rule types available in CacheRight. Below is a description of how each rule type is used.

Notice that the rule types are listed here in reverse order from the way they are given in the examples section. This is done to emphasize their logical order of precedence--meaning that the more-specific rule types are listed before the less-specific ones, which they will override, in the case of any conflict between rules of different types.

BlockByPath /images/tempimages/* :

BlockByPath rules can be used to block the application of any other CacheRight rules for any resources picked out by the request path specified in the rule. BlockByPath rules override all other CacheRight rules that would otherwise apply, thereby allowing the default caching behavior (i.e., the behavior without expiration-based caching) to be restored for specific resources.

ExpiresByPath /navimages/* : 6 months after access public

ExpiresByPath rules can be used to set the expiration time for any resources picked out by the request path specified in the rule. ExpiresByPath rules override both the ExpiresDefault rule (if it exists) and also any ExpiresByType rule(s) that would otherwise apply.

ExpiresByType image/jpeg : 2 weeks after access public

ExpiresByType rules can be used to set the expiration time for all those resources that have the media (MIME) type specified in the rule. ExpiresByType rules always override the ExpiresDefault rule, if one is present.

ExpiresDefault : immediately public

An ExpiresDefault rule, when present, sets the default expiration time for all the resources on a website that are not covered by other CacheRight rules. Thus, if no other rule applies to a given resource, it will have the expiration time given in the ExpiresDefault rule. Unlike the other rule types, you can only have one ExpiresDefault rule in a given file.

Rule Details: Selector

Now that we know about the four kinds of scope a CacheRight rule can have, we are ready to look at the next part of the rule statement, the selector. This is the part of the rule just after the scope keyword and just before the colon. Recall that its function is to select one or more files to which the rule will apply. Looking once again at our example rules:

ExpiresDefault : immediately public

As you can see, the ExpiresDefault rule is unique in that it does not have an explicit selector between the scope keyword and the colon. The reason is that an ExpiresDefault rule applies to every file on the site that is not covered by a more specific rule. Thus, its selector can always be inferred from those of all the other rules in (or from the absence of any other rules).

ExpiresByType image/jpeg : 2 weeks after access public

The ExpiresByType selector is simply a media type -- also known as a MIME (Multipurpose Internet Mail Extension) type. Although this example uses only one MIME type, the selector can include as many as you wish, separated by commas. You will often want caches to treat files with different MIME types differently (for example, caching images longer than text files). This type of selector makes it easy to write such rules. In the example, the selector will apply this rule to all files of jpeg type.

ExpiresByPath /navimages/* : 6 months after access public

BlockByPath /images/tempimages/* :

The ExpiresByPath and BlockByPath selectors represent the (virtual) location of one or more files, relative to the website's home or root directory. As with MIME types, the path selector can include multiple paths, separated by commas. Paths may contain any combination of alphanumeric characters, underscores, forward slashes ( / ) and dots ( . ), plus wildcards (the * symbol). Paths must begin with either an initial slash (representing the home or root directory) or a wildcard. Query strings cannot be included in the path selector, and are ignored when matching against incoming requests. In the above examples, the ExpiresByPath selector picks out all files located in the navimages directory, or any of its subdirectories, while the BlockByPath selector does the same for the tempimages directory and its subdirectories.

Note that unlike ExpiresByType selectors, ExpiresByPath selectors are not mutually exclusive. To continue with our example, it would be perfectly legal to have a second ExpiresByPath rule in our file with the selector /perm_images/*.gif.

Because path selectors are not necessarily mutually exclusive, it is possible for more than one selector to apply to the same file. When this happens, the most specific selector always takes precedence (this is similar to the way selectors work in CSS, if you are familiar with that technology, and it also models the way inheritance works in IIS configuration settings).

Thus for example, for GIF files in the perm_images directory, a rule with the selector /perm_images/*.gif would take precedence over one with the selector /perm_images/* because the former selector is more specific (contains more information) than the latter. Like wise a rule with selector /perm_images/foo.gif would take precedence over both of the preceding rules.

Note: BlockByPath selectors always take precedence over all ExpiresByPath selectors, even when the ExpiresByPath selector contains more path information than the BlockByPath selector. Thus, a BlockByPath selector of /tempimages/* would override an ExpiresByPath selector of /tempimages/butnotthisone.jpg. By definition, BlockByPath rules have the most specific scope of any CacheRight rule type, and so if one of them applies to a request, that rule overrides everything else.

Rule Details: Expiration Clause

Having seen how CacheRight decides which rules apply to which resources, we now need to look at how rules set specific expiration times for the resources to which they apply. Three of our four example rules demonstrate the three ways an expiration clause can be written. (The BlockByPath rule is unique in that, since it doesn't need to set an expiration time, it has an empty expiration clause, so we won't be covering it in this section.):

ExpiresDefault : immediately public

One way to write an expiration clause is by using one of two special keywords -- never and immediately. Using immediately, as in the example, sets the expiration time to be exactly equivalent to the date of access. (The date of access is simply the date and time when the server delivered the file to the client.) Since the file will be "stale" as soon as it is received, it will not be cached. Using never, on the other hand, causes the expiration time to be set for one year from the date of access. The file will be cached, and the cached copy will remain "fresh" for one year.

Why does never mean one year? One year in the future is what the HTTP specification recommends as the maximum expiration time servers should send. It is possible to set longer expiration times than this using CacheRight, but we do not recommend doing so. For the relevant part of the HTTP specification, see

ExpiresByType image/jpeg : 2 weeks after access public

A second way to write an expiration clause is to specify an interval of time relative to some starting-point, at the end of which a cached copy will be considered "stale." This is done with a simple phrase consisting of four elements:

  • a number
  • an interval keyword (years , months , weeks , days , minutes )
  • the keyword after
  • one of two starting-point keywords (access or modification)

The access keyword means that the specified interval is relative to the date on which the client accessed the file on the server. The modification keyword means that the interval is relative to the last time the file was changed. In the example, a cached copy of an affected file will be considered stale 2 weeks after the server delivers it to the client.

Note that the practical effect of a relative interval can be very different depending on the starting-point used. If modification had been used in the example instead of access, then the cached file would be considered stale 2 weeks after its last modification date, no matter when the client received it from the server. Depending on how much time had gone by between the file's last modification and the client getting a copy of it from the server, that copy might be considered stale immediately, or after 2 weeks, or anytime in between.

When choosing between access and modification, the best keyword to use depends on whether it is more useful for a particular file's freshness to be determined from the point of view of the client accessing it, or from the point of view of its creator or editor. Generally speaking , the more frequently files are changed, and the more time-sensitive their content, the more likely you will want to use modification in place of access.

ExpiresByPath /navimages/* : Sun, 04 Jul 2010 12:00:01 GMT private

Here we have changed one of our example rules slightly to illustrate the third way to write an expiration clause, which is to specify an expiration date using GMT format (format details can be found online at In the example, cached copies of the affected files will be considered fresh until July 4, 2010. Note: if you set this date in the past, it will have an effect similar to using the immediately keyword (albeit not quite as restrictive in preventing the use of a cached version under any circumstances).

Rule Details: Directives

We have now covered the main parts of a rule -- those that let you control the expiration times for every resource on your Web site. The last part of a rule consists of one or more keywords that cause additional cache-control directives to be added to the Cache-Control header for a given resource. Three of our four example rules have been using one such directive all along -- the public keyword appended to the end of each rule. (BlockByPath is once again the exception -- rules of this type do not take any directives.) Now it's time to look more closely at the various directives that are available, for which purpose we will modify our example rules slightly:

ExpiresDefault : immediately public

ExpiresByType image/jpeg : 2 weeks after access public no-transform

ExpiresByPath /navimages/* : Sun, 04 May 2010 12:00:01 GMT private

Public and Private

The public and private keywords cause the public and the private directives, respectively, to be added to the Cache-Control header for a given resource. You may have noticed that all of the rule examples given so far have contained one or the other of these directives, but never both. This will always be the case because of the special properties of these two directives:

  1. The public and private directives are mutually exclusive.
  2. Every CacheRight rule (except for BlockByPath rules) must end with one of these two directives (but never both).


The public directive simply insures that a response is cachable by both shared (proxy) and nonshared (browser) caches. The private directive prevents a response from being cached by shared (proxy) caches, but permits caching by browsers. In the above examples, only the last of the three rules (the ExpiresByPath rule) has private rather than public, so only resources affected by that rule will be uncachable by shared (proxy) caches.


ExpiresByType image/jpeg : 2 weeks after access public no-transform

Unlike public and private, use of the no-transform directive is entirely optional. Caches are allowed to transform the objects they cache to make their storage and transmission more efficient. A cache may, for example, recode image files or compress text files. Under certain circumstances, these kinds of transformations can cause problems.

Appending no-transform to a rule prevents caches from modifying the files affected by that rule. Since shared (proxy) caches are more likely to use such transformations, no-transform will often be appended to CacheRight rules that have the public keyword, as in the example.

Verifying that CacheRight is Working

CacheRight controls a number of headers & directives sent by the Web server. The most important ones to be concerned with when editing CacheRight rules are the Expires header and the max-age directive of the Cache-Control header. These are the header fields that the server uses to supply the client with the expiration information for the requested resource.

If the expiration information is supplied in the Expires header, it will be in the form of a GMT date/time. If it is supplied in the max-age directive of the Cache-Control header, it will be in the form of an interval (given in seconds).

When CacheRight is working properly, this date or interval should correspond to the one specified in the expiration clause of the applicable CacheRight rule. In addition, any directives added to the end of the CacheRight rule statement should also show up in the Cache-Control header.

To see how this works, suppose a Web site had a file containing our example CacheRight rules. If you were to make a series of requests with an HTTP sniffer tool (such as LiveHTTPHeaders), with each request URL chosen so as to trigger a different rule, what would the results look like? Consider some examples:

First Example

A request for the site's home page (index.aspx for example) would cause the ExpiresDefault rule to be applied. Recall the expiration clause and directive of this simple rule:

ExpiresDefault : immediately public

As a result of this rule being applied, the following headers would be displayed from the server's response:

Date: Mon, 2 Nov 2009 19:08:16 GMT
Cache-Control: public,no-cache,no-store,max-age=0,must-revalidate,proxy-revalidate
Expires: Mon, 2 Nov 2009 19:08:16 GMT

Because the rule's expiration clause said that this file should expire immediately, the result is that the max-age directive was added to the Cache-Control header, with a value of 0. Meanwhile, the Expires header was also set, and notice that it's value is the same as that of the Date header, which gives the date of access in GMT time. Note also that the public directive was added to the Cache-Control header.

Second Example

A second request, this time for a jpeg file that is not in the /navimages directory, would cause the ExpiresByType rule to be applied. Here is a reminder of what that rule looked like:

ExpiresByType image/jpeg : 2 weeks after access public no-transform

And here are the corresponding headers that would be displayed:

Date: Mon, 2 Nov 2009 19:12:36 GMT
Cache-Control: public,no-transform, max-age=1209600,must-revalidate,proxy-revalidate
Expires: Mon, 16 Nov 2009 19:12:36 GMT

Because the rule's expiration clause specified a relative interval of 2 weeks after last access for the file's expiration, the max-age directive was added to the Cache-Control header with a value of 1,209,600 seconds -- the equivalent of 14 days after access. The Expires header was also set with a GMT date that is exactly 14 days after the one reported in the Date header. Lastly, the public and no-transform directives were added to the Cache-Control header.

Note that, if the expiration clause had specified an interval of 2 weeks days after modification (rather than after access), then the Cache-Control: max-age and Expires values would have been adjusted accordingly. For Expires, the date/time would have been set relative to the Last-Modified header (not shown in the above example), rather than the Date header. Since the max-age directive is always relative to date/time of access, the number of seconds given in it would have been the interval specified in the rule minus the interval between Last-Modified and Date.

Third Example

A third request, this time for a jpeg file in the /navimages directory, would cause the ExpiresByPath rule to be applied. Recall what that rule looks like, noting its expiration clause and directive:

ExpiresByPath /navimages/* : 6 months after access public

And here are the headers that would be reported in the HTTP sniffer for this request:

Date: Mon, 2 Nov 2009 19:12:36 GMT
Cache-Control: public,no-transform, max-age=15552000,must-revalidate,proxy-revalidate
Expires: Sun, 01 May 2010 19:12:36 GMT

Because the rule's expiration clause specified a relative interval of 6 months after last access for the file's expiration, the max-age directive was added to the Cache-Control header with a value of 15,552,000 seconds. The Expires header was also set with a GMT date that is exactly 6 months after the one reported in the Date header. And the public and no-transform directives were, once again, added to the Cache-Control header.

Fourth Example

Finally, we have the example of a request for a jpeg file in the /images/tempimages directory, which would cause our BlockByPath rule to by applied. That rule was very simple:

BlockByPath /images/tempimages/* :

And, because of it, there will not be much of interest to see in the resulting HTTP headers:

Date: Mon, 2 Nov 2009 19:12:36 GMT
Last-Modified: Mon, 2 Nov 2009 14:23:09 GMT

Notice that the response has neither a Cache-Control header nor an Expires header--and this despite the fact that two other CacheRight rules would seem to apply to this request (the ExpiresDefault and the ExpiresByType). Instead, the BlockByPath rule has overridden those other rules, and restored the default caching mechanism, which in this case is for the server to send down a Last-Modified header announcing the time of the file's last modification on disk.

When the browser (or proxy cache) receives another request for this resource, it will need to send a Conditional GET to the server, and wait for a 304 response, to make sure the cached version can be reused. Presumably, that was exactly the desired behavior for this particular file--hence the use of the BlockByPath rule.