From 6712444c6515b3072cea17450f1686a749e61252 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 26 May 2022 17:46:49 +0100 Subject: [PATCH] Editorial: refactor `Link` header processing to be declared per-type See #7890 for more refactoring follow-up work. --- source | 757 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 470 insertions(+), 287 deletions(-) diff --git a/source b/source index 3b91edda9c8..9aed02e8141 100644 --- a/source +++ b/source @@ -14382,14 +14382,127 @@ interface HTMLLinkElement : HTMLElement {
Processing `Link` headers
-

The processing of `Link` headers apart from preload and preconnect, in - particular their influence on a Document's script-blocking style sheet - counter, is not defined. See issue - #4224 for discussion on integrating this into the spec.

+

All link types that can be external resource + links define a process a link header algorithm, which takes a link + processing options. This algorithm defines whether and how they react to appearing in an + HTTP `Link` response header.

-

To extract links from headers given - header list headers:

+

The processing of `Link` headers is not defined for + all link relation types. In particular some implementations might process types that have a no-op + process link headers algorithm, and in doing so influence a Document's + script-blocking style sheet counter. See + issue #4224 for discussion on + integrating this into the spec.

+ +

A link processing options is a struct. It has the following + items:

+ +
+
href (default the empty string)
+
destination (default the empty string)
+
initiator (default "link")
+
integrity (default the empty string)
+
type (default the empty string)
+
A string
+ +
crossorigin (default No CORS)
+
A CORS settings attribute state
+ +
source set (default null)
+
Null or a source set
+ +
base URL
+
A URL
+ +
origin
+
An origin
+ +
environment
+
An environment
+ +
policy container
+
A policy container
+ +
document (default null)
+
Null or a Document
+ +
on document ready (default null)
+
Null or an algorithm accepting a Document
+
+ +

A link processing options has a base URL and an href + rather than a parsed URL because the URL could be a result of the options's source set.

+ +

To create link options from element given a link element + el:

+ +
    +
  1. Let document be el's node document.

  2. + +
  3. +

    Let options be a new link processing options with

    + +
    +
    destination
    +
    the result of translating the + state of el's as attribute
    + +
    crossorigin
    +
    the state of el's crossorigin + content attribute
    + +
    source set
    +
    el's source set
    + +
    base URL
    +
    document's URL
    + +
    origin
    +
    document's origin
    + +
    environment
    +
    document's relevant settings object
    + +
    policy container
    +
    document's policy container
    + +
    document
    +
    document
    +
    +
  4. + +
  5. If el has an href attribute, then set + options's href to the value of + el's href attribute.

  6. + +
  7. If el has an integrity attribute, + then set options's integrity to the + value of el's integrity content + attribute.

  8. + +
  9. If el has a type attribute, then set + options's type to the value of + el's type attribute.

  10. + +
  11. +

    Assert: options's href is not the empty + string, or options's source set is not + null.

    + +

    A link element with neither an href or an + imagesrcset does not represent a link.

    +
  12. + +
  13. Return options.

  14. +
+ +

