Tusdotnet Versions Save

.NET server implementation of the Tus protocol for resumable file uploads. Read more at https://tus.io

2.8

3 months ago

Client disconnect detection

One of the core features of tusdotnet is knowing when a client has disconnected so that held resources can be released. A client disconnect can be detected by either the client telling the server that it disconnected or that a timeout occurs. The timeout settings in tusdotnet previously depended on a reverse proxy signaling a timeout or that Kestrel was configured correctly. Starting with the release tusdotnet contains its own logic for handling timeouts which are more efficient than relying on a global request timeout. The new timeout mechanism determines how long tusdotnet will wait to receive data from the client and not how long the entire request takes, meaning that it will need to wait a shorter time before disconnecting a slow client and unlocking the file.

The client read timeout is configured using the ClientReadTimeout property on the DefaultTusConfiguration. The default value is set to a conservative 60 seconds to not interfere with existing timeout settings.

Lock on HEAD requests

HEAD requests to determine the upload offset for the client was previously a non-locking action. This version changes this behavior to locking. This increases stability in cases where data is in transfer but has not yet reached the server when the client disconnects and reconnects. In earlier versions this would cause the wrong offset to be retrieved. The client would then continue from the wrong offset causing an offset mismatch error when trying to patch the data.

Compatibility with other implementations

Response code for locked operations have been changed from 409 Conflict to 423 Locked to better conform to how clients and other servers are implemented.

Exceptions thrown from OnFileCompleteAsync were swallowed for creation-with-upload

This causes issues in the case when an exception is thrown from OnFileCompleteAsync as the exception would be swallowed and a 201 Created would be returned to the client instead of the exception. See #211 for details.

What's Changed

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.7.2...2.8

2.7.2

5 months ago

Bug fix release

What's Changed

  • Use the request path base when creating location header urls by @Louis9902 in https://github.com/tusdotnet/tusdotnet/pull/210
  • POST to a file url (e.g. /files/1234) created a new file resource (e.g. /files/5678) due to URL misinterpretation (331d707)

New Contributors

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.7.1...2.7.2

2.7.1

1 year ago

Bug fix release.

  1. Exceptions thrown in TusDiskStore where sometimes hidden from the world (2b18346)
  2. TusDiskStore would sometimes throw an InvalidCastException (d08a145)

What's Changed

New Contributors

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.7...2.7.1

2.7

1 year ago

This release brings a long awaited feature namely integration with endpoint routing in ASP.NET Core! 🎉

This allows developers on NET Core 3.1 and later to take advantage of the power of route templates and integrate with features such as the integrated authorization schemes. Older frameworks still need to use the middleware approach, i.e UseTus. UseTus is still available and works exactly as before for NET Core 3.1 and later.

How to migrate? It's very simple. Change UseTus to MapTus and you are good to go.

app.MapTus("/files/", httpContext => new DefaultTusConfiguration {...});

Other changes:

  • The upload url returned to the client can now be customized from OnCreateCompleteAsync by calling SetUploadUrl on the provided context. Please note that the file id must be included as the last part of the path (get it from FileId on the provided context)

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.6.2...2.7

2.6.2

1 year ago

This release fixes an issue when using pipelines in 2.6.1 where the amount of data sent by the client was calculated wrong. This resulted in a 413 Request Entity Too Large error being sent to the client.

Changes between 2.6.0 and 2.6.2:

  • Upload-defer-length can now be used over multiple requests, i.e. the Upload-Length header no longer needs to be set on the first PATCH request.
  • DefaultTusConfiguration is now validated earlier in the pipeline which removes a null ref exception if UrlPath was not set.
  • Minimum version of Microsoft.Owin has been increased to 4.2.2 to prevent a cookie parsing bug in Owin which could cause a denial of service.
  • Exceeding the file's size (Upload-Length) or the server's max size (Tus-Max-Size) will now return a 413 Request Entity Too Large instead of a generic 400 Bad Request. Note to store authors: The Stream or PipeReader provided to AppendDataAsync will now automatically keep track of how much data the client have sent so far and will throw an exception if this number exceeds the file's or server's max size.

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.6...2.6.2

