mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
212 lines
5.0 KiB
TypeScript
212 lines
5.0 KiB
TypeScript
// Loaded from https://deno.land/x/type_is@1.0.1/mod.ts
|
|
|
|
|
|
/*!
|
|
* Based on https://github.com/jshttp/type-is/blob/master/index.js
|
|
* Copyright(c) 2014 Jonathan Ong
|
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
|
* Copyright(c) 2020 Henry Zhuang
|
|
* MIT Licensed
|
|
*/
|
|
|
|
import { lookup, parse, test } from "./deps.ts";
|
|
|
|
/**
|
|
* Compare a `value` content-type with `types`.
|
|
* Each `type` can be an extension like `html`,
|
|
* a special shortcut like `multipart` or `urlencoded`,
|
|
* or a mime type.
|
|
*
|
|
* If no types match, `false` is returned.
|
|
* Otherwise, the first `type` that matches is returned.
|
|
*
|
|
* @param {String} mediaType
|
|
* @param {Array} types
|
|
*/
|
|
export function is(mediaType: string, types?: string[]): boolean | string {
|
|
let i;
|
|
// remove parameters and normalize
|
|
const val = tryNormalizeType(mediaType);
|
|
|
|
// no type or invalid
|
|
if (!val) {
|
|
return false;
|
|
}
|
|
|
|
// no types, return the content type
|
|
if (!types || !types.length) {
|
|
return val;
|
|
}
|
|
|
|
let type;
|
|
for (i = 0; i < types.length; i++) {
|
|
const normalized = normalize(type = types[i]);
|
|
if (normalized && mimeMatch(normalized, val)) {
|
|
return type[0] === "+" || type.indexOf("*") !== -1 ? val : type;
|
|
}
|
|
}
|
|
|
|
// no matches
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if a request's header has a request body.
|
|
* A request with a body __must__ either have `transfer-encoding`
|
|
* or `content-length` headers set.
|
|
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
|
*
|
|
* @param {Object} request
|
|
* @return {Boolean}
|
|
*/
|
|
export function hasBody(header: Headers): boolean {
|
|
return header.get("transfer-encoding") !== null ||
|
|
!isNaN(parseInt(header.get("content-length") || "", 10));
|
|
}
|
|
|
|
/**
|
|
* Check if the incoming request's header contains the "Content-Type"
|
|
* header field, and it contains any of the give mime `type`s.
|
|
* If there is no request body, `null` is returned.
|
|
* If there is no content type, `false` is returned.
|
|
* Otherwise, it returns the first `type` that matches.
|
|
*
|
|
* Examples:
|
|
*
|
|
* // With Content-Type: text/html; charset=utf-8
|
|
* typeofrequest(header, [ 'html' ]); // => 'html'
|
|
* typeofrequest(header, ['text/html' ]); // => 'text/html'
|
|
* typeofrequest(header, ['text/*', 'application/json' ]); // => 'text/html'
|
|
*
|
|
* // When Content-Type is application/json
|
|
* typeofrequest(header, [ 'json', 'urlencoded' ]); // => 'json'
|
|
* typeofrequest(header, [ 'application/json' ]); // => 'application/json'
|
|
* typeofrequest(header, [ 'html', 'application/*' ]); // => 'application/json'
|
|
*
|
|
* typeofrequest(header, [ 'html' ]); // => false
|
|
*
|
|
* @param {String|Array} types...
|
|
* @return {String|false|null}
|
|
*/
|
|
|
|
export function typeofrequest(
|
|
header: Headers,
|
|
types_?: string[],
|
|
): null | boolean | string {
|
|
const types = types_;
|
|
|
|
// no body
|
|
if (!hasBody(header)) {
|
|
return null;
|
|
}
|
|
|
|
// request content type
|
|
const value = header.get("content-type");
|
|
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
|
|
return is(value, types);
|
|
}
|
|
|
|
/**
|
|
* Normalize a mime type.
|
|
* If it's a shorthand, expand it to a valid mime type.
|
|
*
|
|
* In general, you probably want:
|
|
*
|
|
* const type = is(req, ['urlencoded', 'json', 'multipart']);
|
|
*
|
|
* Then use the appropriate body parsers.
|
|
* These three are the most common request body types
|
|
* and are thus ensured to work.
|
|
*
|
|
* @param {String} type
|
|
*/
|
|
export const normalize = function normalize(type: string): string | undefined {
|
|
switch (type) {
|
|
case "urlencoded":
|
|
return "application/x-www-form-urlencoded";
|
|
case "multipart":
|
|
return "multipart/*";
|
|
}
|
|
|
|
if (type[0] === "+") {
|
|
// "+json" -> "*/*+json" expando
|
|
return "*/*" + type;
|
|
}
|
|
|
|
return type.indexOf("/") === -1 ? lookup(type) : type;
|
|
};
|
|
|
|
/**
|
|
* Check if `expected` mime type
|
|
* matches `actual` mime type with
|
|
* wildcard and +suffix support.
|
|
*
|
|
* @param {String} expected
|
|
* @param {String} actual
|
|
* @return {Boolean}
|
|
*/
|
|
function mimeMatch(expected: string, actual: string): boolean {
|
|
// split types
|
|
const actualParts = actual.split("/");
|
|
const expectedParts = expected.split("/");
|
|
|
|
// invalid format
|
|
if (actualParts.length !== 2 || expectedParts.length !== 2) {
|
|
return false;
|
|
}
|
|
|
|
// validate type
|
|
if (expectedParts[0] !== "*" && expectedParts[0] !== actualParts[0]) {
|
|
return false;
|
|
}
|
|
|
|
// validate suffix wildcard
|
|
if (expectedParts[1].substr(0, 2) === "*+") {
|
|
return expectedParts[1].length <= actualParts[1].length + 1 &&
|
|
expectedParts[1].substr(1) ===
|
|
actualParts[1].substr(1 - expectedParts[1].length);
|
|
}
|
|
|
|
// validate subtype
|
|
if (expectedParts[1] !== "*" && expectedParts[1] !== actualParts[1]) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Normalize a type
|
|
*
|
|
* @param {string} value
|
|
* @return {string}
|
|
*/
|
|
function normalizeType(value: string): string | null {
|
|
// parse the type
|
|
const type = parse(value).type;
|
|
|
|
if (!test(type)) {
|
|
return null;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
/**
|
|
* Try to normalize a type
|
|
*
|
|
* @param {string} value
|
|
* @return {string}
|
|
*/
|
|
function tryNormalizeType(value: string): string | null {
|
|
try {
|
|
return normalizeType(value);
|
|
} catch (err) {
|
|
return null;
|
|
}
|
|
}
|