Compare commits

..

2 Commits

Author SHA1 Message Date
Marius 8abe05cebf Merge branch 'main' of github.com:tus/tusd into better-docs 2023-02-16 12:58:37 +01:00
Marius 2bbea6f91f
Update usage-binary.md 2023-02-11 13:57:14 +01:00
13 changed files with 83 additions and 800 deletions

View File

@ -1,156 +0,0 @@
# Taken from https://github.com/hrvey/combine-prs-workflow
# This action can be triggered manually to combine multiple PRs for
# dependency upgrades into a single PR. See the above links for
# more details.
name: 'Combine PRs'
# Controls when the action will run - in this case triggered manually
on:
workflow_dispatch:
inputs:
branchPrefix:
description: 'Branch prefix to find combinable PRs based on'
required: true
default: 'dependabot'
mustBeGreen:
description: 'Only combine PRs that are green (status is success). Set to false if repo does not run checks'
type: boolean
required: true
default: true
combineBranchName:
description: 'Name of the branch to combine PRs into'
required: true
default: 'combine-prs-branch'
ignoreLabel:
description: 'Exclude PRs with this label'
required: true
default: 'nocombine'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "combine-prs"
combine-prs:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/github-script@v6
id: create-combined-pr
name: Create Combined PR
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
owner: context.repo.owner,
repo: context.repo.repo
});
let branchesAndPRStrings = [];
let baseBranch = null;
let baseBranchSHA = null;
for (const pull of pulls) {
const branch = pull['head']['ref'];
console.log('Pull for branch: ' + branch);
if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) {
console.log('Branch matched prefix: ' + branch);
let statusOK = true;
if(${{ github.event.inputs.mustBeGreen }}) {
console.log('Checking green status: ' + branch);
const stateQuery = `query($owner: String!, $repo: String!, $pull_number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number:$pull_number) {
commits(last: 1) {
nodes {
commit {
statusCheckRollup {
state
}
}
}
}
}
}
}`
const vars = {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pull['number']
};
const result = await github.graphql(stateQuery, vars);
const [{ commit }] = result.repository.pullRequest.commits.nodes;
const state = commit.statusCheckRollup.state
console.log('Validating status: ' + state);
if(state != 'SUCCESS') {
console.log('Discarding ' + branch + ' with status ' + state);
statusOK = false;
}
}
console.log('Checking labels: ' + branch);
const labels = pull['labels'];
for(const label of labels) {
const labelName = label['name'];
console.log('Checking label: ' + labelName);
if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
console.log('Discarding ' + branch + ' with label ' + labelName);
statusOK = false;
}
}
if (statusOK) {
console.log('Adding branch to array: ' + branch);
const prString = '#' + pull['number'] + ' ' + pull['title'];
branchesAndPRStrings.push({ branch, prString });
baseBranch = pull['base']['ref'];
baseBranchSHA = pull['base']['sha'];
}
}
}
if (branchesAndPRStrings.length == 0) {
core.setFailed('No PRs/branches matched criteria');
return;
}
try {
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/heads/' + '${{ github.event.inputs.combineBranchName }}',
sha: baseBranchSHA
});
} catch (error) {
console.log(error);
core.setFailed('Failed to create combined branch - maybe a branch by that name already exists?');
return;
}
let combinedPRs = [];
let mergeFailedPRs = [];
for(const { branch, prString } of branchesAndPRStrings) {
try {
await github.rest.repos.merge({
owner: context.repo.owner,
repo: context.repo.repo,
base: '${{ github.event.inputs.combineBranchName }}',
head: branch,
});
console.log('Merged branch ' + branch);
combinedPRs.push(prString);
} catch (error) {
console.log('Failed to merge branch ' + branch);
mergeFailedPRs.push(prString);
}
}
console.log('Creating combined PR');
const combinedPRsString = combinedPRs.join('\n');
let body = '✅ This PR was created by the Combine PRs action by combining the following PRs:\n' + combinedPRsString;
if(mergeFailedPRs.length > 0) {
const mergeFailedPRsString = mergeFailedPRs.join('\n');
body += '\n\n⚠ The following PRs were left out due to merge conflicts:\n' + mergeFailedPRsString
}
await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Combined PR',
head: '${{ github.event.inputs.combineBranchName }}',
base: baseBranch,
body: body
});

