cors-middleware
HTTP cross-origin resource sharing(CORS) middleware.
Compliant with Fetch living standard, 3.2. CORS protocol.
Middleware
For a definition of Universal HTTP middleware, see the http-middleware project.
CORS request and CORS preflight request
A CORS request is a request with an Origin
header.
On the other hand, a CORS preflight request is a CORS request and satisfies the following:
- Method is
Options
- Includes
Access-Control-Request-Method
header - Includes
Access-Control-Request-Headers
header
This project provides middleware for CORS requests.
CORS request
Add a CORS header to the response in the downstream.
import {
cors,
type Handler,
} from "https://deno.land/x/cors_middleware@$VERSION/mod.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";
const middleware = cors();
const corsRequest = new Request("test:", {
headers: { origin: "<origin>" },
});
declare const handler: Handler;
const response = await middleware(corsRequest, handler);
assert(response.headers.has("access-control-allow-origin"));
yield:
Access-Control-Allow-Origin: *
Vary: Origin
CORS request options
Name | Type | Description |
---|---|---|
allowOrigins | * | (string | RegExp )[] |
Allowed origin list. |
allowCredentials | true | "true" |
Access-Control-Allow-Credentials |
exposeHeaders | string[] |
Access-Control-Expose-Headers |
AllowOrigins
allowOrigins
is a list of *
or allowed origins.
The default is *
.
If *
, ACAO(*) is added to the response.
The list may consist of strings or regular expression objects.
The middleware compares the value of the Origin
header with the
allowOrigins
.
If a match is found, ACAM(Origin
) is added to the response.
If no match, ACAM(""
) is added to the response.
import {
cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";
const middleware = cors({
allowOrigins: ["https://test.example", /^https:\/\/cdn\..*/],
});
AllowCredentials
The allowCredentials
value will serialize and added to the response as an ACAC
(Access-Control-Allow-Credentials
) header.
import {
cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
const middleware = cors({ allowCredentials: true });
yield:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Vary: Origin
ExposeHeaders
The value of exposeHeaders
will serialize and added to the response as an ACEH
(Access-Control-Expose-Headers
) header.
However, if the request is a CORS preflight request, it is not added.
import {
cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
const middleware = cors({ exposeHeaders: ["x-test"] });
yield:
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: x-test
Vary: Origin
CORS options serialization error
Each option will serialize.
If serialization fails, it throws an error as follows:
- Elements of
exposeHeaders
are not<field-name
format
import {
cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
import { assertThrows } from "https://deno.land/std/testing/asserts.ts";
const middleware = assertThrows(() =>
cors({ exposeHeaders: ["<invalid:field-name>"] })
);
CORS preflight request
Create CORS preflight request handler.
import {
type Handler,
preflight,
} from "https://deno.land/x/cors_middleware@$VERSION/mod.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";
import { assertSpyCalls, spy } from "https://deno.land/std/testing/mock.ts";
const corsPreflightRequest = new Request("test:", {
method: "OPTIONS",
headers: {
origin: "<origin>",
"access-control-request-method": "POST",
"access-control-request-headers": "content-type",
},
});
declare const handler: Handler;
const next = spy(handler);
const handlePreflight = preflight();
const response = await handlePreflight(corsPreflightRequest, next);
assertSpyCalls(next, 0);
assert(response.status === 204);
assert(response.headers.has("access-control-allow-origin"));
assert(response.headers.has("access-control-allow-methods"));
assert(response.headers.has("access-control-allow-headers"));
assert(response.headers.has("vary"));
yield:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type
Vary: origin, access-control-request-method, access-control-request-headers
If the request is not a CORS preflight request, next
will execute.
CORS preflight options
Name | Type | Description |
---|---|---|
allowMethods | string[] |
Access-Control-Allow-Methods |
allowHeaders | string[] |
Access-Control-Allow-Headers |
maxAge | number |
Access-Control-Max-Age |
status | 200 | 204 |
Preflight response status code. |
AllowMethods
The value of allowMethods
will serialize and added to the response as an ACAM
(Access-Control-Allow-Methods
) header.
If not specified, ACRM (Access-Control-Request-Method
) will add as ACAM to the
response.
import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
const handler = preflight({ allowMethods: ["POST", "PUT"] });
yield:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT
Access-Control-Allow-Headers: <Access-Control-Request-Headers>
Vary: origin, access-control-request-method, access-control-request-headers
AllowHeaders
The value of allowHeaders
will serialize and added to the response as an ACAH
(Access-Control-Allow-Headers
) header.
If not specified, ACRH (Access-Control-Request-Headers
) will add as ACAH to
the response.
import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
const handler = preflight({ allowHeaders: ["x-test1", "x-test2"] });
yield:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: <Access-Control-Request-Method>
Access-Control-Allow-Headers: x-test1, x-test2
Vary: origin, access-control-request-method, access-control-request-headers
MaxAge
The value of maxAge
will serialize and added to the response as an ACMA
(Access-Control-Max-Age
) header.
import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
const handler = preflight({ maxAge: 86400 });
yield:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: <Access-Control-Request-Method>
Access-Control-Allow-Headers: <Access-Control-Request-Headers>
Access-Control-Max-Age: 86400
Vary: origin, access-control-request-method, access-control-request-headers
Status
The default is 204 No Content.
You can change to 200 OK.
API
All APIs can be found in the deno doc.
License
Copyright © 2023-present httpland.
Released under the MIT license