///|
/// Stable categories returned by protocol parsing and state transitions.
/// Applications should branch on these values instead of matching messages.
pub(all) enum TusErrorKind {
InvalidMethod
InvalidPath
InvalidHeaderName
UnsafeHeaderValue
MissingTusResumable
UnsupportedVersion
DuplicateSingletonHeader
InvalidUnsignedInteger
IntegerOverflow
MissingUploadOffset
OffsetMismatch
MissingContentType
InvalidContentType
MissingContentLength
BodyLengthMismatch
MissingUploadLength
ConflictingUploadLength
InvalidDeferredLength
UploadTooLarge
UploadNotFound
UploadAlreadyComplete
UploadTerminated
InvalidMetadata
DuplicateMetadataKey
MetadataTooLarge
TooManyMetadataEntries
InvalidBase64
HeaderCountExceeded
HeaderBytesExceeded
BodyTooLarge
IdentifierExhausted
StorageConflict
StorageFailure
UnsupportedExtension
InvalidScenario
UnsupportedScenario
InternalInvariant
} derive(Debug, Eq)
///|
/// Machine-stable protocol failure. `status` is the recommended HTTP response
/// status. It is data rather than an exception so adapters can translate it.
pub(all) struct TusError {
kind : TusErrorKind
code : String
message : String
status : Int
header_name : String?
expected : String?
actual : String?
} derive(Debug, Eq)
///|
pub fn tus_error(
kind : TusErrorKind,
code : String,
message : String,
status? : Int = 400,
header_name? : String? = None,
expected? : String? = None,
actual? : String? = None,
) -> TusError {
{ kind, code, message, status, header_name, expected, actual, }
}
///|
pub fn invalid_method(http_method : String) -> TusError {
tus_error(
InvalidMethod,
"TUS_METHOD_UNSUPPORTED",
"method is not supported by the configured tus endpoint",
status=405,
actual=Some(http_method),
)
}
///|
pub fn invalid_path(path : String) -> TusError {
tus_error(
InvalidPath,
"TUS_PATH_INVALID",
"request path is not a valid upload collection or resource path",
status=404,
actual=Some(path),
)
}
///|
pub fn missing_header(name : String, kind : TusErrorKind) -> TusError {
tus_error(
kind,
"TUS_REQUIRED_HEADER_MISSING",
"a required tus request header is missing",
header_name=Some(name),
)
}
///|
pub fn duplicate_header(name : String) -> TusError {
tus_error(
DuplicateSingletonHeader,
"TUS_SINGLETON_HEADER_REPEATED",
"a singleton tus header occurs more than once",
header_name=Some(name),
)
}
///|
pub fn unsupported_version(actual : String) -> TusError {
tus_error(
UnsupportedVersion,
"TUS_VERSION_UNSUPPORTED",
"Tus-Resumable does not name a supported protocol version",
status=412,
header_name=Some("tus-resumable"),
expected=Some("1.0.0"),
actual=Some(actual),
)
}
///|
pub fn invalid_integer(name : String, actual : String) -> TusError {
tus_error(
InvalidUnsignedInteger,
"TUS_INTEGER_INVALID",
"header must contain one non-negative decimal integer",
header_name=Some(name),
actual=Some(actual),
)
}
///|
pub fn integer_overflow(name : String, actual : String) -> TusError {
tus_error(
IntegerOverflow,
"TUS_INTEGER_OVERFLOW",
"header value exceeds the supported signed 64-bit range",
header_name=Some(name),
actual=Some(actual),
)
}
///|
pub fn offset_mismatch(expected : Int64, actual : Int64) -> TusError {
tus_error(
OffsetMismatch,
"TUS_OFFSET_MISMATCH",
"Upload-Offset does not match the resource offset",
status=409,
header_name=Some("upload-offset"),
expected=Some(expected.to_string()),
actual=Some(actual.to_string()),
)
}
///|
pub fn body_length_mismatch(expected : Int, actual : Int) -> TusError {
tus_error(
BodyLengthMismatch,
"TUS_BODY_LENGTH_MISMATCH",
"Content-Length does not equal the supplied body length",
status=400,
header_name=Some("content-length"),
expected=Some(expected.to_string()),
actual=Some(actual.to_string()),
)
}
///|
pub fn upload_not_found(identifier : String) -> TusError {
tus_error(
UploadNotFound,
"TUS_UPLOAD_NOT_FOUND",
"the upload resource does not exist",
status=404,
actual=Some(identifier),
)
}
///|
pub fn upload_complete(identifier : String) -> TusError {
tus_error(
UploadAlreadyComplete,
"TUS_UPLOAD_ALREADY_COMPLETE",
"the upload resource has already reached its declared length",
status=409,
actual=Some(identifier),
)
}
///|
pub fn upload_too_large(limit : Int64, actual : Int64) -> TusError {
tus_error(
UploadTooLarge,
"TUS_UPLOAD_TOO_LARGE",
"declared or resulting upload size exceeds the configured limit",
status=413,
expected=Some(limit.to_string()),
actual=Some(actual.to_string()),
)
}
///|
pub fn invalid_metadata(message : String) -> TusError {
tus_error(InvalidMetadata, "TUS_METADATA_INVALID", message)
}
///|
pub fn storage_conflict(identifier : String) -> TusError {
tus_error(
StorageConflict,
"TUS_STORAGE_CONFLICT",
"upload state changed before the transition could be committed",
status=409,
actual=Some(identifier),
)
}
///|
pub fn error_kind_name(kind : TusErrorKind) -> String {
match kind {
InvalidMethod => "invalid-method"
InvalidPath => "invalid-path"
InvalidHeaderName => "invalid-header-name"
UnsafeHeaderValue => "unsafe-header-value"
MissingTusResumable => "missing-tus-resumable"
UnsupportedVersion => "unsupported-version"
DuplicateSingletonHeader => "duplicate-singleton-header"
InvalidUnsignedInteger => "invalid-unsigned-integer"
IntegerOverflow => "integer-overflow"
MissingUploadOffset => "missing-upload-offset"
OffsetMismatch => "offset-mismatch"
MissingContentType => "missing-content-type"
InvalidContentType => "invalid-content-type"
MissingContentLength => "missing-content-length"
BodyLengthMismatch => "body-length-mismatch"
MissingUploadLength => "missing-upload-length"
ConflictingUploadLength => "conflicting-upload-length"
InvalidDeferredLength => "invalid-deferred-length"
UploadTooLarge => "upload-too-large"
UploadNotFound => "upload-not-found"
UploadAlreadyComplete => "upload-already-complete"
UploadTerminated => "upload-terminated"
InvalidMetadata => "invalid-metadata"
DuplicateMetadataKey => "duplicate-metadata-key"
MetadataTooLarge => "metadata-too-large"
TooManyMetadataEntries => "too-many-metadata-entries"
InvalidBase64 => "invalid-base64"
HeaderCountExceeded => "header-count-exceeded"
HeaderBytesExceeded => "header-bytes-exceeded"
BodyTooLarge => "body-too-large"
IdentifierExhausted => "identifier-exhausted"
StorageConflict => "storage-conflict"
StorageFailure => "storage-failure"
UnsupportedExtension => "unsupported-extension"
InvalidScenario => "invalid-scenario"
UnsupportedScenario => "unsupported-scenario"
InternalInvariant => "internal-invariant"
}
}