htmlhttp-headershtml-imports

Can HTML imports be specified using the Link HTTP header, or only with a <link> tag?


The HTML <link> element is most frequently used to include CSS stylesheets in a document. A typical use might look like this:

<link rel="stylesheet" href="/style.css" />

As an alternative to including the tag in the response body, it's possible for the server to specify the stylesheet using the Link HTTP header instead:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Link: </style.css>; rel=stylesheet

<!doctype html>
<html>
  <head><title>Example</title></head>
  <body>Hello!</body>
</html>

The proposed HTML Imports feature specification (WC3 working draft) adds a significant new feature to the <link> element: the ability to import all of the resources from another HTML document at once, potentially including multiple scripts, styles, and templates. A typical use may look like this:

<link rel="import" href="/components.html" />

My expectation was that it would also be possible to specify HTML imports using the Link header in the same way as styles, for cases like this:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Link: </components.html>; rel=import

<!doctype html>
<html>
  <head><title>Example</title></head>
  <body><ex-warm-welcome>Hello!</ex-warm-welcome></body>
</html>

However, the working draft specification only explicitly mentions the <link> element; it doesn't make reference to the Link header. It also uses language that seems to require a <link> element to be associated with each import,

Each document has an import link list, each of whose item is consist of link, the link element and location, a URL.

I see that <link rel="import" ... /> supports an async attribute that stylesheet links do not. It wouldn't be possible to specify this in the header, but given that it's an optional attribute I wouldn't expect this to prevent its support altogether.

Is it possible to specify an HTML import using the Link header, or not?


Solution

  • No.

    According to RFC 5988: Web Linking, the Link header is supposed to be semantically equivalent to the <link> element:

    5.  The Link Header Field
    
       The Link entity-header field provides a means for serialising one or
       more links in HTTP headers.  It is semantically equivalent to the
       <LINK> element in HTML, as well as the atom:link feed-level element
       in Atom [RFC4287].
    

    However, the "The link element" section of the HTML5 specification (W3C recommendation) seems to contradict this, explicitly saying that their semantics are allowed to differ:

    HTTP Link: headers, if supported, must be assumed to come before any links in the document, in the order that they were given in the HTTP message. These headers are to be processed according to the rules given in the relevant specifications. [HTTP] [WEBLINK]

    Note: Registration of relation types in HTTP Link: headers is distinct from HTML link types, and thus their semantics can be different from same-named HTML types.

    RFC 5988 is only a "proposed standard" (info on rfc-editor.org), and although it's referenced by the HTML5 specification that reference is explicitly marked as "non-normative". It only makes reference to the HTML4 specification itself. Given that the HTML5 specification is a full standard and more recent, I would expect it to be more relevant than the RFC, and not expect the Link header to work in this case. But let's set all this lawyering aside for the moment and actually test it.

    Here's a simple Node server, serving pages that attempt to specify an HTML import in each way:

    require('http').createServer(function(request, response) {
      switch (request.url) {
        case '/inline.html':
          response.writeHead(200, {
            'Content-Type': 'text/html',
          });
          response.write('<!doctype html><html><head>');
          response.write('<link rel="import" href="/import.html" />');
          break;
    
        case '/header.html':
          response.writeHead(200, {
            'Content-Type': 'text/html',
            'Link': '</import.html>; rel=import'
          });
          response.write('<!doctype html><html><head>');
          break;
    
        case '/import.html':
          response.writeHead(200, {
            'Content-Type': 'text/html',
          });
          response.write('<!doctype html><html><head>');
          response.write('<script>console.log("imported!")</script>');
          break;
    
        default:
          response.writeHead(404);
      }
    
      response.end();
    }).listen(8080);
    

    When I visit /inline.html in Chrome, I see "imported!" logged in the console as expected. But when I visit /header.html, I see nothing. So the definitive answer seems to be no: both the specification and the implementation do not support the declaration of HTML imports in Link headers.

    Sanity checking revealed a very faulty premise for this test: Chrome currently doesn't even support the Link header for stylesheets! It's the only browser engine currently supporting HTML imports by default, so our conclusion is still correct, but the test itself didn't actually shine any light on the intended behaviour because it was sure to fail regardless.