View File

@ -9,7 +9,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
go-version: [stable, oldstable] go-version: [1.18.x, 1.19.x]
platform: [ubuntu-latest, macos-latest, windows-latest] platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env: env:
@ -21,7 +21,7 @@ jobs:
- -
name: Install Go name: Install Go
uses: actions/setup-go@v4 uses: actions/setup-go@v3
with: with:
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}

View File

@ -21,7 +21,7 @@ jobs:
- -
name: Docker meta name: Docker meta
id: docker_meta id: docker_meta
uses: docker/metadata-action@v4.4.0 uses: docker/metadata-action@v4.3.0
with: with:
images: | images: |
ghcr.io/tus/tusd ghcr.io/tus/tusd
@ -35,7 +35,7 @@ jobs:
- -
name: Set up Docker Buildx name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v2.5.0 uses: docker/setup-buildx-action@v2.4.1
with: with:
install: true install: true
@ -81,10 +81,10 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- -
name: Install Go name: Install Go 1.19
uses: actions/setup-go@v4 uses: actions/setup-go@v3
with: with:
go-version: 'stable' go-version: '1.19.5'
- -
name: Build TUSD name: Build TUSD
@ -105,7 +105,7 @@ jobs:
- -
name: Deploy to heroku name: Deploy to heroku
uses: akhileshns/heroku-deploy@v3.12.14 uses: akhileshns/heroku-deploy@v3.12.13
with: with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}} heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: ${{secrets.HEROKU_APP_NAME}} heroku_app_name: ${{secrets.HEROKU_APP_NAME}}

View File

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.20.4-alpine AS builder FROM golang:1.20.0-alpine AS builder
WORKDIR /go/src/github.com/tus/tusd WORKDIR /go/src/github.com/tus/tusd
# Add gcc and libc-dev early so it is cached # Add gcc and libc-dev early so it is cached
@ -19,17 +19,13 @@ COPY pkg/ ./pkg/
ARG GIT_VERSION ARG GIT_VERSION
ARG GIT_COMMIT ARG GIT_COMMIT
# Get the operating system and architecture to build for
ARG TARGETOS
ARG TARGETARCH
RUN set -xe \ RUN set -xe \
&& GOOS=$TARGETOS GOARCH=$TARGETARCH go build \ && GOOS=linux GOARCH=amd64 go build \
-ldflags="-X github.com/tus/tusd/cmd/tusd/cli.VersionName=${GIT_VERSION} -X github.com/tus/tusd/cmd/tusd/cli.GitCommit=${GIT_COMMIT} -X 'github.com/tus/tusd/cmd/tusd/cli.BuildDate=$(date --utc)'" \ -ldflags="-X github.com/tus/tusd/cmd/tusd/cli.VersionName=${GIT_VERSION} -X github.com/tus/tusd/cmd/tusd/cli.GitCommit=${GIT_COMMIT} -X 'github.com/tus/tusd/cmd/tusd/cli.BuildDate=$(date --utc)'" \
-o /go/bin/tusd ./cmd/tusd/main.go -o /go/bin/tusd ./cmd/tusd/main.go
# start a new stage that copies in the binary built in the previous stage # start a new stage that copies in the binary built in the previous stage
FROM alpine:3.18.0 FROM alpine:3.17.2
WORKDIR /srv/tusd-data WORKDIR /srv/tusd-data
COPY ./docker/entrypoint.sh /usr/local/share/docker-entrypoint.sh COPY ./docker/entrypoint.sh /usr/local/share/docker-entrypoint.sh

View File

