138 lines
3.5 KiB
TypeScript
138 lines
3.5 KiB
TypeScript
![]() |
/**
|
||
|
* TUS协议头部验证器
|
||
|
*
|
||
|
* 该模块实现了TUS协议中各种HTTP头部的验证逻辑
|
||
|
* TUS是一个用于可恢复文件上传的开放协议
|
||
|
*
|
||
|
* @version 1.0.0
|
||
|
* @see https://tus.io/protocols/resumable-upload.html
|
||
|
*/
|
||
|
|
||
|
import { Metadata, TUS_VERSION, TUS_RESUMABLE } from "../utils"
|
||
|
|
||
|
|
||
|
/** 验证器函数类型定义,接收可选的字符串值,返回布尔值表示验证结果 */
|
||
|
type validator = (value?: string) => boolean
|
||
|
|
||
|
/**
|
||
|
* TUS协议头部验证器映射表
|
||
|
* 包含了所有TUS协议规定的HTTP头部的验证规则
|
||
|
*/
|
||
|
export const validators = new Map<string, validator>([
|
||
|
[
|
||
|
'upload-offset',
|
||
|
/**
|
||
|
* Upload-Offset头部验证
|
||
|
* 用于指示资源内的字节偏移量
|
||
|
* 必须是非负整数
|
||
|
*/
|
||
|
(value) => {
|
||
|
const n = Number(value)
|
||
|
return Number.isInteger(n) && String(n) === value && n >= 0
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'upload-length',
|
||
|
/**
|
||
|
* Upload-Length头部验证
|
||
|
* 表示整个上传文件的字节大小
|
||
|
* 必须是非负整数
|
||
|
*/
|
||
|
(value) => {
|
||
|
const n = Number(value)
|
||
|
return Number.isInteger(n) && String(n) === value && n >= 0
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'upload-defer-length',
|
||
|
/**
|
||
|
* Upload-Defer-Length头部验证
|
||
|
* 表示上传大小当前未知,将在后续传输
|
||
|
* 值必须为1,如果长度未延迟则必须省略此头部
|
||
|
*/
|
||
|
(value) => value === '1',
|
||
|
],
|
||
|
[
|
||
|
'upload-metadata',
|
||
|
/**
|
||
|
* Upload-Metadata头部验证
|
||
|
* 必须由一个或多个逗号分隔的键值对组成
|
||
|
* 键和值必须用空格分隔
|
||
|
* 键不能包含空格和逗号且不能为空
|
||
|
* 键应该是ASCII编码,值必须是Base64编码
|
||
|
* 所有键必须唯一
|
||
|
*/
|
||
|
(value) => {
|
||
|
try {
|
||
|
Metadata.parse(value)
|
||
|
return true
|
||
|
} catch {
|
||
|
return false
|
||
|
}
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'x-forwarded-proto',
|
||
|
/**
|
||
|
* X-Forwarded-Proto头部验证
|
||
|
* 用于标识客户端与服务器之间的协议
|
||
|
* 仅允许http或https
|
||
|
*/
|
||
|
(value) => {
|
||
|
if (value === 'http' || value === 'https') {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'tus-version',
|
||
|
/**
|
||
|
* Tus-Version头部验证
|
||
|
* 服务器支持的协议版本列表
|
||
|
* 必须按服务器偏好排序,第一个是最优先的
|
||
|
*/
|
||
|
(value) => {
|
||
|
return TUS_VERSION.includes(value as any)
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'tus-resumable',
|
||
|
/**
|
||
|
* Tus-Resumable头部验证
|
||
|
* 除OPTIONS请求外的每个请求和响应都必须包含
|
||
|
* 值必须是客户端或服务器使用的协议版本
|
||
|
*/
|
||
|
(value) => value === TUS_RESUMABLE,
|
||
|
],
|
||
|
['content-type', (value) => value === 'application/offset+octet-stream'],
|
||
|
[
|
||
|
'upload-concat',
|
||
|
/**
|
||
|
* Upload-Concat头部验证
|
||
|
* 用于部分上传和最终上传的创建请求
|
||
|
* 部分上传值必须为partial
|
||
|
* 最终上传值必须以final开头,后跟分号和空格分隔的部分上传URL列表
|
||
|
*/
|
||
|
(value) => {
|
||
|
if (!value) return false
|
||
|
const valid_partial = value === 'partial'
|
||
|
const valid_final = value.startsWith('final;')
|
||
|
return valid_partial || valid_final
|
||
|
},
|
||
|
],
|
||
|
])
|
||
|
|
||
|
/**
|
||
|
* 验证HTTP头部值是否符合TUS协议规范
|
||
|
* @param name 头部名称
|
||
|
* @param value 头部值
|
||
|
* @returns 验证是否通过
|
||
|
*/
|
||
|
export function validateHeader(name: string, value?: string): boolean {
|
||
|
const lowercaseName = name.toLowerCase()
|
||
|
if (!validators.has(lowercaseName)) {
|
||
|
return true
|
||
|
}
|
||
|
return validators.get(lowercaseName)!(value)
|
||
|
}
|