From 1026132bb2642cb15b32be27773a576f3c8a63e4 Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Tue, 24 Nov 2020 16:42:37 +0530 Subject: [PATCH] Add user agent to protocol mapping --- .../storageprovider/storageprovider.go | 4 - .../services/owncloud/ocs/config/config.go | 15 ++-- .../cloud/capabilities/capabilities.go | 31 +++----- .../handlers/cloud/capabilities/uploads.go | 78 +++++++++++++++++++ 4 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 internal/http/services/owncloud/ocs/handlers/cloud/capabilities/uploads.go diff --git a/internal/grpc/services/storageprovider/storageprovider.go b/internal/grpc/services/storageprovider/storageprovider.go index c47803d37e5..33b28b8b1cf 100644 --- a/internal/grpc/services/storageprovider/storageprovider.go +++ b/internal/grpc/services/storageprovider/storageprovider.go @@ -33,7 +33,6 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/errtypes" - "github.com/cs3org/reva/pkg/logger" "github.com/cs3org/reva/pkg/mime" "github.com/cs3org/reva/pkg/rgrpc" "github.com/cs3org/reva/pkg/rgrpc/status" @@ -191,10 +190,7 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) { } func registerMimeTypes(mimes map[string]string) { - tlog := logger.New().With().Int("pid", os.Getpid()).Logger() - for k, v := range mimes { - tlog.Debug().Str("Registering mime type: ", "'"+fmt.Sprintf("%s -> %s", k, v)+"' ").Msg("") mime.RegisterMime(k, v) } } diff --git a/internal/http/services/owncloud/ocs/config/config.go b/internal/http/services/owncloud/ocs/config/config.go index 6bfb1be7461..1ac227358d7 100644 --- a/internal/http/services/owncloud/ocs/config/config.go +++ b/internal/http/services/owncloud/ocs/config/config.go @@ -25,11 +25,12 @@ import ( // Config holds the config options that need to be passed down to all ocs handlers type Config struct { - Prefix string `mapstructure:"prefix"` - Config data.ConfigData `mapstructure:"config"` - Capabilities data.CapabilitiesData `mapstructure:"capabilities"` - GatewaySvc string `mapstructure:"gatewaysvc"` - DisableTus bool `mapstructure:"disable_tus"` + Prefix string `mapstructure:"prefix"` + Config data.ConfigData `mapstructure:"config"` + Capabilities data.CapabilitiesData `mapstructure:"capabilities"` + GatewaySvc string `mapstructure:"gatewaysvc"` + DefaultUploadProtocol string `mapstructure:"default_upload_protocol"` + UserAgentChunkingMap map[string]string `mapstructure:"user_agent_chunking_map"` } // Init sets sane defaults @@ -38,5 +39,9 @@ func (c *Config) Init() { c.Prefix = "ocs" } + if c.DefaultUploadProtocol == "" { + c.DefaultUploadProtocol = "tus" + } + c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc) } diff --git a/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/capabilities.go b/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/capabilities.go index bf2c8b2d584..a71a311d151 100644 --- a/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/capabilities.go +++ b/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/capabilities.go @@ -28,12 +28,16 @@ import ( // Handler renders the capability endpoint type Handler struct { - c data.CapabilitiesData + c data.CapabilitiesData + defaultUploadProtocol string + userAgentChunkingMap map[string]string } // Init initializes this and any contained handlers func (h *Handler) Init(c *config.Config) { h.c = c.Capabilities + h.defaultUploadProtocol = c.DefaultUploadProtocol + h.userAgentChunkingMap = c.UserAgentChunkingMap // capabilities if h.c.Capabilities == nil { @@ -99,25 +103,6 @@ func (h *Handler) Init(c *config.Config) { // h.c.Capabilities.Files.Undelete is boolean // h.c.Capabilities.Files.Versioning is boolean - if h.c.Capabilities.Files.TusSupport == nil && !c.DisableTus { - // these are global capabilities - // Need to disable other chunking methods - h.c.Capabilities.Files.BigFileChunking = false - h.c.Capabilities.Dav.Chunking = "" - - // TODO: infer from various TUS handlers from all known storages - h.c.Capabilities.Files.TusSupport = &data.CapabilitiesFilesTusSupport{ - Version: "1.0.0", - Resumable: "1.0.0", - Extension: "creation,creation-with-upload", - MaxChunkSize: 0, - HTTPMethodOverride: "", - } - } else { - // Enable chunking support - h.c.Capabilities.Files.BigFileChunking = true - } - // dav if h.c.Capabilities.Dav == nil { @@ -225,11 +210,15 @@ func (h *Handler) Init(c *config.Config) { } } + // upload protocol-specific details + setCapabilitiesForChunkProtocol(chunkProtocol(h.defaultUploadProtocol), &h.c) + } // Handler renders the capabilities func (h *Handler) Handler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - response.WriteOCSSuccess(w, r, h.c) + c := h.getCapabilitiesForUserAgent(r.UserAgent()) + response.WriteOCSSuccess(w, r, c) }) } diff --git a/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/uploads.go b/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/uploads.go new file mode 100644 index 00000000000..324c0cbdd5b --- /dev/null +++ b/internal/http/services/owncloud/ocs/handlers/cloud/capabilities/uploads.go @@ -0,0 +1,78 @@ +// Copyright 2018-2020 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package capabilities + +import ( + "strings" + + "github.com/cs3org/reva/internal/http/services/owncloud/ocs/data" +) + +type chunkProtocol string + +var ( + chunkV1 chunkProtocol = "v1" + chunkNG chunkProtocol = "ng" + chunkTUS chunkProtocol = "tus" +) + +func (h *Handler) getCapabilitiesForUserAgent(userAgent string) data.CapabilitiesData { + if userAgent != "" { + for k, v := range h.userAgentChunkingMap { + // we could also use a regexp for pattern matching + if strings.Contains(userAgent, k) { + // Creating a copy of the capabilities struct is less expensive than taking a lock + c := h.c + setCapabilitiesForChunkProtocol(chunkProtocol(v), &c) + return c + } + } + } + return h.c +} + +func setCapabilitiesForChunkProtocol(cp chunkProtocol, c *data.CapabilitiesData) { + switch cp { + case chunkV1: + // 2.7+ will use Chunking V1 if "capabilities > files > bigfilechunking" is "true" AND "capabilities > dav > chunking" is not there + c.Capabilities.Files.BigFileChunking = true + c.Capabilities.Dav.Chunking = "" + c.Capabilities.Files.TusSupport = nil + + case chunkNG: + //2.7+ will use Chunking NG if "capabilities > files > bigfilechunking" is "true" AND "capabilities > dav > chunking" = 1.0 + c.Capabilities.Files.BigFileChunking = true + c.Capabilities.Dav.Chunking = "1.0" + c.Capabilities.Files.TusSupport = nil + + case chunkTUS: + // 2.7+ will use TUS if "capabilities > files > bigfilechunking" is "false" AND "capabilities > dav > chunking" = "" AND "capabilities > files > tus_support" has proper entries. + c.Capabilities.Files.BigFileChunking = false + c.Capabilities.Dav.Chunking = "" + + // TODO: infer from various TUS handlers from all known storages + c.Capabilities.Files.TusSupport = &data.CapabilitiesFilesTusSupport{ + Version: "1.0.0", + Resumable: "1.0.0", + Extension: "creation,creation-with-upload", + MaxChunkSize: 0, + HTTPMethodOverride: "", + } + } +}