-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.ts
127 lines (103 loc) · 3.02 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
// This module is browser compatible.
import {
ascend,
distinct,
filterKeys,
isBoolean,
isConditionalHeader,
isNegativeNumber,
isNull,
isSuccessfulStatus,
Method,
not,
parseAcceptRanges,
RepresentationHeader,
Status,
SuccessfulStatus,
type Token,
toLowerCase,
} from "./deps.ts";
import type { Precondition } from "./types.ts";
export function isNotSelectionOrModificationMethod(method: string): boolean {
return ([Method.Connect, Method.Options, Method.Trace] as string[]).includes(
method,
);
}
type PreEvaluableStatus = SuccessfulStatus | Status.PreconditionFailed;
export function isPreEvaluableStatus(
status: number,
): status is PreEvaluableStatus {
return isSuccessfulStatus(status) || Status.PreconditionFailed === status;
}
enum PreconditionPriority {
"if-match",
"if-unmodified-since",
"if-none-match",
"if-modified-since",
"if-range",
}
export type Ord = 1 | 0 | -1;
export function toPriority(input: string): number {
input = input.toLowerCase();
const Order = Object.values(PreconditionPriority);
const result = Order.indexOf(input);
return isNegativeNumber(result) ? Infinity : result;
}
export function ascendPrecondition(
left: Precondition,
right: Precondition,
): Ord {
return ascendPreconditionHeader(left.field, right.field);
}
export function ascendPreconditionHeader(
left: string,
right: string,
): Ord {
const l = toPriority(left);
const r = toPriority(right);
return ascend(l, r);
}
export async function applyPrecondition(
request: Request,
response: Response,
precondition: Precondition,
): Promise<Response | void> {
const fieldValue = request.headers.get(precondition.field);
if (isNull(fieldValue)) return;
const evalResult = await precondition.evaluate(request, response);
if (!isBoolean(evalResult)) return;
return precondition.respond(request, response, evalResult);
}
export function isBannedHeader(fieldName: string): boolean {
return ([
RepresentationHeader.ContentEncoding,
RepresentationHeader.ContentLanguage,
RepresentationHeader.ContentLength,
RepresentationHeader.ContentType,
] as string[]).includes(fieldName);
}
/** Return no precondition header. */
export function withoutConditionHeaders(
headers: Headers,
additionalConditionHeaders: readonly string[] = [],
): Headers {
additionalConditionHeaders = distinct(additionalConditionHeaders)
.map(toLowerCase);
function isBannedHeader(key: string): boolean {
return isConditionalHeader(key) ||
additionalConditionHeaders.includes(key);
}
const newHeaders = filterKeys(headers, not(isBannedHeader));
return newHeaders;
}
/** Whether the input has {@link Token} or not.
* If the input is invalid [`Accept-Ranges`](https://www.rfc-editor.org/rfc/rfc9110.html#section-14.3-2) then `false`.
*/
export function hasToken(input: string, token: Token): boolean {
try {
return parseAcceptRanges(input).includes(token);
} catch {
return false;
}
}