Attic is a cozy space with lofty ambitions. attic.social
at main 210 lines 7.0 kB view raw
1// Copyright 2018-2026 the Deno authors. MIT license. 2// This module is browser compatible. 3 4/** 5 * Contains the functions {@linkcode accepts}, {@linkcode acceptsEncodings}, and 6 * {@linkcode acceptsLanguages} to provide content negotiation capabilities. 7 * 8 * @module 9 */ 10 11import { preferredEncodings } from "./_negotiation/encoding.ts"; 12import { preferredLanguages } from "./_negotiation/language.ts"; 13import { preferredMediaTypes } from "./_negotiation/media_type.ts"; 14 15/** 16 * Returns an array of media types accepted by the request, in order of 17 * preference. If there are no media types supplied in the request, then any 18 * media type selector will be returned. 19 * 20 * @example Usage 21 * ```ts 22 * import { accepts } from "@std/http/negotiation"; 23 * import { assertEquals } from "@std/assert"; 24 * 25 * const request = new Request("https://example.com/", { 26 * headers: { 27 * accept: 28 * "text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, *\/*;q=0.8", 29 * }, 30 * }); 31 * 32 * assertEquals(accepts(request), [ 33 * "text/html", 34 * "application/xhtml+xml", 35 * "image/webp", 36 * "application/xml", 37 * "*\/*", 38 * ]); 39 * ``` 40 * 41 * @param request The request to get the acceptable media types for. 42 * @returns An array of acceptable media types. 43 */ 44export function accepts(request: Pick<Request, "headers">): string[]; 45/** 46 * For a given set of media types, return the best match accepted in the 47 * request. If no media type matches, then the function returns `undefined`. 48 * 49 * @example Usage 50 * ```ts 51 * import { accepts } from "@std/http/negotiation"; 52 * import { assertEquals } from "@std/assert"; 53 * 54 * const request = new Request("https://example.com/", { 55 * headers: { 56 * accept: 57 * "text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, *\/*;q=0.8", 58 * }, 59 * }); 60 * 61 * assertEquals(accepts(request, "text/html", "image/webp"), "text/html"); 62 * ``` 63 * 64 * @typeParam T The type of supported content-types (if provided). 65 * @param request The request to get the acceptable media types for. 66 * @param types An array of media types to find the best matching one from. 67 * @returns The best matching media type, if any match. 68 */ 69export function accepts<T extends string = string>( 70 request: Pick<Request, "headers">, 71 ...types: T[] 72): T | undefined; 73export function accepts( 74 request: Pick<Request, "headers">, 75 ...types: string[] 76): string | string[] | undefined { 77 const accept = request.headers.get("accept"); 78 return types.length 79 ? accept ? preferredMediaTypes(accept, types)[0] : types[0] 80 : accept 81 ? preferredMediaTypes(accept) 82 : ["*/*"]; 83} 84 85/** 86 * Returns an array of content encodings accepted by the request, in order of 87 * preference. If there are no encoding supplied in the request, then `["*"]` 88 * is returned, implying any encoding is accepted. 89 * 90 * @example Usage 91 * ```ts 92 * import { acceptsEncodings } from "@std/http/negotiation"; 93 * import { assertEquals } from "@std/assert"; 94 * 95 * const request = new Request("https://example.com/", { 96 * headers: { "accept-encoding": "deflate, gzip;q=1.0, *;q=0.5" }, 97 * }); 98 * 99 * assertEquals(acceptsEncodings(request), ["deflate", "gzip", "*"]); 100 * ``` 101 * 102 * @param request The request to get the acceptable content encodings for. 103 * @returns An array of content encodings this request accepts. 104 */ 105export function acceptsEncodings(request: Pick<Request, "headers">): string[]; 106/** 107 * For a given set of content encodings, return the best match accepted in the 108 * request. If no content encodings match, then the function returns 109 * `undefined`. 110 * 111 * **NOTE:** You should always supply `identity` as one of the encodings 112 * to ensure that there is a match when the `Accept-Encoding` header is part 113 * of the request. 114 * 115 * @example Usage 116 * ```ts 117 * import { acceptsEncodings } from "@std/http/negotiation"; 118 * import { assertEquals } from "@std/assert"; 119 * 120 * const request = new Request("https://example.com/", { 121 * headers: { "accept-encoding": "deflate, gzip;q=1.0, *;q=0.5" }, 122 * }); 123 * 124 * assertEquals(acceptsEncodings(request, "gzip", "identity"), "gzip"); 125 * ``` 126 * 127 * @typeParam T The type of supported encodings (if provided). 128 * @param request The request to get the acceptable content encodings for. 129 * @param encodings An array of encodings to find the best matching one from. 130 * @returns The best matching encoding, if any match. 131 */ 132export function acceptsEncodings<T extends string = string>( 133 request: Pick<Request, "headers">, 134 ...encodings: T[] 135): T | undefined; 136export function acceptsEncodings( 137 request: Pick<Request, "headers">, 138 ...encodings: string[] 139): string | string[] | undefined { 140 const acceptEncoding = request.headers.get("accept-encoding"); 141 return encodings.length 142 ? acceptEncoding 143 ? preferredEncodings(acceptEncoding, encodings)[0] 144 : encodings[0] 145 : acceptEncoding 146 ? preferredEncodings(acceptEncoding) 147 : ["*"]; 148} 149 150/** 151 * Returns an array of languages accepted by the request, in order of 152 * preference. If there are no languages supplied in the request, then `["*"]` 153 * is returned, imply any language is accepted. 154 * 155 * @example Usage 156 * ```ts 157 * import { acceptsLanguages } from "@std/http/negotiation"; 158 * import { assertEquals } from "@std/assert"; 159 * 160 * const request = new Request("https://example.com/", { 161 * headers: { 162 * "accept-language": "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5", 163 * }, 164 * }); 165 * 166 * assertEquals(acceptsLanguages(request), ["fr-CH", "fr", "en", "de", "*"]); 167 * ``` 168 * 169 * @param request The request to get the acceptable languages for. 170 * @returns An array of languages this request accepts. 171 */ 172export function acceptsLanguages(request: Pick<Request, "headers">): string[]; 173/** 174 * For a given set of languages, return the best match accepted in the request. 175 * If no languages match, then the function returns `undefined`. 176 * 177 * @example Usage 178 * ```ts 179 * import { acceptsLanguages } from "@std/http/negotiation"; 180 * import { assertEquals } from "@std/assert"; 181 * 182 * const request = new Request("https://example.com/", { 183 * headers: { 184 * "accept-language": "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5", 185 * }, 186 * }); 187 * 188 * assertEquals(acceptsLanguages(request, "en-gb", "en-us", "en"), "en"); 189 * ``` 190 * 191 * @typeParam T The type of supported languages (if provided). 192 * @param request The request to get the acceptable language for. 193 * @param langs An array of languages to find the best matching one from. 194 * @returns The best matching language, if any match. 195 */ 196export function acceptsLanguages<T extends string = string>( 197 request: Pick<Request, "headers">, 198 ...langs: T[] 199): T | undefined; 200export function acceptsLanguages( 201 request: Pick<Request, "headers">, 202 ...langs: string[] 203): string | string[] | undefined { 204 const acceptLanguage = request.headers.get("accept-language"); 205 return langs.length 206 ? acceptLanguage ? preferredLanguages(acceptLanguage, langs)[0] : langs[0] 207 : acceptLanguage 208 ? preferredLanguages(acceptLanguage) 209 : ["*"]; 210}