@irvinebroque/http-rfc-utils 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/dist/auth.d.ts +139 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +991 -0
- package/dist/auth.js.map +1 -0
- package/dist/cache-status.d.ts +15 -0
- package/dist/cache-status.d.ts.map +1 -0
- package/dist/cache-status.js +152 -0
- package/dist/cache-status.js.map +1 -0
- package/dist/cache.d.ts +94 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +244 -0
- package/dist/cache.js.map +1 -0
- package/dist/client-hints.d.ts +23 -0
- package/dist/client-hints.d.ts.map +1 -0
- package/dist/client-hints.js +81 -0
- package/dist/client-hints.js.map +1 -0
- package/dist/conditional.d.ts +97 -0
- package/dist/conditional.d.ts.map +1 -0
- package/dist/conditional.js +300 -0
- package/dist/conditional.js.map +1 -0
- package/dist/content-disposition.d.ts +23 -0
- package/dist/content-disposition.d.ts.map +1 -0
- package/dist/content-disposition.js +122 -0
- package/dist/content-disposition.js.map +1 -0
- package/dist/cookie.d.ts +43 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +472 -0
- package/dist/cookie.js.map +1 -0
- package/dist/cors.d.ts +53 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +170 -0
- package/dist/cors.js.map +1 -0
- package/dist/datetime.d.ts +53 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +205 -0
- package/dist/datetime.js.map +1 -0
- package/dist/digest.d.ts +220 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +355 -0
- package/dist/digest.js.map +1 -0
- package/dist/encoding.d.ts +14 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +86 -0
- package/dist/encoding.js.map +1 -0
- package/dist/etag.d.ts +55 -0
- package/dist/etag.d.ts.map +1 -0
- package/dist/etag.js +182 -0
- package/dist/etag.js.map +1 -0
- package/dist/ext-value.d.ts +40 -0
- package/dist/ext-value.d.ts.map +1 -0
- package/dist/ext-value.js +119 -0
- package/dist/ext-value.js.map +1 -0
- package/dist/forwarded.d.ts +14 -0
- package/dist/forwarded.d.ts.map +1 -0
- package/dist/forwarded.js +93 -0
- package/dist/forwarded.js.map +1 -0
- package/dist/header-utils.d.ts +71 -0
- package/dist/header-utils.d.ts.map +1 -0
- package/dist/header-utils.js +143 -0
- package/dist/header-utils.js.map +1 -0
- package/dist/headers.d.ts +71 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +134 -0
- package/dist/headers.js.map +1 -0
- package/dist/hsts.d.ts +15 -0
- package/dist/hsts.d.ts.map +1 -0
- package/dist/hsts.js +106 -0
- package/dist/hsts.js.map +1 -0
- package/dist/http-signatures.d.ts +202 -0
- package/dist/http-signatures.d.ts.map +1 -0
- package/dist/http-signatures.js +720 -0
- package/dist/http-signatures.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/json-pointer.d.ts +97 -0
- package/dist/json-pointer.d.ts.map +1 -0
- package/dist/json-pointer.js +278 -0
- package/dist/json-pointer.js.map +1 -0
- package/dist/jsonpath.d.ts +98 -0
- package/dist/jsonpath.d.ts.map +1 -0
- package/dist/jsonpath.js +1470 -0
- package/dist/jsonpath.js.map +1 -0
- package/dist/language.d.ts +14 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +95 -0
- package/dist/language.js.map +1 -0
- package/dist/link.d.ts +102 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +437 -0
- package/dist/link.js.map +1 -0
- package/dist/linkset.d.ts +111 -0
- package/dist/linkset.d.ts.map +1 -0
- package/dist/linkset.js +501 -0
- package/dist/linkset.js.map +1 -0
- package/dist/negotiate.d.ts +71 -0
- package/dist/negotiate.d.ts.map +1 -0
- package/dist/negotiate.js +357 -0
- package/dist/negotiate.js.map +1 -0
- package/dist/pagination.d.ts +80 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +188 -0
- package/dist/pagination.js.map +1 -0
- package/dist/prefer.d.ts +18 -0
- package/dist/prefer.d.ts.map +1 -0
- package/dist/prefer.js +93 -0
- package/dist/prefer.js.map +1 -0
- package/dist/problem.d.ts +54 -0
- package/dist/problem.d.ts.map +1 -0
- package/dist/problem.js +104 -0
- package/dist/problem.js.map +1 -0
- package/dist/proxy-status.d.ts +28 -0
- package/dist/proxy-status.d.ts.map +1 -0
- package/dist/proxy-status.js +220 -0
- package/dist/proxy-status.js.map +1 -0
- package/dist/range.d.ts +28 -0
- package/dist/range.d.ts.map +1 -0
- package/dist/range.js +243 -0
- package/dist/range.js.map +1 -0
- package/dist/response.d.ts +101 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +200 -0
- package/dist/response.js.map +1 -0
- package/dist/sorting.d.ts +66 -0
- package/dist/sorting.d.ts.map +1 -0
- package/dist/sorting.js +168 -0
- package/dist/sorting.js.map +1 -0
- package/dist/structured-fields.d.ts +30 -0
- package/dist/structured-fields.d.ts.map +1 -0
- package/dist/structured-fields.js +468 -0
- package/dist/structured-fields.js.map +1 -0
- package/dist/types.d.ts +772 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/uri-template.d.ts +48 -0
- package/dist/uri-template.d.ts.map +1 -0
- package/dist/uri-template.js +483 -0
- package/dist/uri-template.js.map +1 -0
- package/dist/uri.d.ts +80 -0
- package/dist/uri.d.ts.map +1 -0
- package/dist/uri.js +423 -0
- package/dist/uri.js.map +1 -0
- package/package.json +66 -0
package/dist/digest.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Digest Fields per RFC 9530.
|
|
3
|
+
* RFC 9530 §2, §3, §4, §5.
|
|
4
|
+
* @see https://www.rfc-editor.org/rfc/rfc9530.html
|
|
5
|
+
*
|
|
6
|
+
* Provides Content-Digest and Repr-Digest HTTP header field parsing/formatting
|
|
7
|
+
* for content and representation integrity verification. Also provides
|
|
8
|
+
* Want-Content-Digest and Want-Repr-Digest preference fields.
|
|
9
|
+
*/
|
|
10
|
+
import { parseSfDict, serializeSfDict } from './structured-fields.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Constants
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Algorithm classification constants.
|
|
16
|
+
* RFC 9530 §5, §7.2.
|
|
17
|
+
*/
|
|
18
|
+
export const DIGEST_ALGORITHMS = {
|
|
19
|
+
/** Algorithms suitable for adversarial settings */
|
|
20
|
+
active: ['sha-256', 'sha-512'],
|
|
21
|
+
/** Algorithms that MUST NOT be used in adversarial settings */
|
|
22
|
+
deprecated: ['md5', 'sha', 'unixsum', 'unixcksum', 'adler', 'crc32c'],
|
|
23
|
+
};
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Algorithm Helpers
|
|
26
|
+
// =============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* Check if an algorithm is active (suitable for adversarial settings).
|
|
29
|
+
* RFC 9530 §5.
|
|
30
|
+
*/
|
|
31
|
+
export function isActiveAlgorithm(algorithm) {
|
|
32
|
+
return DIGEST_ALGORITHMS.active.includes(algorithm.toLowerCase());
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if an algorithm is deprecated.
|
|
36
|
+
* RFC 9530 §5.
|
|
37
|
+
*/
|
|
38
|
+
export function isDeprecatedAlgorithm(algorithm) {
|
|
39
|
+
return DIGEST_ALGORITHMS.deprecated.includes(algorithm.toLowerCase());
|
|
40
|
+
}
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// Parsing
|
|
43
|
+
// =============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* Parse digest values from a structured field dictionary.
|
|
46
|
+
* Returns null for malformed input.
|
|
47
|
+
*/
|
|
48
|
+
function parseDigestField(value) {
|
|
49
|
+
const dict = parseSfDict(value);
|
|
50
|
+
if (!dict) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const digests = [];
|
|
54
|
+
for (const [algorithm, item] of Object.entries(dict)) {
|
|
55
|
+
// RFC 9530 §2, §3: value is a Byte Sequence
|
|
56
|
+
if ('items' in item) {
|
|
57
|
+
// Inner list not valid for digest values
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const sfItem = item;
|
|
61
|
+
if (!(sfItem.value instanceof Uint8Array)) {
|
|
62
|
+
// Must be a byte sequence
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
digests.push({
|
|
66
|
+
algorithm: algorithm.toLowerCase(),
|
|
67
|
+
value: sfItem.value,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return digests.length > 0 ? digests : [];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Parse Content-Digest header field value.
|
|
74
|
+
* RFC 9530 §2.
|
|
75
|
+
*
|
|
76
|
+
* @param value - The Content-Digest header value
|
|
77
|
+
* @returns Array of digests, or null if malformed
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const digests = parseContentDigest('sha-256=:abc123...:');
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function parseContentDigest(value) {
|
|
85
|
+
return parseDigestField(value);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parse Repr-Digest header field value.
|
|
89
|
+
* RFC 9530 §3.
|
|
90
|
+
*
|
|
91
|
+
* @param value - The Repr-Digest header value
|
|
92
|
+
* @returns Array of digests, or null if malformed
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const digests = parseReprDigest('sha-512=:xyz789...:');
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function parseReprDigest(value) {
|
|
100
|
+
return parseDigestField(value);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse digest preference values from a structured field dictionary.
|
|
104
|
+
* Returns null for malformed input.
|
|
105
|
+
*/
|
|
106
|
+
function parseWantDigestField(value) {
|
|
107
|
+
const dict = parseSfDict(value);
|
|
108
|
+
if (!dict) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const preferences = [];
|
|
112
|
+
for (const [algorithm, item] of Object.entries(dict)) {
|
|
113
|
+
// RFC 9530 §4: value is an Integer 0-10
|
|
114
|
+
if ('items' in item) {
|
|
115
|
+
// Inner list not valid for preferences
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const sfItem = item;
|
|
119
|
+
if (typeof sfItem.value !== 'number') {
|
|
120
|
+
// Must be an integer
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const weight = sfItem.value;
|
|
124
|
+
// RFC 9530 §4: must be in range 0 to 10 inclusive
|
|
125
|
+
if (!Number.isInteger(weight) || weight < 0 || weight > 10) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
preferences.push({
|
|
129
|
+
algorithm: algorithm.toLowerCase(),
|
|
130
|
+
weight,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return preferences.length > 0 ? preferences : [];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Parse Want-Content-Digest header field value.
|
|
137
|
+
* RFC 9530 §4.
|
|
138
|
+
*
|
|
139
|
+
* @param value - The Want-Content-Digest header value
|
|
140
|
+
* @returns Array of preferences, or null if malformed
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* const prefs = parseWantContentDigest('sha-256=10, sha-512=3');
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function parseWantContentDigest(value) {
|
|
148
|
+
return parseWantDigestField(value);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Parse Want-Repr-Digest header field value.
|
|
152
|
+
* RFC 9530 §4.
|
|
153
|
+
*
|
|
154
|
+
* @param value - The Want-Repr-Digest header value
|
|
155
|
+
* @returns Array of preferences, or null if malformed
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const prefs = parseWantReprDigest('sha-512=3, sha-256=10, unixsum=0');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function parseWantReprDigest(value) {
|
|
163
|
+
return parseWantDigestField(value);
|
|
164
|
+
}
|
|
165
|
+
// =============================================================================
|
|
166
|
+
// Formatting
|
|
167
|
+
// =============================================================================
|
|
168
|
+
/**
|
|
169
|
+
* Format digests as a structured field dictionary string.
|
|
170
|
+
*/
|
|
171
|
+
function formatDigestField(digests) {
|
|
172
|
+
const dict = {};
|
|
173
|
+
for (const digest of digests) {
|
|
174
|
+
// RFC 9530 §5: MUST NOT generate deprecated algorithms
|
|
175
|
+
// But we allow formatting any algorithm the caller provides
|
|
176
|
+
dict[digest.algorithm] = { value: digest.value };
|
|
177
|
+
}
|
|
178
|
+
return serializeSfDict(dict);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Format Content-Digest header field value.
|
|
182
|
+
* RFC 9530 §2.
|
|
183
|
+
*
|
|
184
|
+
* @param digests - Array of digests to format
|
|
185
|
+
* @returns Formatted header value
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* const header = formatContentDigest([
|
|
190
|
+
* { algorithm: 'sha-256', value: digestBytes }
|
|
191
|
+
* ]);
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export function formatContentDigest(digests) {
|
|
195
|
+
return formatDigestField(digests);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Format Repr-Digest header field value.
|
|
199
|
+
* RFC 9530 §3.
|
|
200
|
+
*
|
|
201
|
+
* @param digests - Array of digests to format
|
|
202
|
+
* @returns Formatted header value
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* const header = formatReprDigest([
|
|
207
|
+
* { algorithm: 'sha-512', value: digestBytes }
|
|
208
|
+
* ]);
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
export function formatReprDigest(digests) {
|
|
212
|
+
return formatDigestField(digests);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Format preferences as a structured field dictionary string.
|
|
216
|
+
*/
|
|
217
|
+
function formatWantDigestField(preferences) {
|
|
218
|
+
const dict = {};
|
|
219
|
+
for (const pref of preferences) {
|
|
220
|
+
// RFC 9530 §4: weight is an Integer 0-10
|
|
221
|
+
if (pref.weight < 0 || pref.weight > 10 || !Number.isInteger(pref.weight)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
dict[pref.algorithm] = { value: pref.weight };
|
|
225
|
+
}
|
|
226
|
+
return serializeSfDict(dict);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Format Want-Content-Digest header field value.
|
|
230
|
+
* RFC 9530 §4.
|
|
231
|
+
*
|
|
232
|
+
* @param preferences - Array of preferences to format
|
|
233
|
+
* @returns Formatted header value
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* const header = formatWantContentDigest([
|
|
238
|
+
* { algorithm: 'sha-256', weight: 10 },
|
|
239
|
+
* { algorithm: 'sha-512', weight: 3 }
|
|
240
|
+
* ]);
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
export function formatWantContentDigest(preferences) {
|
|
244
|
+
return formatWantDigestField(preferences);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Format Want-Repr-Digest header field value.
|
|
248
|
+
* RFC 9530 §4.
|
|
249
|
+
*
|
|
250
|
+
* @param preferences - Array of preferences to format
|
|
251
|
+
* @returns Formatted header value
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* const header = formatWantReprDigest([
|
|
256
|
+
* { algorithm: 'sha-512', weight: 3 },
|
|
257
|
+
* { algorithm: 'sha-256', weight: 10 },
|
|
258
|
+
* { algorithm: 'unixsum', weight: 0 }
|
|
259
|
+
* ]);
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
export function formatWantReprDigest(preferences) {
|
|
263
|
+
return formatWantDigestField(preferences);
|
|
264
|
+
}
|
|
265
|
+
// =============================================================================
|
|
266
|
+
// Generation and Verification
|
|
267
|
+
// =============================================================================
|
|
268
|
+
/**
|
|
269
|
+
* Map algorithm keys to Web Crypto algorithm names.
|
|
270
|
+
*/
|
|
271
|
+
const CRYPTO_ALGORITHMS = {
|
|
272
|
+
'sha-256': 'SHA-256',
|
|
273
|
+
'sha-512': 'SHA-512',
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Generate a digest for the given data.
|
|
277
|
+
* RFC 9530 §2, §3.
|
|
278
|
+
*
|
|
279
|
+
* Uses Web Crypto API for hashing. Only active algorithms are supported
|
|
280
|
+
* for generation per RFC 9530 §5.
|
|
281
|
+
*
|
|
282
|
+
* @param data - Data to hash (string, ArrayBuffer, or ArrayBufferView)
|
|
283
|
+
* @param algorithm - Hash algorithm (default: 'sha-256')
|
|
284
|
+
* @returns Promise resolving to digest
|
|
285
|
+
* @throws Error if algorithm is not supported for generation
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* const digest = await generateDigest('hello world');
|
|
290
|
+
* const headers = { 'Content-Digest': formatContentDigest([digest]) };
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export async function generateDigest(data, algorithm = 'sha-256') {
|
|
294
|
+
const cryptoAlgorithm = CRYPTO_ALGORITHMS[algorithm];
|
|
295
|
+
if (!cryptoAlgorithm) {
|
|
296
|
+
throw new Error(`Unsupported algorithm for generation: ${algorithm}`);
|
|
297
|
+
}
|
|
298
|
+
let buffer;
|
|
299
|
+
if (typeof data === 'string') {
|
|
300
|
+
buffer = new TextEncoder().encode(data).buffer;
|
|
301
|
+
}
|
|
302
|
+
else if (data instanceof ArrayBuffer) {
|
|
303
|
+
buffer = data;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// ArrayBufferView - create a copy to ensure it's an ArrayBuffer
|
|
307
|
+
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
308
|
+
buffer = view.slice().buffer;
|
|
309
|
+
}
|
|
310
|
+
const hashBuffer = await globalThis.crypto.subtle.digest(cryptoAlgorithm, buffer);
|
|
311
|
+
return {
|
|
312
|
+
algorithm,
|
|
313
|
+
value: new Uint8Array(hashBuffer),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Verify a digest against the given data.
|
|
318
|
+
* RFC 9530 §2, §3.
|
|
319
|
+
*
|
|
320
|
+
* Only active algorithms (sha-256, sha-512) can be verified.
|
|
321
|
+
* Deprecated algorithms will return false.
|
|
322
|
+
*
|
|
323
|
+
* @param data - Data to verify
|
|
324
|
+
* @param digest - Digest to check against
|
|
325
|
+
* @returns Promise resolving to true if digest matches
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* const digests = parseContentDigest(headers.get('Content-Digest'));
|
|
330
|
+
* const sha256 = digests?.find(d => d.algorithm === 'sha-256');
|
|
331
|
+
* if (sha256 && await verifyDigest(content, sha256)) {
|
|
332
|
+
* // Content integrity verified
|
|
333
|
+
* }
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
export async function verifyDigest(data, digest) {
|
|
337
|
+
// RFC 9530 §5: deprecated algorithms should not be used for verification
|
|
338
|
+
// in adversarial settings, but we allow it for backward compatibility
|
|
339
|
+
if (!isActiveAlgorithm(digest.algorithm)) {
|
|
340
|
+
// Cannot verify deprecated algorithms
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
const computed = await generateDigest(data, digest.algorithm);
|
|
344
|
+
// Compare byte arrays
|
|
345
|
+
if (computed.value.length !== digest.value.length) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
for (let i = 0; i < computed.value.length; i++) {
|
|
349
|
+
if (computed.value[i] !== digest.value[i]) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accept-Encoding utilities per RFC 9110.
|
|
3
|
+
* RFC 9110 §12.4.2, §12.4.3, §12.5.3.
|
|
4
|
+
*/
|
|
5
|
+
import type { EncodingRange } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse an Accept-Encoding header into ranges.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseAcceptEncoding(header: string): EncodingRange[];
|
|
10
|
+
/**
|
|
11
|
+
* Negotiate encoding based on Accept-Encoding.
|
|
12
|
+
*/
|
|
13
|
+
export declare function negotiateEncoding(ranges: EncodingRange[], supported: string[]): string | null;
|
|
14
|
+
//# sourceMappingURL=encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD;;GAEG;AAEH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAsCnE;AAWD;;GAEG;AAEH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAiC7F"}
|
package/dist/encoding.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accept-Encoding utilities per RFC 9110.
|
|
3
|
+
* RFC 9110 §12.4.2, §12.4.3, §12.5.3.
|
|
4
|
+
*/
|
|
5
|
+
import { isEmptyHeader, splitListValue, parseQValue } from './header-utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse an Accept-Encoding header into ranges.
|
|
8
|
+
*/
|
|
9
|
+
// RFC 9110 §12.5.3: Accept-Encoding field-value parsing.
|
|
10
|
+
export function parseAcceptEncoding(header) {
|
|
11
|
+
if (isEmptyHeader(header)) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const ranges = [];
|
|
15
|
+
const parts = splitListValue(header);
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
const segments = part.split(';').map(segment => segment.trim());
|
|
18
|
+
const encoding = segments[0]?.toLowerCase();
|
|
19
|
+
if (!encoding)
|
|
20
|
+
continue;
|
|
21
|
+
let q = 1.0;
|
|
22
|
+
let invalidQ = false;
|
|
23
|
+
for (let i = 1; i < segments.length; i++) {
|
|
24
|
+
const segment = segments[i];
|
|
25
|
+
const eqIndex = segment.indexOf('=');
|
|
26
|
+
if (eqIndex === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = segment.slice(0, eqIndex).trim().toLowerCase();
|
|
29
|
+
if (key !== 'q')
|
|
30
|
+
continue;
|
|
31
|
+
const parsed = parseQValue(segment.slice(eqIndex + 1).trim());
|
|
32
|
+
if (parsed === null) {
|
|
33
|
+
invalidQ = true;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
q = parsed;
|
|
37
|
+
}
|
|
38
|
+
if (invalidQ) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
ranges.push({ encoding, q });
|
|
42
|
+
}
|
|
43
|
+
ranges.sort((a, b) => b.q - a.q);
|
|
44
|
+
return ranges;
|
|
45
|
+
}
|
|
46
|
+
function getQForEncoding(ranges, encoding) {
|
|
47
|
+
for (const range of ranges) {
|
|
48
|
+
if (range.encoding === encoding) {
|
|
49
|
+
return range.q;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Negotiate encoding based on Accept-Encoding.
|
|
56
|
+
*/
|
|
57
|
+
// RFC 9110 §12.4.2, §12.4.3, §12.5.3: Content-coding selection.
|
|
58
|
+
export function negotiateEncoding(ranges, supported) {
|
|
59
|
+
if (supported.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (ranges.length === 0) {
|
|
63
|
+
return supported[0] ?? null;
|
|
64
|
+
}
|
|
65
|
+
const wildcard = ranges.find(range => range.encoding === '*');
|
|
66
|
+
let best = null;
|
|
67
|
+
let bestQ = 0;
|
|
68
|
+
for (const encoding of supported) {
|
|
69
|
+
const normalized = encoding.toLowerCase();
|
|
70
|
+
const explicitQ = getQForEncoding(ranges, normalized);
|
|
71
|
+
const q = explicitQ !== null
|
|
72
|
+
? explicitQ
|
|
73
|
+
: (normalized === 'identity'
|
|
74
|
+
? (wildcard ? wildcard.q : 1.0)
|
|
75
|
+
: (wildcard ? wildcard.q : 0));
|
|
76
|
+
if (q > bestQ) {
|
|
77
|
+
best = encoding;
|
|
78
|
+
bestQ = q;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (bestQ === 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return best;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;GAEG;AACH,yDAAyD;AACzD,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAC9C,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;QAC5C,IAAI,CAAC,QAAQ;YAAE,SAAS;QAExB,IAAI,CAAC,GAAG,GAAG,CAAC;QACZ,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,OAAO,KAAK,CAAC,CAAC;gBAAE,SAAS;YAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3D,IAAI,GAAG,KAAK,GAAG;gBAAE,SAAS;YAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAClB,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACV,CAAC;YACD,CAAC,GAAG,MAAM,CAAC;QACf,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACX,SAAS;QACb,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,MAAuB,EAAE,QAAgB;IAC9D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC,CAAC,CAAC;QACnB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,gEAAgE;AAChE,MAAM,UAAU,iBAAiB,CAAC,MAAuB,EAAE,SAAmB;IAC1E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAChC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;IAC9D,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,SAAS,KAAK,IAAI;YACxB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU;gBACxB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBAC/B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;YACZ,IAAI,GAAG,QAAQ,CAAC;YAChB,KAAK,GAAG,CAAC,CAAC;QACd,CAAC;IACL,CAAC;IAED,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
package/dist/etag.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ETag utilities per RFC 9110.
|
|
3
|
+
* RFC 9110 §8.8.3, §8.8.3.2.
|
|
4
|
+
* @see https://httpwg.org/specs/rfc9110.html#field.etag
|
|
5
|
+
*/
|
|
6
|
+
import type { ETag } from './types.js';
|
|
7
|
+
export type { ETag } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate a simple ETag from data (sync, using string hash)
|
|
10
|
+
* Uses a simple hash algorithm suitable for most use cases.
|
|
11
|
+
* Returns format: "hash" (strong) or W/"hash" (if weak option specified)
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateETag(data: unknown, options?: {
|
|
14
|
+
weak?: boolean;
|
|
15
|
+
}): string;
|
|
16
|
+
/**
|
|
17
|
+
* Generate an ETag using Web Crypto API (async, more secure)
|
|
18
|
+
* Uses SHA-256 by default.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateETagAsync(data: unknown, options?: {
|
|
21
|
+
algorithm?: 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
22
|
+
weak?: boolean;
|
|
23
|
+
}): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Parse an ETag string into its components
|
|
26
|
+
* Handles: "abc", W/"abc", ""
|
|
27
|
+
* Returns null for invalid format
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseETag(etag: string): ETag | null;
|
|
30
|
+
/**
|
|
31
|
+
* Format an ETag object back to string
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatETag(etag: ETag): string;
|
|
34
|
+
/**
|
|
35
|
+
* Compare two ETags per RFC 9110 §8.8.3.
|
|
36
|
+
*
|
|
37
|
+
* Strong comparison: both must be strong AND values match
|
|
38
|
+
* Weak comparison: values match (regardless of weak/strong)
|
|
39
|
+
*
|
|
40
|
+
* RFC 9110 §8.8.3.2 comparison table:
|
|
41
|
+
* | ETag 1 | ETag 2 | Strong | Weak |
|
|
42
|
+
* |---------|---------|--------|-------|
|
|
43
|
+
* | W/"1" | W/"1" | false | true |
|
|
44
|
+
* | W/"1" | "1" | false | true |
|
|
45
|
+
* | "1" | "1" | true | true |
|
|
46
|
+
* | "1" | W/"1" | false | true |
|
|
47
|
+
* | W/"1" | W/"2" | false | false |
|
|
48
|
+
* | "1" | "2" | false | false |
|
|
49
|
+
*/
|
|
50
|
+
export declare function compareETags(a: ETag, b: ETag, strong?: boolean): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Convenience function to compare ETag strings directly
|
|
53
|
+
*/
|
|
54
|
+
export declare function compareETagStrings(a: string, b: string, strong?: boolean): boolean;
|
|
55
|
+
//# sourceMappingURL=etag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etag.d.ts","sourceRoot":"","sources":["../src/etag.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAoEvC;;;;GAIG;AAEH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAKhF;AAED;;;GAGG;AAEH,wBAAsB,iBAAiB,CACnC,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GACtF,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;GAIG;AAEH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmCnD;AAED;;GAEG;AAEH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CAa/E;AAED;;GAEG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CASzF"}
|