@httpland/cors-middleware
v1.0.0
Published
HTTP cross-origin resource sharing(CORS) middleware
Downloads
14
Maintainers
Readme
cors-middleware
HTTP cross-origin resource sharing(CORS) middleware.
Compliant with Fetch living standard, 3.2. CORS protocol.
Terms
Middleware
For a definition of Universal HTTP middleware, see the http-middleware project.
CORS request
Add a CORS header to the response in the downstream.
No special action is taken in response to CORS preflight requests. Use preflight for that.
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
cors
accept following 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 *
or a list of allowed origins.
The default is *
.
Asterisk
If *
, Access-Control-Allow-Origin
(*) will add to the response.
List
The list may consist of strings or regular expression objects.
The middleware compares Origin
header and each element of the allowOrigins
.
If matched, Access-Control-Allow-Origin
(Origin header) will add to the
response.
If no match, Access-Control-Allow-Origin
(null) will add 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\..*/],
});
yield:
Access-Control-Allow-Origin: <Origin>
Vary: Origin
AllowCredentials
The allowCredentials
value will serialize and added to the response as
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
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";
assertThrows(() => cors({ exposeHeaders: ["<invalid:field-name>"] }));
Effects
Middleware will make changes to the following elements of the HTTP message.
- HTTP Headers
- Access-Control-Allow-Origin
- Access-Control-Allow-Credentials
- Access-Control-Expose-Headers
- Vary
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
preflight
accept following 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. |
and CORS request options without exposeHeaders
.
AllowMethods
The value of allowMethods
will serialize and added to the response as an
Access-Control-Allow-Methods
header.
If not specified, Access-Control-Request-Method
header will add as
Access-Control-Allow-Methods
header 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
Access-Control-Allow-Headers
header.
If not specified, Access-Control-Request-Headers
will add as
Access-Control-Allow-Headers
header 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
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.
Serialization error
Throws an error if option has an invalid value.
This is following case:
- Elements of
allowMethods
are not<method>
format - Elements of
allowHeaders
are not<field-name>
format maxAge
is not non-negative integer
import {
preflight,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
import { assertThrows } from "https://deno.land/std/testing/asserts.ts";
assertThrows(() => preflight({ allowMethods: ["<invalid:method>"] }));
assertThrows(() => preflight({ allowHeaders: ["<invalid:field-name>"] }));
assertThrows(() => preflight({ maxAge: NaN }));
API
All APIs can be found in the deno doc.
FAQ
Because the two offer different functions. cors creates middleware to provide CORS headers.
On the other hand, preflight creates a handler for CORS preflight requests. (Although it is actually a middleware signature, since it transfers processing to subsequent requests other than CORS preflight requests.)
Mixing middleware with handler characteristics and middleware characteristics will create expressive constraints.
License
Copyright © 2023-present httpland.
Released under the MIT license