diff --git a/cmd/tusd/cli/hooks/grpc.go b/cmd/tusd/cli/hooks/grpc.go index a55a1b4..2e8eef4 100644 --- a/cmd/tusd/cli/hooks/grpc.go +++ b/cmd/tusd/cli/hooks/grpc.go @@ -18,7 +18,7 @@ type GrpcHook struct { Client pb.HookServiceClient } -func (g GrpcHook) Setup() error { +func (g *GrpcHook) Setup() error { opts := []grpc_retry.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffLinear(time.Duration(g.Backoff) * time.Second)), grpc_retry.WithMax(uint(g.MaxRetries)), @@ -35,9 +35,9 @@ func (g GrpcHook) Setup() error { return nil } -func (g GrpcHook) InvokeHook(typ HookType, info handler.HookEvent, captureOutput bool) ([]byte, int, error) { +func (g *GrpcHook) InvokeHook(typ HookType, info handler.HookEvent, captureOutput bool) ([]byte, int, error) { ctx := context.Background() - req := &pb.SendRequest{Hook: marshal(info)} + req := &pb.SendRequest{Hook: marshal(typ, info)} resp, err := g.Client.Send(ctx, req) if err != nil { if e, ok := status.FromError(err); ok { @@ -51,7 +51,7 @@ func (g GrpcHook) InvokeHook(typ HookType, info handler.HookEvent, captureOutput return nil, 0, err } -func marshal(info handler.HookEvent) *pb.Hook { +func marshal(typ HookType, info handler.HookEvent) *pb.Hook { return &pb.Hook{ Upload: &pb.Upload{ Id: info.Upload.ID, @@ -69,5 +69,6 @@ func marshal(info handler.HookEvent) *pb.Hook { Uri: info.HTTPRequest.URI, RemoteAddr: info.HTTPRequest.RemoteAddr, }, + Name: string(typ), } } diff --git a/cmd/tusd/cli/hooks/proto/v1/hook.proto b/cmd/tusd/cli/hooks/proto/v1/hook.proto index 633740a..f27ff19 100644 --- a/cmd/tusd/cli/hooks/proto/v1/hook.proto +++ b/cmd/tusd/cli/hooks/proto/v1/hook.proto @@ -47,6 +47,8 @@ message Hook { // HTTPRequest contains details about the HTTP request that reached // tusd. HTTPRequest httpRequest = 2; + // The hook name + string name = 3; } // Request data to send hook diff --git a/docs/faq.md b/docs/faq.md index cc9929e..f6e9baa 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -18,7 +18,7 @@ Explicit examples for the above points can be found in the [Nginx configuration] ### Can I run custom verification/authentication checks before an upload begins? -Yes, this is made possible by the [hook system](/docs/hooks.md) inside the tusd binary. It enables custom routines to be executed when certain events occurs, such as a new upload being created which can be handled by the `pre-create` hook. Inside the corresponding hook file, you can run your own validations against the provided upload metadata to determine whether the action is actually allowed or should be rejected by tusd. Please have a look at the [corresponding documentation](docs/hooks.md#pre-create) for a more detailed explanation. +Yes, this is made possible by the [hook system](/docs/hooks.md) inside the tusd binary. It enables custom routines to be executed when certain events occurs, such as a new upload being created which can be handled by the `pre-create` hook. Inside the corresponding hook file, you can run your own validations against the provided upload metadata to determine whether the action is actually allowed or should be rejected by tusd. Please have a look at the [corresponding documentation](/docs/hooks.md#pre-create) for a more detailed explanation. ### Can I run tusd inside a VM/Vagrant/VirtualBox? diff --git a/docs/hooks.md b/docs/hooks.md index dc45112..a6015ee 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -27,7 +27,7 @@ A successful HTTP response code (i.e. smaller than `400`) indicates that tusd sh ### pre-create -This event will be triggered before an upload is created, allowing you to run certain routines. For example, validating that specific metadata values are set, or verifying that a corresponding entity belonging to the upload (e.g. a user) exists. Because this event will result in a blocking hook, you can determine whether the upload should be created or rejected using the exit code. An exit code of `0` will allow the upload to be created and continued as usual. A non-zero exit code will reject an upload creation request, making it a good place for authentication and authorization. Please be aware, that during this stage the upload ID will be an empty string as the entity has not been created and therefore this piece of information is not yet available. +This event will be triggered before an upload is created, allowing you to run certain routines. For example, validating that specific metadata values are set, or verifying that a corresponding entity belonging to the upload (e.g. a user) exists. Because this event will result in a blocking hook, you can determine whether the upload should be created or rejected using the exit code. An exit code of `0` will allow the upload to be created and continued as usual. A non-zero exit code will reject an upload creation request, making it a good place for authentication and authorization. Please be aware that during this stage the upload ID will be an empty string and `Storage` will be null. This is because the entity has not been created and therefore this piece of information is not yet available. ### post-create @@ -114,8 +114,8 @@ The process of the hook files are provided with information about the event and "URI": "/files/14b1c4c77771671a8479bc0444bbc5ce", "RemoteAddr": "1.2.3.4:47689", "Header": { - "Host": "myuploads.net", - "Cookies": "..." + "Host": ["myuploads.net"], + "Cookies": ["..."] } } } @@ -187,8 +187,8 @@ Tusd will issue a `POST` request to the specified URL endpoint, specifying the h "URI": "/files/14b1c4c77771671a8479bc0444bbc5ce", "RemoteAddr": "1.2.3.4:47689", "Header": { - "Host": "myuploads.net", - "Cookies": "..." + "Host": ["myuploads.net"], + "Cookies": ["..."] } } } @@ -205,7 +205,7 @@ $ tusd --hooks-http http://localhost:8081/write --hooks-http-retry 5 --hooks-htt ## GRPC Hooks -GRPC Hooks are the third type of hooks supported by tusd. Like the others hooks, it is disabled by default. To enable it, pass the `--hooks-grpc option to the tusd binary. The flag's value will be a gRPC endpoint, which the tusd binary will be sent to: +GRPC Hooks are the third type of hooks supported by tusd. Like the others hooks, it is disabled by default. To enable it, pass the `--hooks-grpc` option to the tusd binary. The flag's value will be a gRPC endpoint, which the tusd binary will be sent to: ```bash $ tusd --hooks-grpc localhost:8080 @@ -262,7 +262,7 @@ Tusd will issue a `gRPC` request to the specified endpoint, specifying the hook "HTTPRequest": { "Method": "PATCH", "URI": "/files/14b1c4c77771671a8479bc0444bbc5ce", - "RemoteAddr": "1.2.3.4:47689", + "RemoteAddr": "1.2.3.4:47689" } } ``` diff --git a/docs/usage-binary.md b/docs/usage-binary.md index c8fd26d..54a854f 100644 --- a/docs/usage-binary.md +++ b/docs/usage-binary.md @@ -68,6 +68,12 @@ Usage of tusd: 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 all events + -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 @@ -93,7 +99,7 @@ Usage of tusd: -s3-object-prefix string Prefix for S3 object names -timeout int - Read timeout for connections in milliseconds. A zero value means that reads will not timeout (default 30000) + Read timeout for connections in milliseconds. A zero value means that reads will not timeout (default 6000) -unix-sock string If set, will listen to a UNIX socket at this location instead of a TCP socket -upload-dir string diff --git a/pkg/handler/cors_test.go b/pkg/handler/cors_test.go index 7d3928f..209b525 100644 --- a/pkg/handler/cors_test.go +++ b/pkg/handler/cors_test.go @@ -21,7 +21,7 @@ func TestCORS(t *testing.T) { }, Code: http.StatusOK, ResHeader: map[string]string{ - "Access-Control-Allow-Headers": "Origin, X-Requested-With, X-Request-ID, X-HTTP-Method-Override, Content-Type, Upload-Length, Upload-Offset, Tus-Resumable, Upload-Metadata, Upload-Defer-Length, Upload-Concat", + "Access-Control-Allow-Headers": "Authorization, Origin, X-Requested-With, X-Request-ID, X-HTTP-Method-Override, Content-Type, Upload-Length, Upload-Offset, Tus-Resumable, Upload-Metadata, Upload-Defer-Length, Upload-Concat", "Access-Control-Allow-Methods": "POST, GET, HEAD, PATCH, DELETE, OPTIONS", "Access-Control-Max-Age": "86400", "Access-Control-Allow-Origin": "tus.io", diff --git a/pkg/handler/unrouted_handler.go b/pkg/handler/unrouted_handler.go index 0817cde..e72e0bf 100644 --- a/pkg/handler/unrouted_handler.go +++ b/pkg/handler/unrouted_handler.go @@ -222,7 +222,7 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler { if r.Method == "OPTIONS" { // Preflight request header.Add("Access-Control-Allow-Methods", "POST, GET, HEAD, PATCH, DELETE, OPTIONS") - header.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-Request-ID, X-HTTP-Method-Override, Content-Type, Upload-Length, Upload-Offset, Tus-Resumable, Upload-Metadata, Upload-Defer-Length, Upload-Concat") + header.Add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, X-Request-ID, X-HTTP-Method-Override, Content-Type, Upload-Length, Upload-Offset, Tus-Resumable, Upload-Metadata, Upload-Defer-Length, Upload-Concat") header.Set("Access-Control-Max-Age", "86400") } else {