Skip to content

Commit

Permalink
Fix capabilities response for multiple client versions (#1331)
Browse files Browse the repository at this point in the history
  • Loading branch information
ishank011 authored Nov 27, 2020
1 parent 1c9d29e commit 3e50f7b
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 26 deletions.
3 changes: 3 additions & 0 deletions changelog/unreleased/ocs-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Bugfix: Fix capabilities response for multiple client versions

https://github.com/cs3org/reva/pull/1331
4 changes: 0 additions & 4 deletions internal/grpc/services/storageprovider/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}
}
Expand Down
15 changes: 10 additions & 5 deletions internal/http/services/owncloud/ocs/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -38,5 +39,9 @@ func (c *Config) Init() {
c.Prefix = "ocs"
}

if c.DefaultUploadProtocol == "" {
c.DefaultUploadProtocol = "tus"
}

c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -93,27 +97,12 @@ func (h *Handler) Init(c *config.Config) {
h.c.Capabilities.Files = &data.CapabilitiesFiles{}
}

// h.c.Capabilities.Files.PrivateLinks is boolean
// h.c.Capabilities.Files.BigFileChunking is boolean // TODO is this old or new chunking? jfd: I guess old

if h.c.Capabilities.Files.BlacklistedFiles == nil {
h.c.Capabilities.Files.BlacklistedFiles = []string{}
}
// 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
// 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: "",
}
}

// dav

if h.c.Capabilities.Dav == nil {
Expand Down Expand Up @@ -221,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)
})
}
Original file line number Diff line number Diff line change
@@ -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 = nil
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: "",
}
}
}

0 comments on commit 3e50f7b

Please sign in to comment.