2.6.1

1 year ago

EDIT: ⚠️ Pipeline support is broken in this release, go for 2.6.2 instead.

Fixed:

  • Upload-defer-length can now be used over multiple requests, i.e. the Upload-Length header no longer needs to be set on the first PATCH request.
  • DefaultTusConfiguration is now validated earlier in the pipeline which removes a null ref exception if UrlPath was not set.
  • Minimum version of Microsoft.Owin has been increased to 4.2.2 to prevent a cookie parsing bug in Owin which could cause a denial of service.

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.6...2.6.1

2.6

2 years ago

Support for manually enabling/disabling extensions

tusdotnet ships with a build in feature detection for extensions based on what the store supports. This version adds support for manually enabling and disabling extensions. The store still needs to support the extension for it to work.

As an example, to allow all extensions but termination:


return new DefaultTusConfiguration
{
    UrlPath = "/files",
    Store = new TusDiskStore(...),
    AllowedExtensions = TusExtensions.All.Except(TusExtensions.Termination),
}

To enable specific extensions, in this case creation and termination:

return new DefaultTusConfiguration
{
    UrlPath = "/files",
    Store = new TusDiskStore(...),
    AllowedExtensions = new TusExtensions(TusExtensions.Creation, TusExtensions.Termination),
    ...
}

And finally, to only allow a single extension, in this case creation:

return new DefaultTusConfiguration
{
    UrlPath = "/files",
    Store = new TusDiskStore(...),
    AllowedExtensions = TusExtensions.Creation,
    ...
}

What's Changed

Full Changelog: https://github.com/tusdotnet/tusdotnet/compare/2.5.0...2.6

2.5.0

2 years ago

Support for System.IO.Pipelines

tusdotnet now allows stores to read directly from the request's BodyReader (System.IO.Pipelines.PipeReader) on .NET Core 3.1 and later. This has a number of advantages with regards to CPU load, memory usage and throughput (see https://github.com/tusdotnet/tusdotnet/issues/146). The downside to using pipelines is that it might be slower to write the file as multiple syscalls are needed. For this reason, pipelines are not enabled by default on .NET Core 3.1. In .NET 6 most of these issues have been fixed so tusdotnet will automatically use pipelines if supported by the store.

Requirements to be able to use pipelines in tusdotnet:

  • Run on .NET Core 3.1 or later
  • Use a store that implements ITusPipelineStore (TusDiskStore does)
  • Set UsePipelinesIfAvailable to true on the DefaultTusConfiguration object (only required for .NET Core 3.1)

Thanks to @SnGmng for coming up with the idea and creating the initial PR!

New build target: .NET 6

A new build target for .NET 6 has been added which improves overall performance.

Performance improvements

Parts of tusdotnet have been rewritten to boost performance.

Rewritten part Time taken reduction Memory usage reduction Benchmark commit
Metadata parsing 55% 72% c5b79aa4e8a039971d238de5a3f302d00ec48d34
Checksum parsing 40% 50% 4d0ad6c966259a31eb230bf5485f0a3a64018aaa
File concat parsing 80% 80% 0206fb8fa2d1eaea754a4fd0b72fb2900594c986
Event dispatching 50% 0% 00b692b0a1983d46f69205f4ce59a9f1650e7d25

Misc improvements

  • Flakiness in tests have been reduced
  • Error messages for file concat parsing are now easier to understand

2.4.0

2 years ago

New extension "checksum-trailer"

This version adds support for providing the Upload-Checksum as a trailing header, i.e. after the body has been received. This feature is only available on .NET Core 3.1 or later as there is no earlier support for trailing headers in .NET.

checksum-trailer is a sub-extension to the checksum extension.

More info: https://tus.io/protocols/resumable-upload.html#checksum

For store authors

