Simple Hit-Metering and Usage-Limiting for HTTP
Extracted elements (30)
An empty Meter header in a request is defined as equivalent to 'will-report-and-limit', and sending only 'Connection: Meter' with no explicit Meter header achieves the same effect, making the most common case maximally efficient with minimal bytes.
Negotiation is done hop-by-hop rather than end-to-end to avoid requiring a protocol version revision and to ensure that only explicitly volunteering proxies join the metering subtree. Proxies at the leaves insert 'Cache-control: s-maxage=0' to force non-participating proxies to revalidate through the subtree.
Range requests are only counted when they include byte #0 of the resource, because in almost every case an end-client retrieves the beginning of any resource it accesses at all, and seldom retrieves any portion more than once. This rule produces 'best-efforts' accuracy without complex tracking.
The max-uses count does not include the use of a response to satisfy the end-client request that triggered the proxy's fetch. This supports prefetch semantics: a cache may receive max-uses=0, store the response, and serve one client request without revalidation, giving the origin server precise control over actual use count.
Usage reports upon cache-entry removal are intentionally off the critical path: they may be done in parallel with any other operation and are best-efforts only, so a proxy does not serialize other operations on their completion. This ensures hit-metering adds no round-trips to any client-visible critical path.
A proxy that receives a response with version less than HTTP/1.1 SHOULD NOT send Meter request directives to that server, as they would waste bandwidth. If the server later sends an HTTP/1.1 or higher response, the proxy should resume sending Meter directives.
When responses carry a Vary header, separate hit-counts MUST be maintained for each combination of selecting request-headers, even if they map to the same entity-tag. A proxy that does not support the Vary mechanism must not cache Vary responses and need not implement any hit-counting for them.
A Meter header MUST NOT be sent in response to a request from a client whose version is less than HTTP/1.1, and MUST NOT be accepted from such a client, to protect against proxies that might not properly implement the Connection header.
A proxy that has offered to send usage reports MUST send a usage report when: (1) it forwards a conditional GET/HEAD on behalf of a client, (2) the max-uses limit forces a conditional GET, (3) a metering timeout expires with a non-zero hit-count, or (4) it is about to remove a cache entry with a non-zero hit-count.
A server MUST NOT send a Meter header that would require a proxy to do something it has not yet offered to do. A proxy receiving a Meter header in a response MUST either obey it, or MUST revalidate the corresponding cache entry on every access (acting as if 'Cache-control: s-maxage=0' were present).
A usage report MUST NOT be transmitted as part of a forwarded request that includes multiple entity tags in an If-None-Match or If-Match header, as this would produce ambiguous counting.
Any proxy that transmits the Meter header in a request MUST implement every requirement of this specification, without exception or amendment. A proxy willing neither to obey usage-limits nor to send usage reports MUST NOT transmit a Meter header in the request.
Cooperating caches using non-HTTP protocols (e.g., ICP) to exchange cached responses MUST ensure the origin server receives reports that account for all uses or reuses by all cooperating members, and that usage limits apply to the group as a whole.
Proxies counting Range requests MUST count as a 'use' or 'reuse' only those Range requests that result in the return of byte #0 of the resource, to produce consistent approximations across partial-content scenarios.
The Meter header MUST always be protected by a Connection header. A proxy that does not implement Meter MUST NOT pass it through to another system. If a Meter header is received in a message whose version is less than HTTP/1.1, it MUST be ignored.
Usage reports MUST always be transmitted as part of a conditional request (GET or HEAD), since the conditional header is required for the origin server to know which response instance is being counted. Proxies forwarding usage reports MUST NOT change the contents of the conditional header.
When a proxy forwards a hit-metered or usage-limited response to a client not in the metering subtree, it MUST omit the Meter header and MUST add 'Cache-control: s-maxage=0' to the response.
When a proxy has exhausted its allocation of 'uses' or 'reuses' for a cache entry, it MUST revalidate the cache entry using a conditional request before returning it in a response.
The Meter design reveals no more information about individual users than HTTP/1.1's 'Cache-control: s-maxage=0' already would. It may actually help conceal organizational structure on the outbound side of a proxy. The specification is explicitly neutral with respect to privacy: it neither improves nor worsens user privacy relative to existing HTTP/1.1 mechanisms.
Abbreviated single-character forms are defined for all Meter directives: 'w' (will-report-and-limit), 'x' (wont-report), 'y' (wont-limit), 'c=N/N' (count), 'u=N' (max-uses), 'r=N' (max-reuses), 'd' (do-report), 'e' (dont-report), 't=N' (timeout), 'n' (wont-ask). All implementations MUST support both forms and SHOULD use abbreviated forms.
The 'count=NNN/MMM' report directive carries two decimal integers: the count of uses since the last report and the count of reuses. Its transmission in a request with no other Meter directive also implicitly conveys 'will-report-and-limit'. Proxies SHOULD NOT transmit 'count=0/0'.
The Meter general-header field carries zero or more directives used to negotiate hit-metering and usage-limiting between proxies and origin servers, and to report use/reuse counts. Multiple Meter headers in a message may be combined into a single header.
The 'timeout=NNN' response directive sets a metering timeout of NNN minutes after response origination; if the proxy has a non-zero hit count when it expires, it MUST send a report. Timeouts should be accurate to plus or minus one minute. This directive implies 'do-report'.
The 'wont-ask' response directive advises the proxy SHOULD NOT send Meter headers to that server; the proxy should forget this advice after no more than 24 hours. This avoids overhead for servers not wishing to use the Meter header, and implies 'dont-report'.
Three meter-request-directives control proxy participation: 'will-report-and-limit' (willing to report and obey limits), 'wont-report' (will limit but not report), and 'wont-limit' (will report but not limit). An empty Meter header in a request is equivalent to 'will-report-and-limit'.
A malicious proxy could report inflated hit counts, potentially causing large payments from advertisers to content providers. To mitigate this, proxies SHOULD only relay usage counts from outbound proxies that have authenticated via Proxy-Authorization or are on an approved list.
It is impossible to enforce usage limits if a proxy cheats by offering to limit usage but then ignoring the server's Meter directives. The protocol provides no cryptographic enforcement mechanism for compliance.
Hit-metering counting: a proxy maintains counters CU (uses) and CR (reuses) initialized to 0 when a response is first cached. CU increments on 200/203/206-byte-0 responses; CR increments on 304 responses. On forwarding a request upstream, the proxy includes the current CU/CR as a 'count' directive and resets them upon receiving the server's response.
Usage-limiting counting: a proxy maintains TU/TR (use/reuse totals) and MU/MR (limits). TU and TR are zeroed only upon receipt of new max-uses/max-reuses directives. When TU >= MU or TR >= MR, the proxy MUST forward the request. A PF prefetch flag allows a single use of a max-uses=0 response without revalidation.
The Meter header BNF defines three directive classes: meter-request-directive (will-report-and-limit | wont-report | wont-limit), meter-report-directive (count=1*DIGIT/1*DIGIT), and meter-response-directive (max-uses=N | max-reuses=N | do-report | dont-report | timeout=N | wont-ask). Request and report directives may only appear in requests; response directives only in responses.