@ -23,7 +23,6 @@ var Flags struct {
ShowGreeting bool ShowGreeting bool
DisableDownload bool DisableDownload bool
DisableTermination bool DisableTermination bool
DisableCors bool
Timeout int64 Timeout int64
S3Bucket string S3Bucket string
S3ObjectPrefix string S3ObjectPrefix string
@ -73,7 +72,6 @@ func ParseFlags() {
flag.BoolVar(&Flags.ShowGreeting, "show-greeting", true, "Show the greeting message") flag.BoolVar(&Flags.ShowGreeting, "show-greeting", true, "Show the greeting message")
flag.BoolVar(&Flags.DisableDownload, "disable-download", false, "Disable the download endpoint") flag.BoolVar(&Flags.DisableDownload, "disable-download", false, "Disable the download endpoint")
flag.BoolVar(&Flags.DisableTermination, "disable-termination", false, "Disable the termination endpoint") flag.BoolVar(&Flags.DisableTermination, "disable-termination", false, "Disable the termination endpoint")
flag.BoolVar(&Flags.DisableCors, "disable-cors", false, "Disable CORS headers")
flag.Int64Var(&Flags.Timeout, "timeout", 6*1000, "Read timeout for connections in milliseconds. A zero value means that reads will not timeout") flag.Int64Var(&Flags.Timeout, "timeout", 6*1000, "Read timeout for connections in milliseconds. A zero value means that reads will not timeout")
flag.StringVar(&Flags.S3Bucket, "s3-bucket", "", "Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set)") flag.StringVar(&Flags.S3Bucket, "s3-bucket", "", "Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set)")
flag.StringVar(&Flags.S3ObjectPrefix, "s3-object-prefix", "", "Prefix for S3 object names") flag.StringVar(&Flags.S3ObjectPrefix, "s3-object-prefix", "", "Prefix for S3 object names")
@ -108,6 +106,7 @@ func ParseFlags() {
flag.StringVar(&Flags.TLSCertFile, "tls-certificate", "", "Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.") flag.StringVar(&Flags.TLSCertFile, "tls-certificate", "", "Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.")
flag.StringVar(&Flags.TLSKeyFile, "tls-key", "", "Path to the file containing the key for the TLS certificate.") flag.StringVar(&Flags.TLSKeyFile, "tls-key", "", "Path to the file containing the key for the TLS certificate.")
flag.StringVar(&Flags.TLSMode, "tls-mode", "tls12", "Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong.") flag.StringVar(&Flags.TLSMode, "tls-mode", "tls12", "Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong.")
flag.StringVar(&Flags.CPUProfile, "cpuprofile", "", "write cpu profile to file") flag.StringVar(&Flags.CPUProfile, "cpuprofile", "", "write cpu profile to file")
flag.Parse() flag.Parse()

View File

@ -29,7 +29,6 @@ func Serve() {
RespectForwardedHeaders: Flags.BehindProxy, RespectForwardedHeaders: Flags.BehindProxy,
DisableDownload: Flags.DisableDownload, DisableDownload: Flags.DisableDownload,
DisableTermination: Flags.DisableTermination, DisableTermination: Flags.DisableTermination,
DisableCors: Flags.DisableCors,
StoreComposer: Composer, StoreComposer: Composer,
NotifyCompleteUploads: true, NotifyCompleteUploads: true,
NotifyTerminatedUploads: true, NotifyTerminatedUploads: true,

View File

@ -1,6 +1,6 @@
# Hooks # Hooks
When integrating tusd into an application, it is important to establish a communication channel between the two components. The tusd binary accomplishes this by providing a system which triggers actions when certain events happen, such as an upload being created or finished. This simple-but-powerful system enables use cases ranging from logging over validation and authorization to processing the uploaded files. When integrating tusd into an application, it is important to establish a communication channel between the two components. The tusd binary accomplishes this by providing a system which triggers actions when certain events happen, such as an upload being created or finished. This simple-but-powerful system enables uses ranging from logging over validation and authorization to processing the uploaded files.
When a specific action happens during an upload (pre-create, post-receive, post-finish, or post-terminate), the hook system enables tusd to fire off a specific event. Tusd provides two ways of doing this: When a specific action happens during an upload (pre-create, post-receive, post-finish, or post-terminate), the hook system enables tusd to fire off a specific event. Tusd provides two ways of doing this:

View File

@ -1,5 +1,17 @@
# Running tusd # Running tusd
Using tusd is as simple as invoked a single command. This guide walks you through the most important configuration options that are necessary for most applications. To see all options, simply inspect the output of `tusd --help`.
## General configuration
### Host and port
### Uploads
## Storage configuration
### Local disk
Starting the tusd upload server is as simple as invoking a single command. For example, following Starting the tusd upload server is as simple as invoking a single command. For example, following
snippet demonstrates how to start a tusd process which accepts tus uploads at snippet demonstrates how to start a tusd process which accepts tus uploads at
`http://localhost:1080/files/` (notice the trailing slash) and stores them locally in the `./data` directory: `http://localhost:1080/files/` (notice the trailing slash) and stores them locally in the `./data` directory:
@ -14,6 +26,7 @@ $ tusd -upload-dir=./data
[tusd] 2019/09/29 21:10:50 Supported tus extensions: creation,creation-with-upload,termination,concatenation,creation-defer-length [tusd] 2019/09/29 21:10:50 Supported tus extensions: creation,creation-with-upload,termination,concatenation,creation-defer-length
[tusd] 2019/09/29 21:10:50 You can now upload files to: http://0.0.0.0:1080/files/ [tusd] 2019/09/29 21:10:50 You can now upload files to: http://0.0.0.0:1080/files/
``` ```
### AWS S3
Alternatively, if you want to store the uploads on an AWS S3 bucket, you only have to specify Alternatively, if you want to store the uploads on an AWS S3 bucket, you only have to specify
the bucket and provide the corresponding access credentials and region information using the bucket and provide the corresponding access credentials and region information using
@ -55,6 +68,8 @@ $ tusd -s3-bucket=my-test-bucket.com -s3-transfer-acceleration
tusd is also able to read the credentials automatically from a shared credentials file (~/.aws/credentials) as described in https://github.com/aws/aws-sdk-go#configuring-credentials. tusd is also able to read the credentials automatically from a shared credentials file (~/.aws/credentials) as described in https://github.com/aws/aws-sdk-go#configuring-credentials.
But be mindful of the need to declare the AWS_REGION value which isn't conventionally associated with credentials. But be mindful of the need to declare the AWS_REGION value which isn't conventionally associated with credentials.
### Google Cloud Storage
Furthermore, tusd also has support for storing uploads on Google Cloud Storage. In order to enable this feature, supply the path to your account file containing the necessary credentials: Furthermore, tusd also has support for storing uploads on Google Cloud Storage. In order to enable this feature, supply the path to your account file containing the necessary credentials:
``` ```
@ -66,6 +81,7 @@ $ tusd -gcs-bucket=my-test-bucket.com
[tusd] Using /files/ as the base path. [tusd] Using /files/ as the base path.
[tusd] Using /metrics as the metrics path. [tusd] Using /metrics as the metrics path.
``` ```
### Azure Blob
Tusd also supports storing uploads on Microsoft Azure Blob Storage. In order to enable this feature, provide the Tusd also supports storing uploads on Microsoft Azure Blob Storage. In order to enable this feature, provide the
corresponding access credentials using environment variables. corresponding access credentials using environment variables.
@ -111,6 +127,10 @@ Using endpoint https://xxxxx.blob.core.windows.net
[tusd] Using /metrics as the metrics path. [tusd] Using /metrics as the metrics path.
``` ```
## Proxy configuration
## TLS configuration
TLS support for HTTPS connections can be enabled by supplying a certificate and private key. Note that the certificate file must include the entire chain of certificates up to the CA certificate. The default configuration supports TLSv1.2 and TLSv1.3. It is possible to use only TLSv1.3 with `-tls-mode=tls13`; alternately, it is possible to disable TLSv1.3 and use only 256-bit AES ciphersuites with `-tls-mode=tls12-strong`. The following example generates a self-signed certificate for `localhost` and then uses it to serve files on the loopback address; that this certificate is not appropriate for production use. Note also that the key file must not be encrypted/require a passphrase. TLS support for HTTPS connections can be enabled by supplying a certificate and private key. Note that the certificate file must include the entire chain of certificates up to the CA certificate. The default configuration supports TLSv1.2 and TLSv1.3. It is possible to use only TLSv1.3 with `-tls-mode=tls13`; alternately, it is possible to disable TLSv1.3 and use only 256-bit AES ciphersuites with `-tls-mode=tls12-strong`. The following example generates a self-signed certificate for `localhost` and then uses it to serve files on the loopback address; that this certificate is not appropriate for production use. Note also that the key file must not be encrypted/require a passphrase.
``` ```
@ -130,97 +150,4 @@ $ tusd -upload-dir=./data -host=127.0.0.1 -port=8443 -tls-certificate=localhost.
[tusd] You can now upload files to: https://127.0.0.1:8443/files/ [tusd] You can now upload files to: https://127.0.0.1:8443/files/
``` ```
## Hooks configuration
Besides these simple examples, tusd can be easily configured using a variety of command line
options:
```
$ tusd -help
-azure-blob-access-tier string
Blob access tier when uploading new files (possible values: archive, cool, hot, '')
-azure-container-access-type string
Access type when creating a new container if it does not exist (possible values: blob, container, '')
-azure-endpoint string
Custom Endpoint to use for Azure BlockBlob Storage (requires azure-storage to be pass)
-azure-object-prefix string
Prefix for Azure object names
-azure-storage string
Use Azure BlockBlob Storage with this container name as a storage backend (requires the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_KEY environment variable to be set)
-base-path string
Basepath of the HTTP server (default "/files/")
-behind-proxy
Respect X-Forwarded-* and similar headers which may be set by proxies
-cpuprofile string
write cpu profile to file
-expose-metrics
Expose metrics about tusd usage (default true)
-gcs-bucket string
Use Google Cloud Storage with this bucket as storage backend (requires the GCS_SERVICE_ACCOUNT_FILE environment variable to be set)
-gcs-object-prefix string
Prefix for GCS object names
-hooks-dir string
Directory to search for available hooks scripts
-hooks-enabled-events string
Comma separated list of enabled hook events (e.g. post-create,post-finish). Leave empty to enable default events (default "pre-create,post-create,post-receive,post-terminate,post-finish")
-hooks-grpc string
An gRPC endpoint to which hook events will be sent to
-hooks-grpc-backoff int
Number of seconds to wait before retrying each retry (default 1)
-hooks-grpc-retry int
Number of times to retry on a server error or network timeout (default 3)
-hooks-http string
An HTTP endpoint to which hook events will be sent to
-hooks-http-backoff int
Number of seconds to wait before retrying each retry (default 1)
-hooks-http-forward-headers string
List of HTTP request headers to be forwarded from the client request to the hook endpoint
-hooks-http-retry int
Number of times to retry on a 500 or network timeout (default 3)
-hooks-plugin string
Path to a Go plugin for loading hook functions (only supported on Linux and macOS; highly EXPERIMENTAL and may BREAK in the future)
-hooks-stop-code int
Return code from post-receive hook which causes tusd to stop and delete the current upload. A zero value means that no uploads will be stopped
-host string
Host to bind HTTP server to (default "0.0.0.0")
-max-size int
Maximum size of a single upload in bytes
-metrics-path string
Path under which the metrics endpoint will be accessible (default "/metrics")
-port string
Port to bind HTTP server to (default "1080")
-s3-bucket string
Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set)
-s3-disable-content-hashes
Disable the calculation of MD5 and SHA256 hashes for the content that gets uploaded to S3 for minimized CPU usage (experimental and may be removed in the future)
-s3-disable-ssl
Disable SSL and only use HTTP for communication with S3 (experimental and may be removed in the future)
-s3-endpoint string
Endpoint to use S3 compatible implementations like minio (requires s3-bucket to be pass)
-s3-object-prefix string
Prefix for S3 object names
-s3-part-size int
Size in bytes of the individual upload requests made to the S3 API. Defaults to 50MiB (experimental and may be removed in the future) (default 52428800)
-s3-transfer-acceleration
Use AWS S3 transfer acceleration endpoint (requires -s3-bucket option and Transfer Acceleration property on S3 bucket to be set)
-show-greeting
Show the greeting message (default true)
-timeout int
Read timeout for connections in milliseconds. A zero value means that reads will not timeout (default 6000)
-tls-certificate string
Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.
-tls-key string
Path to the file containing the key for the TLS certificate.
-tls-mode string
Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong. (default "tls12")
-unix-sock string
If set, will listen to a UNIX socket at this location instead of a TCP socket
-upload-dir string
Directory to store uploads in (default "./data")
-disable-cors
Disables CORS headers. If set to true, tusd will not send any CORS related header. This is useful if you have a proxy sitting in front of tusd that handles CORS (default false)
-verbose
Enable verbose logging output (default true)
-version
Print tusd version information
```

18
go.mod
View File

@ -6,19 +6,19 @@ module github.com/tus/tusd
go 1.16 go 1.16
require ( require (
cloud.google.com/go/storage v1.30.1 cloud.google.com/go/storage v1.29.0
github.com/Azure/azure-storage-blob-go v0.14.0 github.com/Azure/azure-storage-blob-go v0.14.0
github.com/aws/aws-sdk-go v1.44.275 github.com/aws/aws-sdk-go v1.44.201
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3 github.com/golang/protobuf v1.5.2
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/prometheus/client_golang v1.15.1 github.com/prometheus/client_golang v1.14.0
github.com/sethgrid/pester v1.2.0 github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.1
github.com/vimeo/go-util v1.4.1 github.com/vimeo/go-util v1.4.1
google.golang.org/api v0.125.0 google.golang.org/api v0.110.0
google.golang.org/grpc v1.55.0 google.golang.org/grpc v1.53.0
gopkg.in/Acconut/lockfile.v1 v1.1.0 gopkg.in/Acconut/lockfile.v1 v1.1.0
gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/h2non/gock.v1 v1.1.2
) )

507
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -28,9 +28,6 @@ type Config struct {
// DisableTermination indicates whether the server will refuse termination // DisableTermination indicates whether the server will refuse termination
// requests of the uploaded file, by not mounting the DELETE handler. // requests of the uploaded file, by not mounting the DELETE handler.
DisableTermination bool DisableTermination bool
// Disable cors headers. If set to true, tusd will not send any CORS related header.
// This is useful if you have a proxy sitting in front of tusd that handles CORS.
DisableCors bool
// NotifyCompleteUploads indicates whether sending notifications about // NotifyCompleteUploads indicates whether sending notifications about
// completed uploads using the CompleteUploads channel should be enabled. // completed uploads using the CompleteUploads channel should be enabled.
NotifyCompleteUploads bool NotifyCompleteUploads bool

View File

@ -96,20 +96,4 @@ func TestCORS(t *testing.T) {
t.Errorf("expected header to contain METHOD but got: %#v", methods) t.Errorf("expected header to contain METHOD but got: %#v", methods)
} }
}) })
SubTest(t, "Disable CORS", func(t *testing.T, store *MockFullDataStore, composer *StoreComposer) {
handler, _ := NewHandler(Config{
StoreComposer: composer,
DisableCors: true,
})
(&httpTest{
Method: "OPTIONS",
ReqHeader: map[string]string{
"Origin": "tus.io",
},
Code: http.StatusOK,
ResHeader: map[string]string{},
}).Run(handler, t)
})
} }

