|
|
|
|
|
|
|
|
|
|
|
|
|
export function negotiate(accept, types) { |
|
|
|
const parts = []; |
|
|
|
accept.split(',').forEach((str, i) => { |
|
const match = /([^/ \t]+)\/([^; \t]+)[ \t]*(?:;[ \t]*q=([0-9.]+))?/.exec(str); |
|
|
|
|
|
if (match) { |
|
const [, type, subtype, q = '1'] = match; |
|
parts.push({ type, subtype, q: +q, i }); |
|
} |
|
}); |
|
|
|
parts.sort((a, b) => { |
|
if (a.q !== b.q) { |
|
return b.q - a.q; |
|
} |
|
|
|
if ((a.subtype === '*') !== (b.subtype === '*')) { |
|
return a.subtype === '*' ? 1 : -1; |
|
} |
|
|
|
if ((a.type === '*') !== (b.type === '*')) { |
|
return a.type === '*' ? 1 : -1; |
|
} |
|
|
|
return a.i - b.i; |
|
}); |
|
|
|
let accepted; |
|
let min_priority = Infinity; |
|
|
|
for (const mimetype of types) { |
|
const [type, subtype] = mimetype.split('/'); |
|
const priority = parts.findIndex( |
|
(part) => |
|
(part.type === type || part.type === '*') && |
|
(part.subtype === subtype || part.subtype === '*') |
|
); |
|
|
|
if (priority !== -1 && priority < min_priority) { |
|
accepted = mimetype; |
|
min_priority = priority; |
|
} |
|
} |
|
|
|
return accepted; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function is_content_type(request, ...types) { |
|
const type = request.headers.get('content-type')?.split(';', 1)[0].trim() ?? ''; |
|
return types.includes(type.toLowerCase()); |
|
} |
|
|
|
|
|
|
|
|
|
export function is_form_content_type(request) { |
|
|
|
|
|
return is_content_type( |
|
request, |
|
'application/x-www-form-urlencoded', |
|
'multipart/form-data', |
|
'text/plain' |
|
); |
|
} |
|
|