Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ETag-based caching #56

Merged
merged 3 commits into from
May 4, 2020
Merged

Add support for ETag-based caching #56

merged 3 commits into from
May 4, 2020

Conversation

developit
Copy link
Contributor

@developit developit commented May 4, 2020

When providing an ETag header on responses, the client automatically sends that header value on subsequent requests for the matching resource as an If-None-Match request header. If the ETag value received in If-None-Match is the same as the ETag computed by the disk crawl, a 304 "Not Modified" status can be returned along with an empty body to indicate that the requestor's cached value should be used.


I'm currently using the following workaround to implement this manually:

server.use((req, res, next) => {
	// `req` is not passed to setHeaders(), so we obtain that info here
	res._requestHeaders = req.headers;
	next();
});

server.use(
	sirv('public', {
		etag: true,
		setHeaders(res, path, stats) {
			const etag = res._requestHeaders['if-none-match'];
			const computedEtag = `W/"${stats.size}-${stats.mtime.getTime()}"`;
			if (etag && etag === computedEtag) {
				res.writeHead(304);
				res.end();
				// hack: disable sirv's normal response & piping:
				res.writeHead = res.write = res.end = () => {};
			}
		}
	})
);

@lukeed
Copy link
Owner

lukeed commented May 4, 2020

Awesome, thanks! Can you add this into next branch though? I'm gunning to release 1.0 this week

@developit developit changed the base branch from master to next May 4, 2020 19:12
lukeed and others added 2 commits May 4, 2020 19:17
When providing an ETag header on responses, the client automatically sends that header value on subsequent requests for the matching resource as an `If-None-Match` request header. If the ETag value received in `If-None-Match` is the same as the ETag computed by the disk crawl, a 304 "Not Modified" status can be returned along with an empty body to indicate that the requestor's cached value should be used.
@developit
Copy link
Contributor Author

@lukeed fixed!

Copy link
Owner

@lukeed lukeed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you 🙏 Little embarrassed I added ETag w/o its counterpart haha

@lukeed lukeed merged commit 5305b55 into lukeed:next May 4, 2020
@lukeed
Copy link
Owner

lukeed commented May 4, 2020

Available as:

  • sirv-cli@1.0.0-next.4
  • sirv@1.0.0-next.4

lukeed added a commit that referenced this pull request Jun 10, 2020
* chore(sirv): bump “@polka/url” for better decoding

* feat(sirv): inline `opts.single` behavior

* fix(sirv): unknown Content-Type as empty string

* feat(sirv-cli): run HTTP/2 server behind flags

* chore(sirv-cli): update readme

* feat: run `sade` in single-command mode

* feat(sirv): allow `--single` to accept path;

- Closes #35

* fix(sirv): respect existing `Content-Type` header;

- Closes #38
- Closes #39

* fix(sirv-cli): use "-K" for `--http2` alias

* feat: allow precompiled gzip & brotli files;

- Closes #3

* refactor(sirv): consolidate "dev & prod" modes;

- still optimized
- adds ETag support to "dev" mode
- adds brotli/gzip support to "dev" mode
- Related: #3

* chore: bump devdeps

* v1.0.0-next.0

* chore(docs): fix Polka demo usage;

- Closes #42

* fix(sirv): set "no-store" during `dev` mode;

- Closes #45

* v1.0.0-next.1

* fix(sirv): extract `list` into package

* fix(sirv): ignore deeply-nested dotfiles too

* chore(sirv): update `polka/url` dep;

lukeed/polka#119

* v1.0.0-next.2

* feat(sirv-cli): add `--pass` flag for passphrase

* v1.0.0-next.3

* fix(sirv): compare `ETag` against `If-None-Match` header (#56)

* fix(sirv-cli): use `host` for port availability

* Add support for ETag-based caching

When providing an ETag header on responses, the client automatically sends that header value on subsequent requests for the matching resource as an `If-None-Match` request header. If the ETag value received in `If-None-Match` is the same as the ETag computed by the disk crawl, a 304 "Not Modified" status can be returned along with an empty body to indicate that the requestor's cached value should be used.

* chore: use existing `isEtag` var

Co-authored-by: Luke Edwards <luke.edwards05@gmail.com>

* chore(sirv): squash declaration

* v1.0.0-next.4

* break: require Node 10.x minimum;

- Node 8.x is already End of Life (2019-12-31)

* v1.0.0-next.5

* feat(sirv): add type definitions;

- Closes #61

* chore: add `notice` to base readme re: website;

- Closes #62

* feat(sirv): add `filter` option to determine file list;

- supplants default `dotfiles` matcher, responsible for own logic
- Closes #50

* fix(sirv): replace `filter` w/ built-in ".well-known" allowance;

- Closes #50

* chore: rename files

* chore(sirv-cli): rename `boot` file

* chore(sirv): produce `build` files w/ "module" entry

* chore: run tests with esm loader

* chore: re-extract `middleware` helper file

* chore: begin integration test suites;

- include fixtures directory

* chore: use `pnpm` again for lerna;

This reverts commit a56872b.

# Conflicts:
#	lerna.json

* chore(action): install `pnpm` for ci

* chore: add `single` tests

* chore(action): use `curl` installer for pnpm

* chore: add "extensions" tests

* chore: add `dotfiles` test suite

* chore: add `dev` test suite

* chore: add `etag` test suite

* chore: add `brotli` and `gzip` suites

* chore: add `maxAge` and `immutable` test suites

* chore: add `ranges` test suite

* fix(test): remove `only` on dotfiles suite

* chore: import `setHeaders` and `onNoMatch` suites

* chore: cleanup test helpers

* chore: include "build" step in CI

* chore: initial CLI tests

* revert: allow normal resolution

* chore: try `actions/cache` recipe

* chore: add loose CLI tests

* fix(test): terminate child procs correctly

* chore: boot `http2` server within test

* fix(sirv): normalize encoded/accented characters for cache

* debug: server spawner really annoying

* feat: add "assets" option (#53)

* Add option to specify asset paths for SPAs

Allows asset path prefixes to be specified by the CLI when running in
single-page mode.

If a path is requested that doesn't exist, and that path matches one of
the asset path prefixes, the request will 404 instead of retuning a 200
containing the root index.

Fixes #44

* fix: ensure `assets` array & preload prep work

* chore: add `assets` tests

* chore: update options definition

* update `--single` & `--assets` text

Co-authored-by: Luke Edwards <luke.edwards05@gmail.com>

* refactor: rename "assets" to "ignores" option

* fix: include dotfiles & well-known in default ignores

* fix: move `ignores` check into `toAssume` builder

* refactor: hoist bound `lookup` function

* fix(sirv): do not fill cache when `dev` true

* v1.0.0-next.6

* fix(sirv): extension regexp

* v1.0.0-next.7

* fix(sirv): remove premature ignore check;

- ran before extensions could be applied
- effectively reverts to #53

* v1.0.0-next.8

* fix(sirv): allow definition to export type members

* v1.0.0-next.9

* fix(sirv): dedupe extensions list w/ brotli + gzip

* chore: update documentation

* chore: update bench figures;

- include dummy apps directly

* chore: fix spacing

Co-authored-by: Jason Miller <developit@users.noreply.github.com>
Co-authored-by: Carey Metcalfe <carey@cmetcalfe.ca>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants