Uploaded image for project: 'OASIS Open Data Protocol (OData) TC'
  1. OASIS Open Data Protocol (OData) TC
  2. ODATA-1198

ETag handling deviations from RFC7232 are avoidable if we consider two kinds of ETag (ETag in response header and ETag in response payload)

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: V4.01_CS01
    • Fix Version/s: V4.01_CS02
    • Component/s: JSON Format, Protocol
    • Labels:
      None
    • Environment:

      Proposed

    • Proposal:
      Hide

      New proposal based on discussion with Matt: close without action.

      Rationale: https://tools.ietf.org/html/rfc7232#section-3.1 states:

      An origin server MUST use the strong comparison function when
      comparing entity-tags for If-Match (Section 2.3.2), since the client
      intends this precondition to prevent the method from being applied if
      there have been any changes to the representation data.

      This is geared towards web servers managing static resources, and is perfectly valid in that context.

      This statement however is not true for (business) applications which track changes to the underlying data independent from its wire-representation in different formats. These applications want to prevent accidental changes to the underlying data, and for this an ETag only needs to change if the underlying data changes, meaning that different representations of the same underlying data can share the same ETag.

      From the perspective of RFC7232 these representation-independent "sufficiently varying" ETags are weak ETags, which is why we deviate from RFC7232 in this aspect. 

      Notes from F2F discussion on 2018-09-28

      • Servers SHOULD use strong Etags for OData entities == "internal" Etag transported in @etag
      • Clients SHOULD use @etag for If-Match
      • Servers MUST accept both @etag and the header-etag for If-Match
      • in single-entity responses servers SHOULD send @etag also in etag header
      • If the serializer (especially for JSON) can produce byte-for-byte identical representations of the same underlying data
      • Or if we ignore "byte-for-byte identical" and deem "JSON-equivalent" sufficient
      • Multi-entity response == Collection or Expand
      • Multi-entity response typically does not have etag header
      • MAY have weak etag if caching needs to be supported
      • MAY have strong etag for if-match
      • Collection-response MAY have @etag for if-Match which MAY differ from the header-etag for caching
      • Note: currently no @etag defined for collections in wrapper object, and Hubert uses/needs this
      Show
      New proposal based on discussion with Matt: close without action . Rationale:  https://tools.ietf.org/html/rfc7232#section-3.1  states: An origin server MUST use the strong comparison function when comparing entity-tags for If-Match ( Section 2.3.2 ), since the client intends this precondition to prevent the method from being applied if there have been any changes to the representation data . This is geared towards web servers managing static resources, and is perfectly valid in that context. This statement however is not true for (business) applications which track changes to the underlying data independent from its wire-representation in different formats . These applications want to prevent accidental changes to the underlying data , and for this an ETag only needs to change if the underlying data changes, meaning that different representations of the same underlying data can share the same ETag. From the perspective of RFC7232 these representation-independent "sufficiently varying" ETags are weak ETags, which is why we deviate from RFC7232 in this aspect.  Notes from F2F discussion on 2018-09-28 Servers SHOULD use strong Etags for OData entities == "internal" Etag transported in @etag Clients SHOULD use @etag for If-Match Servers MUST accept both @etag and the header-etag for If-Match in single-entity responses servers SHOULD send @etag also in etag header If the serializer (especially for JSON) can produce byte-for-byte identical representations of the same underlying data Or if we ignore "byte-for-byte identical" and deem "JSON-equivalent" sufficient Multi-entity response == Collection or Expand Multi-entity response typically does not have etag header MAY have weak etag if caching needs to be supported MAY have strong etag for if-match Collection-response MAY have @etag for if-Match which MAY differ from the header-etag for caching Note: currently no @etag defined for collections in wrapper object, and Hubert uses/needs this

      Description

      ETags in response headers should be limited to use for cache validation

      ETags in response payload (instance annotations) should be limited to use for optimistic concurrency

      Conflating the two kinds of ETag leads us to difficulties

      In Section 8.2.4 Header If-Match:

      > Services sending ETag headers with weak ETags that only depend on the representation-independent entity state MUST use the weak comparison function because it is sufficient to prevent accidental overwrites. This is a deviation from [RFC7232].

      Difficulty: deviation from RFC7232. If we instead required that instance annotation etags be strong etags, and that If-Match only be used (for optimistic concurrency control) with strong etags, we would be compliant with both the draft and final RFC7232 specs. How could it be a strong etag if it depends on the representation-independent entity state? It could be so if we imagine that the representation-independent entity state has some kind of canonical form (which we never actually include in any request/response payload) and that the strong etag is a tag (e.g. version/hash) of that state.

      In Section 8.2.5 Header If-None-Match

      > “As defined in [RFC7232], a client MAY include an If-None-Match header in a request to GET, PUT, PATCH or DELETE. The value of the If-None-Match request header MUST be an ETag value previously retrieved for the resource, or “*”.

      Difficulty: apart from when “*” is used (to ensure non-existence of the resource), then the method should be GET and the purpose should be for cache validation. As such, it would seem to be important to use an ETag that came from a response header, not from response payload (in instance annotations).

      In Section 8.3.3 Header ETag

      > A response MAY include an ETag header, see [RFC7232]. Services MUST include this header if they require an ETag to be specified when modifying the resource.

      Difficulty: clients may wish to be able to do cache validation as well as optimistic concurrency. Requiring the ETag response header to be specified when modifying the resource doesn’t allow for the possibility that the client wants to use the ETag response header (which might be a content hash) for cache validation (e.g. GET using If-None-Match) and that the client wants to use an ETag from response payload (which might be a version number) for optimistic concurrency (e.g. PATCH using If-Match).

      In Section 11.5.4.1 Invoking an Action

      > To request processing of the action only if the binding parameter value, an entity or collection of entities, is unmodified, the client includes the If-Match header with the latest known ETag value for the entity or collection of entities. The ETag value for a collection as a whole is transported in the ETag header of a collection response.

      Difficulty: any ETag response header for a collection as a whole is likely to be only feasibly implemented as a hash of response payload. (At least any such ETag intended for use in cache validation would be such). Then suggesting that it be suitable for If-Match with an action invocation for some kind of optimistic concurrency control is probably not realistically implementable (suppose the collection response was for a subset of properties and the action request is to update some properties that weren’t included in the collection).

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              evan.ireland.2 Evan Ireland
            • Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: