x/conditional_request_middleware
conditional-request-middleware
HTTP conditional request middleware.
Compliant with RFC 9110, 13. Conditional Requests
Middleware
For a definition of Universal HTTP middleware, see the http-middleware project.
Usage
To evaluate precondition, you need to provide a function to retrieve the selected representation.
The following example evaluates the If-None-Match
precondition and handle
response.
import {
conditionalRequest,
type Handler,
} from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import {
assertEquals,
assertFalse,
} from "https://deno.land/std/testing/asserts.ts";
import { assertSpyCalls, spy } from "https://deno.land/std/testing/mock.ts";
const selectRepresentation = spy((request: Request) => {
return new Response("<body>", { headers: { etag: "<etag>" } });
});
const middleware = conditionalRequest(selectRepresentation);
const request = new Request("<uri>", {
headers: { "if-none-match": "<etag>" },
});
declare const _handler: Handler;
const handler = spy(_handler);
const response = await middleware(request, handler);
assertSpyCalls(handler, 0);
assertSpyCalls(selectRepresentation, 1);
assertEquals(response.status, 304);
assertFalse(response.body);
Precondition
RFC 9110, 13.1. Preconditions compliant and supports the following precondition:
If multiple precondition headers are present, precondition is processed according to precedence.
IfMatch
If-Match
header field precondition.
import { IfMatch } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
const precondition = new IfMatch();
const request = new Request("<uri>", {
headers: { "if-match": "<strong:etag>" },
});
const selectedRepresentation = new Response("<content>", {
headers: { etag: "<weak:etag>" },
});
declare const evalResult: false;
assertEquals(precondition.field, "if-match");
assertEquals(
precondition.evaluate(request, selectedRepresentation),
evalResult,
);
assertEquals(
precondition.respond(request, selectedRepresentation, evalResult)?.status,
412,
);
Effects
Precondition will effect following:
If evaluation is false
:
- HTTP content
- HTTP response status
- HTTP headers
IfNoneMatch
If-None-Match
header field precondition.
import { IfNoneMatch } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
const precondition = new IfNoneMatch();
const request = new Request("<uri>", {
headers: { "if-none-match": "<weak:etag>" },
});
const selectedRepresentation = new Response("<content>", {
headers: { etag: "<weak:etag>" },
});
declare const evalResult: false;
assertEquals(precondition.field, "if-none-match");
assertEquals(
precondition.evaluate(request, selectedRepresentation),
evalResult,
);
assertEquals(
precondition.respond(request, selectedRepresentation, evalResult)?.status,
304,
);
Effects
Precondition will effect following:
If evaluation is false
:
- HTTP content
- HTTP response status
- HTTP headers
IfModifiedSince
If-Modified-Since
header field precondition.
import { IfModifiedSince } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
const precondition = new IfModifiedSince();
const request = new Request("<uri>", {
headers: { "if-modified-since": "<after:HTTP-date>" },
});
const selectedRepresentation = new Response("<content>", {
headers: { "last-modified": "<before:HTTP-date>" },
});
declare const evalResult: false;
assertEquals(precondition.field, "if-modified-since");
assertEquals(
precondition.evaluate(request, selectedRepresentation),
evalResult,
);
assertEquals(
precondition.respond(request, selectedRepresentation, evalResult)?.status,
304,
);
Effects
Precondition will effect following:
If evaluation is false
:
- HTTP content
- HTTP response status
- HTTP headers
- Content-Type
- Content-Encoding
- Content-Length
- Content-Language
IfUnmodifiedSince
If-Unmodified-Since
header field precondition.
import { IfUnmodifiedSince } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
const precondition = new IfUnmodifiedSince();
const request = new Request("<uri>", {
headers: { "if-unmodified-since": "<before:HTTP-date>" },
});
const selectedRepresentation = new Response("<content>", {
headers: { "last-modified": "<after:HTTP-date>" },
});
declare const evalResult: false;
assertEquals(precondition.field, "if-unmodified-since");
assertEquals(
precondition.evaluate(request, selectedRepresentation),
evalResult,
);
assertEquals(
precondition.respond(request, selectedRepresentation, evalResult)?.status,
412,
);
Effects
Precondition will effect following:
If evaluation is false
:
- HTTP content
- HTTP response status
- HTTP headers
IfRange
If-Range
header field precondition.
import { IfRange } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
const precondition = new IfRange();
const request = new Request("<uri>", {
headers: { "if-range": "<strong:etag>", range: "<range-unit>=<range-set>" },
});
const selectedRepresentation = new Response("<content>", {
headers: { etag: "<strong:etag>" },
});
declare const evalResult: false;
assertEquals(precondition.field, "if-range");
assertEquals(
precondition.evaluate(request, selectedRepresentation),
evalResult,
);
assertEquals(
(await precondition.respond(request, selectedRepresentation, evalResult))
?.status,
206,
);
Effects
Precondition will effect following:
If evaluation is true
:
- HTTP content
- HTTP response status
- HTTP headers
- Content-Range
- Content-Type
Conditions
Middleware will execute only if the following conditions are met:
- Request is conditional request
- Request method is not
CONNECT
,OPTIONS
orTRACE
- Select representation status is
2xx
or412
License
Copyright © 2023-present httpland.
Released under the MIT license