diff --git a/spec/vulcain.md b/spec/vulcain.md index 14b676d..d918d9d 100644 --- a/spec/vulcain.md +++ b/spec/vulcain.md @@ -2,12 +2,13 @@ title = "The Vulcain Protocol" area = "Internet" workgroup = "Network Working Group" +submissiontype = "IETF" [seriesInfo] name = "Internet-Draft" -value = "draft-dunglas-vulcain-00" +value = "draft-dunglas-vulcain-01" stream = "IETF" -status = "informational" +status = "standard" [[author]] initials="K." @@ -19,9 +20,8 @@ organization = "Les-Tilleuls.coop" email = "kevin@les-tilleuls.coop" [author.address.postal] city = "Lille" - street = "2 rue Hegel" - code = "59000" - postalline= ["Bâtiment Canal"] + street = "82 rue Winston Churchill" + code = "59160" country = "France" %%% @@ -57,16 +57,87 @@ and [JSON:API](https://jsonapi.org/) allow the use of Web Linking [@!RFC5988] to references between resources. The `Preload` HTTP header allows the client to ask the server to transmit resources linked to the -main resource it will need as soon as possible. To do so, the `Preload` header `MUST` contain a -selector [#selectors] referencing links to resources that `SHOULD` be preloaded. +main resource it will need as soon as possible. -The server `MUST` recursively follow links referenced by the selector. When a selector traverses +`Preload` is a List Structured Header [@!I-D.ietf-httpbis-header-structure]. Its values `MUST` be +Strings (Section 3.3.3 of [@!I-D.ietf-httpbis-header-structure]). Its ABNF is: + +~~~ abnf +Preload = sf-list +sf-item = sf-string +~~~ + +Its values are selectors (#selectors) matching links to resources that `SHOULD` be preloaded. If a +value is an empty String, then all links of the current documents are matched. + +The server `MUST` recursively follow links matched by the selector. When a selector traverses several resources, all the traversed resources `SHOULD` be sent to the client. If several links referencing the same resource are selected, this resource `MUST` be sent at most once. The server `MAY` limit the number resources that it sends in response to one request. -Multiple selectors can be sent by passing multiple `Preload` HTTP headers. +Example: + +~~~ http +Preload: "/member/*/author", "/member/*/comments" +~~~ + +The following optional parameters are defined: + + * A Parameter whose name is `rel`, and whose value is a String (Section 3.3.3 + of [@!I-D.ietf-httpbis-header-structure]) or a Token (Section 3.3.4 of + [@!I-D.ietf-httpbis-header-structure]), conveying the expected relation type of the selected + links. + + * A Parameter whose name is `hreflang`, and whose value is a String (Section 3.3.3 of + [@!I-D.ietf-httpbis-header-structure]), conveying the expected language of the selected links. + + * A Parameter whose name is `type`, and whose value is a String (Section 3.3.3 of + [@!I-D.ietf-httpbis-header-structure]), conveying the expected media type of the selected links. + +The `rel` parameter contains a relation type as defined in [@!RFC5988]. If this parameter is +provided, the server `SHOULD` preload only relations matched by the provided selector and having +this type. + +The `hreflang` parameter contains a language as defined in [@!RFC5988]. If this parameter is +provided, the server `SHOULD` preload only relations matched by the provided selector and in this +language. When possible (for instance, when doing a HTTP/2 Server Push), the server `SHOULD` set +the `Accept-Language` request header to this value. If the `hreflang` parameter isn't provided but +the server is able to guess the expected language of the relation using other mechanisms (such as +the `hreflang` attribute defined by the Atom format for the `atom:link` element, [@RFC4287] Section +4.2.7.4), then the `Accept-Language` request header `SHOULD` be set to the guessed value. + +The `type` parameter contains a media type as defined in [@!RFC5988]. If this parameter is provided, +the server `SHOULD` preload only relations matched by the provided selector and having this media +type. When possible (for instance, when doing a HTTP/2 Server Push), the server `SHOULD` set the +`Accept` request header to this value. If the `type` parameter isn't provided but the server is +able to guess the expected media type of the relation using other mechanisms (such as the `type` +attribute defined by the Atom format for the `atom:link` element, [@RFC4287] Section 4.2.7.3), then +the `Accept` request header `SHOULD` be set to the guessed value. + +If several parameters are provided for the same selector, the server `SHOULD` preload only relations +matching the selector and constraints hinted by the parameters. + +Examples: + +~~~ http +Preload: "/member/*/author"; hreflang="fr-FR" +Preload: "/member/*/author/avatar"; type="image/webp" +~~~ + +The server `SHOULD` preload all links matched by the `/member/*/author` selector and having a lang +of `fr-FR`, as well as all links matching the `/member/*/author/avatar` selector and having a type +of `image/webp`. + +~~~ http +Preload: ""; rel=author +Preload: ""; rel="https://example.com/custom-rel" +~~~ + +The server `SHOULD` preload all links of the requested resource having the relation type `author` or +`https://example.com/custom-rel`. + +## Preload Example Considering the following resources: @@ -113,7 +184,7 @@ requested one: ~~~ http GET /books/ HTTP/2 -Preload: /member/*/author +Preload: "/member/*/author" ~~~ In addition to `/books`, the server `SHOULD` use HTTP/2 Server Push to push the `/books/1`, @@ -124,20 +195,18 @@ Server Push requests generated by the server for related resources `MUST` includ selector in a `Preload` HTTP header. When requesting a pushed relation, the client `MUST` compute the remaining selector and pass it in the `Preload` header. -Example: - Explicit Request: ~~~ http GET /books/ HTTP/2 -Preload: /member/*/author +Preload: "/member/*/author" ~~~ Request to a relation generated by the server (for the push) and the client: ~~~ http GET /books/1 HTTP/2 -Preload: /author +Preload: "/author" ~~~ ## Using Preload Link Relations @@ -154,11 +223,15 @@ Server Push. The `Fields` HTTP header allows the client to ask the server to return only the specified fields of the requested resource, and of the preloaded related resources. +The `Fields` HTTP header is a List Structured Header accepting the exact same values than the +`Preload` HTTP header defined in (#preload). + The `Fields` HTTP header `MUST` contain a selector (see #Selector). The server `SHOULD` return only the fields matching this selector. -Multiple `Fields` HTTP headers can be passed. All fields matching at least one of these headers -`MUST` be returned. Other fields of the resource `MAY` be omitted. +All matched fields `MUST` be returned if they exist. Other fields of the resource `MAY` be omitted. + +## Fields Example Considering the following resources: @@ -185,9 +258,9 @@ And the following HTTP request: ~~~ http GET /books/1 HTTP/2 -Preload: /author -Fields: /author/familyName -Fields: /genre +Preload: "/author" +Fields: "/author/familyName" +Fields: "/genre" ~~~ The server must return a response containing the following JSON document: @@ -217,14 +290,14 @@ Explicit Request: ~~~ http GET /books/ HTTP/2 -Fields: /member/*/author +Fields: "/member/*/author" ~~~ Request to a relation generated by the server (for the push) and the client: ~~~ http GET /books/1 HTTP/2 -Fields: /author +Fields: "/author" ~~~ # Selectors @@ -243,7 +316,7 @@ server to use a specific selector format: GET /books/1 HTTP/2 Accept: text/xml Prefer: selector=css -Fields: brand > name +Fields: "brand > name" ~~~ If no explicit preferences have been passed, the server `MUST` assume that the selector format is @@ -295,31 +368,59 @@ complexity of requests executed by the server. # Query Parameters Another option available to clients is to utilize Request URI query-string parameters to pass -preload and fields selectors. The `preload` and `query` parameters `MAY` be used to pass selectors -corresponding respectively to the `Preload` and `Fields` HTTP headers. To pass multiple selectors, -parameters can be passed multiple times. +preload and fields selectors. + +The `preload` and `query` parameters `MAY` be used to pass selectors corresponding respectively to +the `Preload` and `Fields` HTTP headers. Valid values for these query parameters are exactly the +same than the ones defined of the `Preload` and `Fields` HTTP headers. -Example: `/books/1?fields=/title&fields=/author&preload=/author` +In conformance with the Section 3.4 of the URI RFC [@!RFC3986], values of query parameters `MUST` be +percent-encoded. To pass multiple selectors, parameters can be passed multiple times. + +Example: `/books/1?fields=%22%2Ftitle%22&fields=%22%2Fauthor%22&preload=%22%2Fauthor%22` When using query parameters, the server `MUST` pass the remaining part of the selector as parameter of the generated link. +`Preload` and `Fields` HTTP headers aren't [CORS safe-listed +request-headers](https://fetch.spec.whatwg.org/#cors-safelisted-request-header). Query parameters, +on the other hand, allow to send cross-site requests that don't trigger preflight requests. Also, +query parameters don't require clients to compute the remaining part of the selector when requesting +relations. + +However, support for query parameters can be challenging to implement by servers (links contained in +served documents `MUST` be modified) and generate URLs that are hard to read for a human. + +Altering the URI can also have undesirable effects. + +For these reasons, using HTTP headers `SHOULD` be preferred. Support for query parameters is +`OPTIONAL`. A server supporting query parameters `MUST` also support the corresponding HTTP headers. + Example: ~~~ http -GET /books/?preload=/member/*/author HTTP/2 +GET /books/?preload=%22%2Fmember%2F%2A%2Fauthor%22 HTTP/2 { "member": { - "/books/1?preload=/author", - "/books/1?preload=/author" + "/books/1?preload=%22%2Fauthor%22", + "/books/1?preload=%22%2Fauthor%22" } } ~~~ -As altering the URI can have undesirable effects, using HTTP headers `SHOULD` be preferred. Support -for query parameters is `OPTIONAL`. A server supporting query parameters `MUST` also support the -corresponding HTTP headers. +Example using parameters: + +~~~ http +GET /books/?preload=%22%2Fmember%2F%2A%22%3B%20rel%3Dauthor HTTP/2 + +{ + "member": { + "/books/1?preload=%22%22%3B%20rel%3Dauthor", + "/books/1?preload=%22%22%3B%20rel%3Dauthor" + } +} +~~~ # Computing Links Server-Side @@ -373,4 +474,111 @@ registry defined in [@!RFC3864]. A selector registry could also be added. +# Implementation Status + +[RFC Editor Note: Please remove this entire section prior to publication as an RFC.] + +This section records the status of known implementations of the protocol defined by this +specification at the time of posting of this Internet-Draft, and is based on a proposal described +in [@RFC6982]. The description of implementations in this section is intended to assist the IETF in +its decision processes in progressing drafts to RFCs. Please note that the listing of any individual +implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to +verify the information presented here that was supplied by IETF contributors. This is not intended +as, and must not be construed to be, a catalog of available implementations or their features. +Readers are advised to note that other implementations may exist. According to RFC 6982, "this will +allow reviewers and working groups to assign due consideration to documents that have the benefit +of running code, which may serve as evidence of valuable experimentation and feedback that have +made the implemented protocols more mature. It is up to the individual working groups to use this +information as they see fit." + +## Vulcain Gateway Server + +Organization responsible for the implementation: + +Les-Tilleuls.coop + +Implementation Name and Details: + +Vulcain.rocks, available at + +Brief Description: + +A gateway server allowing to add support for the Vulcain protocol to any existing API. It is written +in Go and is optimized for performance. + +Level of Maturity: + +Beta. + +Coverage: + +All the features of the protocol as well as the extended JSON pointer selector. + +Version compatibility: + +The implementation follows the draft version 00. + +Licensing: + +All code is covered under the GNU Affero Public License version 3 or later. + +Implementation Experience: + +Used in production. + +Contact Information: + +Kévin Dunglas, [kevin+vulcain@dunglas.fr](mailto:kevin+vulcain@dunglas.fr) + +Interoperability: + +Reported compatible with all major browsers and server-side tools. + +## Helix Vulcain Filters + +Organization responsible for the implementation: + +Adobe + +Implementation Name and Details: + +Helix Vulcain Filters, available at + +Brief Description: + +Vulcain-like filters for OpenWhisk web actions. + +Level of Maturity: + +Stable. + +Coverage: + +HTTP headers as well as the extended JSON pointer selector. + +Version compatibility: + +The implementation follows the draft version 00. + +Licensing: + +All code is covered under the Apache License 2.0. + +Implementation Experience: + +Used in production. + +Contact Information: + + + +Interoperability: + +Reported compatible with all major browsers and server-side tools. + +# Acknowledgements + +The author would like to thank Evert Pot, who authored the Prefer-Push Internet-Draft from which +some parts of this specification is inspired, and André R. who gave good design ideas. + {backmatter}