To extract links from headers given a header + list headers:

  1. Let links be a new list.

  2. @@ -14407,10 +14520,6 @@ interface HTMLLinkElement : HTMLElement {
  3. Let linkObject be the result of parsing linkHeader.

  4. -
  5. If linkObject["relation_type"] is not "preload" or "preconnect", - then continue.

  6. -
  7. If linkObject["target_uri"] does not exist, then continue.

  8. @@ -14426,16 +14535,19 @@ interface HTMLLinkElement : HTMLElement { "pre-media" or "media" phase:

      -
    1. Let links be the result of - extracting links from response's - header list.

    2. +
    3. Let links be the result of extracting links from response's header list.

    4. For each linkObject in links:

        -
      1. Let attribs be - linkObject["target_attributes"].

      2. +
      3. Let rel be linkObject["relation_type"].

      4. + +
      5. Let attribs be linkObject["target_attributes"].

      6. Let expectedPhase be "media" if either "srcset", "HTMLLinkElement : HTMLElement { does not match the environment, then continue.

      7. -
      8. Let element be the result of creating an - element given doc, link, and the HTML - namespace.

      9. +
      10. +

        Let options be a new link processing options with

        -
      11. Set an attribute value for - element using "href" and - linkObject["target_uri"].

      12. +
        +
        href
        +
        linkObject["target_uri"]
        -
      13. Set an attribute value for - element using "rel" and - linkObject["relation_type"].

      14. - -
      15. For each entry in attribs: if - entry[0] is "as", "type", "crossorigin", "imagesizes", "blocking", "integrity", "imagesrcset", or "media", then set an attribute value for - element using entry[0] and entry[1].

      16. +
        base URL
        +
        doc's URL
        -
      17. Fetch and process - el.

      18. +
        origin
        +
        doc's origin
        + +
        environment
        +
        doc's relevant settings object
        + +
        policy container
        +
        doc's policy container
        + +
        document
        +
        doc
        +
        + + +
      19. Apply link options from parsed header attributes to options + given attribs.

      20. + +
      21. If attribs["imagesrcset"] exists and attribs["imagesizes"] exists, + then set options's source set to the + result of creating a source set given + linkObject["target_uri"], attribs["imagesrcset"], and attribs["imagesizes"].

      22. + +
      23. Run the process a link header steps for rel given + options.

    +

    To apply link options from parsed header attributes to a link processing + options options given attribs:

    + +
      +
    1. If attribs["as"] exists, then set options's destination to the result of translating attribs["as"].

    2. + +
    3. If attribs["crossorigin"] exists and is an ASCII case-insensitive match for one of + the CORS settings attribute keywords, + then set options's crossorigin to the + CORS settings attribute state corresponding to that keyword.

    4. + +
    5. If attribs["integrity"] exists, then set options's integrity to attribs["integrity"].

    6. + +
    7. If attribs["type"] exists, then set options's type to attribs["type"].

    8. +
    + + +
    Early hints

    Early hints allow user-agents to perform some operations, such as to speculatively @@ -14537,7 +14690,6 @@ data-x="rel-preload">preload; as=font< the style will not be accessible to the document.

    -

    To process early hint headers given a response response and an environment reservedEnvironment:

    @@ -14564,7 +14716,7 @@ data-x="rel-preload">preload; as=font< headers">extracting links from response's header list.

    -
  9. Let uncommittedPreloads be an empty list.

  10. +
  11. Let earlyHints be an empty list.

  12. For each linkObject in links:

    @@ -14579,6 +14731,34 @@ data-x="rel-preload">preload; as=font< committed as soon as it becomes available.

      +
    1. Let rel be linkObject["relation_type"].

    2. + +
    3. +

      Let options be a new link processing options with

      + +
      +
      href
      +
      linkObject["target_uri"]
      + +
      initiator
      +
      "early-hint"
      + +
      base URL
      +
      response's URL
      + +
      origin
      +
      response's URL's origin
      + +
      environment
      +
      reservedEnvironment
      + +
      policy container
      +
      earlyPolicyContainer
      +
      +
    4. +
    5. Let attribs be linkObject["target_attributes"].

      @@ -14594,104 +14774,31 @@ data-x="rel-preload">preload; as=font< created.

    6. -
    7. Let crossorigin be attribs["crossorigin"] if attribs["crossorigin"] exists, - or the empty string otherwise.

    8. - -
    9. Let url be the result of parsing - linkObject["target_uri"] relative to response's - URL.

    10. - -
    11. If linkObject["relation_type"] is "preconnect", then preconnect to url - given crossorigin and response's url's origin, and - continue.

    12. - -
    13. Assert: linkObject["relation_type"] is "preload".

    14. - -
    15. If attribs["as"] does not exist, then continue.

    16. - -
    17. Let destination be attribs["as"].

    18. - -
    19. If destination is not a destination, continue.

    20. - -
    21. Let earlyRequest be the result of creating a potential-CORS request given url, - destination, and crossorigin.

    22. - -
    23. Set earlyRequest's policy - container to earlyPolicyContainer.

    24. - -
    25. Let type be the empty string.

    26. - -
    27. If attribs["type"] exists, then set type to - attribs["type"].

    28. - -
    29. If attribs["integrity"] exists, then set earlyRequest's integrity metadata to - attribs["integrity"].

    30. +
    31. Apply link options from parsed header attributes to options + given attribs.

    32. -
    33. Let unsafeEndTime be 0.

    34. - -
    35. Let earlyResponse be null.

    36. - -
    37. Let processResponse given response - res be to set earlyResponse to res.

    38. - -
    39. -

      Append the following steps given Document - document to uncommittedPreloads:

      - -
        -
      1. Let entry be new preload entry whose - integrity metadata is - earlyRequest's integrity metadata.

      2. - -
      3. -

        Let respond be the following steps given response response:

        - -
          -
        1. Finalize and report timing given response, - document's relevant global object, "early-hint", and unsafeEndTime.

        2. - -
        3. If entry's on response - available is null, then set entry's response to response; otherwise call entry's on response available given - response.

        4. -
        -
      4. +
      5. Run the process a link header steps for rel given + options.

      6. -
      7. Let key be the result of creating a - preload key given earlyRequest.

      8. +
      9. Append options to + earlyHints.

      10. +
      +
    40. -
    41. Set document's map of preloaded resources[key] to - entry.

    42. +
    43. +

      Return the following substeps given Document doc: for each options in earlyHints:

      -
    44. If earlyResponse is null, then set processResponse to - respond; otherwise call respond with earlyResponse.

    45. -
    -
  13. +
      +
    1. If options's on document ready is null, then set + options's document to + docs.

    2. -
    3. Preload earlyRequest given - type and the following steps given response - res: set unsafeEndTime to the unsafe shared current time and - call processResponse with res.

    4. +
    5. Otherwise, call options's on document ready with doc.

    - -
  14. Return uncommittedPreloads.

@@ -25563,6 +25670,9 @@ document.body.appendChild(wbr);
  • Return true.

  • +

    The process a link header steps for this type of linked resource are to do + nothing.

    +

    In the absence of a link with the icon keyword, for Document objects whose URL's scheme is an HTTP(S) scheme, user agents may @@ -25761,6 +25871,9 @@ document.body.appendChild(wbr); and response.

    +

    The process a link header steps for this type of linked resource are to do + nothing.

    + @@ -25880,6 +25993,9 @@ document.body.appendChild(wbr); data-x="event-load">load at the link element.

    +

    The process a link header steps for this type of linked resource are to do + nothing.

    +
    @@ -26068,41 +26184,44 @@ document.body.appendChild(wbr);

    The fetch and process the linked resource steps for this type of linked resource, - given a link element el, are:

    + given a link element el, are to create link options from el and + to preconnect given the result.

    -
      -
    1. Let urlRecord be the result of parsing - el's href attribute, relative to el's - node document.

    2. +

      The process a link header step for this type of linked resource given a link processing options options are to + preconnect given options.

      -
    3. If urlRecord is not failure, then preconnect to - urlRecord given the current state of el's crossorigin attribute and el's node - document's origin.

    4. -
    - -

    To preconnect to a URL urlRecord given a CORS - settings attribute state crossOrigin and an origin - documentOrigin:

    +

    To preconnect given a link processing options options:

      -
    1. If urlRecord's scheme is not an +

    2. If options's + href is an empty string, returns.

    3. + +
    4. Parse options's + href relative to options's + base URL and let url be the + resulting URL record. If this fails, return. + +
    5. If url's scheme is not an HTTP(S) scheme, then return.

    6. Let partitionKey be the result of determining the network partition key given el's node - document's relevant settings object.

    7. + partition key">determining the network partition key given options's + environment.

    8. Let useCredentials be true.

    9. -
    10. If crossOrigin is not Anonymous and documentOrigin does not have - the same origin as urlRecord's origin, then set useCredentials to false.

    11. +
    12. If options's crossorigin is not + Anonymous and options's origin does not + have the same origin as url's + origin, then set useCredentials to + false.

    13. The user agent should obtain a connection given partitionKey, - urlRecord's origin, and + url's origin, and useCredentials.

      This connection is obtained but not used directly. It will remain in the @@ -26308,43 +26427,7 @@ document.body.appendChild(wbr);

    14. Return true.

    -

    To preload a resource given a request - request, a string type and processResponse, which is an algorithm - accepting a response:

    - -
      -
    1. If type doesn't match - request's destination, then - return.

    2. - -
    3. Fetch request, with - processResponseConsumeBody - set to the following steps given response - response and null or byte sequence bytesOrNull:

      - -
        -
      1. -

        If bytesOrNull is a byte sequence, then set response's - body to the first return value of safely extracting bytesOrNull.

        - -

        By using processResponseConsumeBody, - we have extracted the entire body. This is necessary to ensure the preloader loads the - entire body from the network, regardless of whether the preload will be consumed (which is - uncertain at this point). This step then resets the request's body to a new body containing the - same bytes, so that other specifications can read from it at the time of actual consumption, - despite us having already done so once.

        -
      2. - -
      3. Otherwise, set response to a network error.

      4. - -
      5. Call processResponse with response.

        -
      -
    4. -
    - -

    For the purposes of the above algorithm, a string type +

    For the purposes of this section, a string type matches a string destination if the following algorithm returns true:

      @@ -26396,88 +26479,160 @@ document.body.appendChild(wbr); credentials mode is request's credentials mode.

      -

      The fetch and process the linked resource steps for this type of linked resource, - given a link element el, are:

      +

      To preload given a link processing options options and + an optional processResponse, which is an algorithm accepting a response:

        -
      1. Let as be the current state of el's as attribute.

      2. +
      3. If options's destination is not + a destination, then return.

      4. -
      5. If as does not represent a state, return false.

      6. +
      7. If options's type doesn't match options's destination, then return.

      8. -
      9. Let request be the result of creating a link element request given el and the result - of translating - as.

      10. +
      11. Let href be options's href.

      12. -
      13. If request is null, then return.

      14. +
      15. If options's destination is + "image" and options's source set is not null, then set href + to the result of selecting an image source from + options's source set.

      16. -
      17. -

        If as is "image", then:

        +
      18. If href is an empty string, return.

      19. -
          -
        1. Let selected source and selected pixel density be the URL and - pixel density that results from selecting an image - source given el, respectively.

        2. +
        3. Parse href relative to + options's base URL. If that fails, then + return. Otherwise let url be the resulting URL record.

        4. -
        5. If selected source is null, then return false.

        6. +
        7. Let unsafeEndTime be 0.

        8. -
        9. Parse selected source, relative to - el's node document. If that fails, then return false. Otherwise, let - url be the resulting URL record.

        10. +
        11. Let response be "pending".

        12. -
        13. Set request's URL to - url.

        14. -
        - +
      20. Let request be the result of creating a potential-CORS request given url, destination, + and options's crossorigin.

      21. + +
      22. Set request's policy + container to options's policy container.

      23. + +
      24. Set request's integrity metadata to options's + integrity.

      25. -
      26. Let preloadKey be the result of creating a +

      27. Let entry be a new preload entry whose + integrity metadata is options's + integrity.

      28. + +
      29. Let key be the result of creating a preload key given request.

      30. -
      31. Let preloadEntry be a new preload entry whose - integrity metadata is request's integrity metadata.

      32. +
      33. Let finalize be the following step given a Document + document and a response response: + finalize and report timing given response, + document's relevant global object, options's + initiator, and unsafeEndTime.

      34. -
      35. Set el's node document's map - of preloaded resources[preloadKey] to preloadEntry.

      36. +
      37. +

        Fetch request, with processResponseConsumeBody set to the following steps + given a response response and null, failure, + or a byte sequence bytesOrNull:

        -
      38. Let type be the empty string.

      39. +
          +
        1. +

          If bytesOrNull is a byte sequence, then set response's + body to the first return value of safely extracting bytesOrNull.

          + +

          By using processResponseConsumeBody, + we have extracted the entire body. This is necessary to ensure the preloader loads the + entire body from the network, regardless of whether the preload will be consumed (which is + uncertain at this point). This step then resets the request's body to a new body containing the + same bytes, so that other specifications can read from it at the time of actual consumption, + despite us having already done so once.

          +
        2. -
        3. If el has a type attribute, then set - type to the value of el's type - attribute.

        4. +
        5. Otherwise, set response to a network error.

        6. + +
        7. Set unsafeEndTime to the unsafe shared current time.

        8. + +
        9. If options's document is not + null, then call finalize given options's document and response.

        10. + +
        11. If entry's on response + available is null, then set entry's response to response; otherwise call entry's on response available given + response.

        12. + +
        13. If processResponse is given, then call processResponse with + response.

        14. +
        +
      40. -

        Preload request, given type - and the following steps given response - response:

        +

        Let commit be the following steps given a Document + document:

          -
        1. Finalize and report timing with response, given el's - relevant global object and "link".

        2. +
        3. If entry's response is not null, then + call finalize given document and entry's + response.

        4. -
        5. If preloadEntry's on response - available is null, then set preloadEntry's response to response.

        6. +
        7. Set document's map of preloaded resources[key] to + entry.

        8. +
        +
      41. -
      42. Otherwise, call preloadEntry's on response available with response.

      43. +
      44. If options's document is null, then set options's on document ready to commit. + Otherwise call commit with options's document.

      45. +
      + +

      The fetch and process the linked resource steps for this type of linked resource, + given a link element el, are:

      + +
        +
      1. Update the source set for el.

      2. + +
      3. Let options be the result of creating link options from + el.

      4. +
      5. +

        Preload options, with the following steps given a response response: + +

        1. -

          If response is a network error, fire an event named error at el. Otherwise, fire an event named load - at el.

          +

          If response is a network error, fire an event named error at el. Otherwise, fire an event named + load at el.

          -

          The actual browsers' behavior is different from the spec here, and the - feasibility of changing the behavior has not yet been investigated. See issue #1142.

          +

          The actual browsers' behavior is different from the spec here, and the + feasibility of changing the behavior has not yet been investigated. See issue #1142.

      +

      The process a link header step for this type of link + given a link processing options options + is to preload options.

      + +
      Link type "prerender"
      @@ -26732,6 +26887,9 @@ document.body.appendChild(wbr);
    1. Unblock rendering on el.

    +

    The process a link header steps for this type of linked resource are to do + nothing.

    +
    @@ -30000,30 +30158,58 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...Selecting an image source -

    When asked to select an image source for a given img or - link element el, user agents must do the following:

    +

    To select an image source given an img element el:

    1. Update the source set for el.

    2. -
    3. If el's source set is empty, - return null as the URL and undefined as the pixel density.

    4. +
    5. If el's source set is empty, return null as the URL and undefined + as the pixel density.

    6. + +
    7. Return the result of selecting an + image from el's source set.

    8. +
    -
  • Otherwise, take el's source set - and let it be source set.

  • +

    To select an image source from a source set given a source set + sourceSet:

    -
  • If an entry b in source set has the same associated pixel - density descriptor as an earlier entry a in source set, then remove - entry b. Repeat this step until none of the entries in source set have the +

      +
    1. If an entry b in sourceSet has the same associated pixel + density descriptor as an earlier entry a in sourceSet, then remove + entry b. Repeat this step until none of the entries in sourceSet have the same associated pixel density descriptor as an earlier entry.

    2. -
    3. In a user agent-specific manner, - choose one image source from source set. - Let this be selected source.

    4. +
    5. In an implementation-defined manner, choose one image source + from sourceSet. Let this be selectedSource.

    6. -
    7. Return selected source and its associated pixel density.

    8. +
    9. Return selectedSource and its associated pixel density.

    +
    Creating a source set from attributes
    + +

    When asked to create a source set given a string default source, a string + srcset and a string sizes:

    + +
      +
    1. Let source set be an empty source set.

    2. + +
    3. If srcset is not an empty string, then set + source set to the result of parsing + srcset.

    4. + +
    5. Let source size be the result of parsing sizes.

    6. + +
    7. If default source is not the empty string and + source set does not contain an image source with a pixel + density descriptor value of 1, and no image source with a width + descriptor, append default source to source set.

    8. + +
    9. Normalize the source densities of source set.

    10. + +
    11. Return source set.

    12. +
    +
    Updating the source set
    @@ -30048,27 +30234,25 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...If child is el:

      -
    1. Let source set be an empty source set.

    2. +
    3. Let srcset be the empty string.

    4. -
    5. If child has a srcset or imagesrcset attribute, parse child's srcset attribute and set - source set to the returned source set.

    6. +
    7. Let sizes be the empty string.

    8. -
    9. Parse child's sizes - attribute, and let source set's source size be the returned - value.

    10. +
    11. If el has a srcset or imagesrcset attribute, set srcset to that + attribute.

    12. -
    13. If child has a src or href attribute whose value is not the empty string and - source set does not contain an image source with a pixel - density descriptor value of 1, and no image source with a width - descriptor, append child's src or href attribute value to source set.

    14. +
    15. If el has a sizes or imagesizes attribute, set sizes to that + attribute.

    16. -
    17. Normalize the source densities of source set.

    18. +
    19. If el has a src or href attribute, set href to that + attribute.

    20. -
    21. Let el's source set be source set.

    22. +
    23. Let el's source set be the result of creating a source set given + href, srcset and sizes.

    24. Return.

      @@ -88573,9 +88757,8 @@ interface Location { // but see also response -
      uncommitted preloads
      -
      null or a list of algorithms representing early preloaded links, to be committed - once the Document has been created
      +
      commit early hints
      +
      null or an algorithm accepting a Document, once it has been created

      Once a navigation params struct is created, this standard does not @@ -88870,7 +89053,7 @@ interface Location { // but see also has cross-origin redirects is false, and uncommitted preloads is null.

    25. + data-x="navigation-params-commit-early-hints">commit early hints is null.

    26. Run process a navigate response with navigationType, allowedToDownload, hasTransientActivation, and @@ -88931,7 +89114,7 @@ interface Location { // but see also has cross-origin redirects is false, and uncommitted preloads is null.

    27. + data-x="navigation-params-commit-early-hints">commit early hints is null.

    28. Run process a navigate response with navigationType, allowedToDownload, hasTransientActivation, and @@ -89046,7 +89229,7 @@ interface Location { // but see also to null.

    29. -

      Set uncommittedPreloads to null.

      +

      Set commitEarlyHints to null.

      Preloaded links from early hint headers remain in the preload cache after a same origin redirect, but @@ -89144,7 +89327,7 @@ interface Location { // but see also fetch request, with processEarlyHintsResponse set to the following step given a response earlyResponse: If - uncommittedPreloads is null, then set uncommittedPreloads to the result + commitEarlyHints is null, then set commitEarlyHints to the result of processing early hint headers given earlyResponse and request's reserved client.

    30. @@ -89288,8 +89471,8 @@ interface Location { // but see also has cross-origin redirects is hasCrossOriginRedirects, and - uncommitted preloads is - uncommittedPreloads.

      + commit early hints is + commitEarlyHints.

    31. Run process a navigate response with navigationType, allowedToDownload, hasTransientActivation, and @@ -89884,11 +90067,11 @@ interface Location { // but see also issue #2900.

    32. -
    33. If navigationParams's - uncommitted preloads is not null, - then for each commitEarlyPreload in - navigationParams's uncommitted - preloads, call commitEarlyPreload given document.

      +
    34. If navigationParams's commit early hints is not null, then call + navigationParams's commit early hints with + document.

    35. Process link headers given document, navigationParams's response, and