No new interface is required for checksum-trailer. tusdotnet will automatically call ITusChecksumStore.VerifyChecksumAsync if a trailing checksum is provided. If the trailing header fails to parse, tusdotnet will purposely provide a fauly checksum to force the store to discard the chunk. To not have to calculate the checksum of the chunk the store can call tusdotnet.Helpers.ChecksumTrailerHelper.IsFallback(algorithm, checksum) from inside VerifyChecksumAsync. This method will return true if the provided checksum is the fallback used by tusdotnet. IsFallback will always return false on unsupported platforms.

Custom file Id providers

TusDiskStore now supports customizing the file ids returned. This is helpful in cases where developers need to conform to a specific format for other backend systems. tusdotnet ships with two built in providers and will default to using a GUID (format = "n") as ID.

More info: https://github.com/tusdotnet/tusdotnet/wiki/Custom-File-Id-Provider

Custom file locks

tusdotnet uses locks to prevent multiple requests from modifying the same file at the same time. In earlier versions this was done through a simple in-memory lock. This version adds support for custom file locks which is helpful when tusdotnet is used in a clustered environment.

tusdotnet ships with the original in-memory lock and a new disk file lock.

More info: https://github.com/tusdotnet/tusdotnet/wiki/Custom-File-Lock

Bug fixes

  • OnFileCompleteAsync never gets fired when uploading a file with size 0 (#119, #134)

New build targets

.NET Standard 2.0 and .NET Core 3.1 have been added as build targets.

  • .NET Standard 2.0 will hopefully remove some warnings from code analyzers while at the same time reducing the number of packages that need to be install during dotnet restore.
  • .NET Core 3.1 was added to support the checksum-trailer extension as earlier LTS versions did not support trailing headers.

As .NET continues to develop and new versions being released, older versions are also being retired. In the upcoming months a new version of tusdotnet will be released that drops support for .NET Standard 1.3 and .NET 4.5.2 while .NET Standard 2.0, .NET Core 3.1 (latest LTS) and later will still be supported.

2.3

4 years ago

This release aims to give better compatibility in regards to recent updates to the tus protocol.

New extension "creation-with-upload" #80

This extension allows the client to provide parts of the file content in the initial file creation (POST) request. It is recommended to not include too much data as everything will be lost if the client disconnects during this request (as no Location is returned to the client). The reponse will contain the Upload-Offset to use for the following PATCH request. If validation of the file or the headers (e.g. Content-Type) fails then no data will be written and zero will be returned as Upload-Offset.

Note that Upload-Defer-Length is not supported when using creation-with-upload.

Protocol specification: https://tus.io/protocols/resumable-upload.html#creation-with-upload

Metadata can now contain keys without values #79

In previous versions only key/value pairs where allowed as metadata:

Upload-Metadata: filename d29ybGRfZG9taW5hdGlvbl9wbGFuLnBkZg==

In 2.3 the client can also include keys with no value:

Upload-Metadata: filename d29ybGRfZG9taW5hdGlvbl9wbGFuLnBkZg==,is_confidential

To use the old, more restrictive way of parsing metadata, set the MetadataParsingStrategy configuration property to Original

app.UseTus(httpContext => new DefaultTusConfiguration
{
    UrlPath = ...,
    Store = ...,
    MetadataParsingStrategy = MetadataParsingStrategy.Original
    ...
});

Bug fixes

  • If the Content-Type header for a PATCH request is not application/offset+octet-stream a 415 Unsupported Media Type is now returned instead of a 400 Bad Request. #83
  • Source links is now using the correct URI on Github. #84
  • In some edge cases, files created using Upload-Defer-Length could be corrupted if Upload-Defer-Length was not supported when writing the data.
  • Deleting a file no longer cares about the client being disconnected throughout the entire process or not (reduces number of partially deleted files).
  • Partially deleted files (e.g. if file deletion failed) are now handled correctly by GetExpiredFilesAsync and DeleteExpiredFilesAsync.