View File

@ -53,24 +53,6 @@ func NewHTTPError(err error, statusCode int) HTTPError {
return httpError{err, statusCode} return httpError{err, statusCode}
} }
type contextWithValues struct {
context.Context
valueHolder context.Context
}
func (c contextWithValues) Value(key interface{}) interface{} {
return c.valueHolder.Value(key)
}
func newContextWithValues(ctx context.Context) contextWithValues {
return contextWithValues{
// Use background to not get cancel event
Context: context.Background(),
// Use request context to get stored values
valueHolder: ctx,
}
}
var ( var (
ErrUnsupportedVersion = NewHTTPError(errors.New("unsupported version"), http.StatusPreconditionFailed) ErrUnsupportedVersion = NewHTTPError(errors.New("unsupported version"), http.StatusPreconditionFailed)
ErrMaxSizeExceeded = NewHTTPError(errors.New("maximum size exceeded"), http.StatusRequestEntityTooLarge) ErrMaxSizeExceeded = NewHTTPError(errors.New("maximum size exceeded"), http.StatusRequestEntityTooLarge)
@ -116,12 +98,6 @@ type HookEvent struct {
} }
func newHookEvent(info FileInfo, r *http.Request) HookEvent { func newHookEvent(info FileInfo, r *http.Request) HookEvent {
// The Host header field is not present in the header map, see https://pkg.go.dev/net/http#Request:
// > For incoming requests, the Host header is promoted to the
// > Request.Host field and removed from the Header map.
// That's why we add it back manually.
r.Header.Set("Host", r.Host)
return HookEvent{ return HookEvent{
Upload: info, Upload: info,
HTTPRequest: HTTPRequest{ HTTPRequest: HTTPRequest{
@ -241,7 +217,7 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler {
header := w.Header() header := w.Header()
if origin := r.Header.Get("Origin"); !handler.config.DisableCors && origin != "" { if origin := r.Header.Get("Origin"); origin != "" {
header.Set("Access-Control-Allow-Origin", origin) header.Set("Access-Control-Allow-Origin", origin)
if r.Method == "OPTIONS" { if r.Method == "OPTIONS" {
@ -308,7 +284,7 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler {
// PostFile creates a new file upload using the datastore after validating the // PostFile creates a new file upload using the datastore after validating the
// length and parsing the metadata. // length and parsing the metadata.
func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request) { func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request) {
ctx := newContextWithValues(r.Context()) ctx := context.Background()
// Check for presence of application/offset+octet-stream. If another content // Check for presence of application/offset+octet-stream. If another content
// type is defined, it will be ignored and treated as none was set because // type is defined, it will be ignored and treated as none was set because
@ -451,7 +427,7 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
// HeadFile returns the length and offset for the HEAD request // HeadFile returns the length and offset for the HEAD request
func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) { func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) {
ctx := newContextWithValues(r.Context()) ctx := context.Background()
id, err := extractIDFromPath(r.URL.Path) id, err := extractIDFromPath(r.URL.Path)
if err != nil { if err != nil {
@ -516,7 +492,7 @@ func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request)
// PatchFile adds a chunk to an upload. This operation is only allowed // PatchFile adds a chunk to an upload. This operation is only allowed
// if enough space in the upload is left. // if enough space in the upload is left.
func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request) { func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request) {
ctx := newContextWithValues(r.Context()) ctx := context.Background()
// Check for presence of application/offset+octet-stream // Check for presence of application/offset+octet-stream
if r.Header.Get("Content-Type") != "application/offset+octet-stream" { if r.Header.Get("Content-Type") != "application/offset+octet-stream" {
@ -745,7 +721,7 @@ func (handler *UnroutedHandler) finishUploadIfComplete(ctx context.Context, uplo
// GetFile handles requests to download a file using a GET request. This is not // GetFile handles requests to download a file using a GET request. This is not
// part of the specification. // part of the specification.
func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) { func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) {
ctx := newContextWithValues(r.Context()) ctx := context.Background()
id, err := extractIDFromPath(r.URL.Path) id, err := extractIDFromPath(r.URL.Path)
if err != nil { if err != nil {
@ -866,7 +842,7 @@ func filterContentType(info FileInfo) (contentType string, contentDisposition st
// DelFile terminates an upload permanently. // DelFile terminates an upload permanently.
func (handler *UnroutedHandler) DelFile(w http.ResponseWriter, r *http.Request) { func (handler *UnroutedHandler) DelFile(w http.ResponseWriter, r *http.Request) {
ctx := newContextWithValues(r.Context()) ctx := context.Background()
// Abort the request handling if the required interface is not implemented // Abort the request handling if the required interface is not implemented
if !handler.composer.UsesTerminater { if !handler.composer.UsesTerminater {