deno_std icon indicating copy to clipboard operation
deno_std copied to clipboard

Add `Sec-Fetch-Mode` and `Sec-Fetch-Dest` to `@std/http/unstable-headers`

Open csvn opened this issue 1 year ago • 1 comments

Is your feature request related to a problem? Please describe.

In many frontend projects I've worked on, I've started relying on ``Sec-Fetch-Modeand/orSec-Fetch-Destheaders. Because it's very common to return/index.htmlfor SPA apps, but returning it for CSS/JS and other unrelated static resources is annoying. Therefore it's very helpful to check that the current request is anavigatetodocumentbefore returning/index.html`, otherwise 404.

I don't know why this header is not included in https://www.iana.org/assignments/http-fields/http-fields.xhtml#field-names, but these headers were part of Baseline 2023, and are supported in all major browsers currently.

Would PR's adding the below be accepted, or does new API's require discussion first in issues?

Describe the solution you'd like

It would be great if the Sec-Fetch-* headers were just included in HEADERS from jsr:@std/http@1/unstable-header. It would be even more awesome if there was a dedicated API for this, like with accepts in negotiation.ts:

import { fetchMode, fetchDestination } from 'jsr:@std/http@1';

const request = new Request('https://example.com/', {
  headers: {
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Dest': 'document'
  }
});

fetchMode(req, 'navigate');
// true
fetchMode(req, 'same-origin');
// false
fetchMode(req, 'navigate', 'no-cors');
// true

fetchDestination(req, 'document');
// true
fetchDestination(req, 'iframe');
// false
fetchDestination(req, 'document', 'iframe', 'frame');
// true

The biggest win for this being able to write the values above in a type safe way:

import { serveFile, fethMode, fetchDestination } from '@std/http';

export const spaFallback: Deno.ServeHandler = (req) => {
  if (!isDocumentReq(req)) return new Response(undefined, { status: 404 });
  return serveFile(req, '/index.html');
}

export function isDocumentReq(req: Request) {
  return fethMode(req, 'navigate') && fetchDestination(req, 'document');
}

Describe alternatives you've considered

There current code is not terrible, but using type-safe header values and type safe possible header values means it's easy to for instance misspell 'navigate' to 'navigation'.

export function isDocumentReq(req: Request) {
  const mode = req.headers.get('Sec-Fetch-Mode');
  const dest = req.headers.get('Sec-Fetch-Dest');
  return mode === 'navigate' && dest === 'document';
}

csvn avatar Oct 13 '24 15:10 csvn