braid-spec icon indicating copy to clipboard operation
braid-spec copied to clipboard

Maybe add Accept-Range-Patch header

Open mitar opened this issue 6 years ago • 8 comments

For server to announce that it accepts range patches, more precisely, that which range units it accepts for non-GET requests.

  • How do we communicate which non-GET requests accept range units?
  • Should we have this header, or something else which tells that resource is Braid-enabled more in general? Or both?

mitar avatar Nov 03 '19 07:11 mitar

@mitar Can you please provide example use-cases for this? Or shall we close it?

toomim avatar Feb 13 '21 08:02 toomim

So the idea is that you should know that server supports different and which range units.

mitar avatar Feb 13 '21 17:02 mitar

I understand the idea, but I would really like to see some use-cases for it so that we can prioritize. (edited)

toomim avatar Feb 13 '21 20:02 toomim

I mean, that comes from our work on the spec. We are extending range header to non-GET requests. it is important for the server to communicate that it supports that. So this is motivated by the correctness of the protocol, not from an use case.

mitar avatar Feb 13 '21 21:02 mitar

@mitar Are you aware of the Range-Request-Allow-Methods and Range-Request-Allow-Units headers that are currently in the range-patch spec? These seem to do the same thing.

Link: https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-range-patch-01.txt#L500

It looks like @brynbellomy contributed these headers to the draft on the same day as this issue was created.

I'm also noticing that most of what we want here could be provided by the existing Accept-Patch header defined in rfc5789 Section 3.1. This header seems to have two advantages over the options we've specified so far:

  1. it works for arbitrary patch formats; not just Range-Patch
  2. and it is already a standard in HTTP

However, I see two things currently lacking with Accept-Patch:

  1. In order to say that a server accepts a range-patch, we need a media type for range patches, so that we can say something like Accept-Patch: application/range-patch; unit=json. Note that the media-type would need to specify the range unit as well for it to work with Accept-Patch.
  2. Accept-Patch only specifies which patch types are accepted by a server; not which HTTP methods are allowed (as in Range-Request-Allow-Methods)

Yet, when I zoom out, I don't see any actual use-case for (2), where a server needs to specify that it will accept a patch for some methods but not for others. The only possible methods that could get listed here are PUT, PATCH, and POST. If a server can support patches at one of these, it can probably support patches at the others, and if not, it seems like that'd be a part of the server's API documentation and not something that needs to be auto-discovered in an OPTIONS request. Can someone please correct me if I'm wrong about this?

I also noticed that the existing media-type we've specified for range patches doesn't meet the needs of (1), because they don't include the range units. As far as I can see, we have specified these definitions of a range patch:

  • application/json+patch defined here and here
  • Content-Type: multipart/byteranges mentioned here

Thus, it seems that instead of these new headers, we could just define a media-type for a range-patch that can be parameterized with its range-unit. Then the existing Accept-Patch header would suffice for advertising support of any patch, including range patches. This would give us one less thing to take through the standardization process.

I'd love to get a reality check here, though. @mitar and @brynbellomy does this reasoning make sense to you?

toomim avatar Feb 21 '21 01:02 toomim

Hmm, I've realized that this issue also connects with @brynbellomy's way of requesting that a server return patches vs. full state snapshots. Bryn currently adds this information to the Subscribe: header (as described here):

  • Subscribe: states
  • Subscribe: txs
  • Subscribe: states,txs

In this model, the client specifies states to request full state snapshots, and txs to request patches.

However, if the server can specify which types of patches it is capable of accepting with the Accept-Patch header, then it stands to reason that a client might also pass an Accept-Patch header to specify which types of patches it's capable of receiving.

This header hasn't been necessary in HTTP until Braid, because patches have only been sent from client-to-server, never from server-to-client. But now that we're sending patches in the opposite direction, it would make sense to just make the protocol symmetric, and use the same header for a client to advertise its capabilities that a server uses to advertise its own capabilities.

Thus, after all these discoveries, I'm proposing that we make the following changes to the spec:

  • Specify that servers use the Accept-Patch header to specify which patch types it accepts
  • Specify that clients use the Accept-Patch header to specify which patch types they want in response
  • Add a media-type for range patches that is parameterized by range unit, e.g. application/range-patch; unit=json

This re-uses existing HTTP headers, and gives us a (perhaps) useful new content-type for range patches. It doesn't allow a server to specify which methods support which patch types, but that doesn't seem necessary. Please correct me if I'm missing something.

toomim avatar Feb 21 '21 02:02 toomim

Ooo, here's another discovery: HTTP already has an Accept-Ranges header that can specify the range units a server accepts. Example:

Accept-Ranges: json

So if we create a range-patch media type, then a server could advertise that it supports json range patches with:

Accept-Patch: multipart/range-patch
Accept-Ranges: json

I do feel it's a little odd to invent a media-type for a range patch. However, there's already some precedent in existing HTTP range requests to return multipart byte ranges with the multipart/byteranges media type: https://tools.ietf.org/html/rfc7233#appendix-A

On the other hand, it seems that multipart formats are required to have byte-boundary separators:

   In the case of multipart entities, in which one or more different
   sets of data are combined in a single body, a "multipart" media type
   field must appear in the entity's header.  The body must then contain
   one or more body parts, each preceded by a boundary delimiter line,
   and the last one followed by a closing boundary delimiter line.

https://tools.ietf.org/html/rfc2046#section-5.1

And this rfc2046 stuff is explicitly required of all multipart media-types in rfc6838:

   Multipart and message are composite types; that is, they provide a
   means of encapsulating zero or more objects, each one a separate
   media type.

   All subtypes of multipart and message MUST conform to the syntax
   rules and other requirements specified in [RFC2046] and amended by
   Section 3.5 of [RFC6532].

https://tools.ietf.org/html/rfc6838#section-4.2.6

toomim avatar Feb 21 '21 06:02 toomim

I've found a clear (and perhaps obvious) use-case. This header prevents data loss.

If a server does not understand how to accept a range-patch, then a PUT with a range could obliterate the existing content, instead of patching it.

Thus, clients will want to check whether unknown resources support range patches, with a header like this, before sending them.

toomim avatar Aug 13 '23 08:08 toomim