Protocol changes
The spaces concept allows clients to look up the space endpoints a user has access to and then do individual sync discoveries. Technically, we introduce an indirection that allows clients to rely on server provided URLs instead of hardcoded /webdav
or /dav/files/{username}
paths, that may change over time.
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant Client participant Graph participant SpaceA participant SpaceB links Client: {"web": "https://owncloud.dev/clients/web/", "RClone": "https://owncloud.dev/clients/rclone/"} link Graph: Documentation @ https://owncloud.dev/extensions/graph/ Note left of Client: First, a clients looks
up the spaces a user has access to opt space lookup Client->>+Graph: GET /me/drives Graph-->>-Client: 200 OK JSON list of spaces, say A, B and C,
each with a dedicated webDavURL, etag and quota end Note left of Client: Then it can do a parallel
sync discovery on spaces
whose etag changed par Client to Space A Client->>+SpaceA: PROPFIND {webDavURL for Space A} SpaceA-->>-Client: 207 Multistatus PROPFIND response and Client to Space B Client->>+SpaceB: PROPFIND {webDavURL for space B} SpaceB-->>-Client: 207 Multistatus PROPFIND response end
The ocDAV service is responsible for translating ownCloud flavoured WebDAV into CS3 API calls.
General view
A PROPFIND finds its way to a storage provider like this:
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant Client participant ocDAV participant StorageProvider Note right of Client: {spaceid} identifies the space
{relative/path} is relative to the space root Client->>+ocDAV: PROPFIND /dav/space/{spaceid}/{relative/path} Note right of ocDAV: translate ownCloud flavoured webdav
into CS3 API requests ocDAV->>+StorageProvider: ListContainer({spaceid}, path: {relative/path}) StorageProvider-->>-ocDAV: []ResourceInfo ocDAV-->>-Client: 207 Multistatus
While the above is a simplification to get an understanding of what needs to go where, there are several places where sharding can happen.
Proxy can do user based routing
The ocis proxy authenticates requests and can forward requests to different backends, depending on the logged-in user or cookies. For example multiple ocdav services can be configured to shard users based on username or affiliation.
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant Client participant proxy participant ocDAV1 as ocDAV [a-k] participant ocDAV2 as ocDAV [l-z] Note right of Client: {spaceid} identifies the space
{relative/path} is relative to the space root Client->>+proxy: PROPFIND /dav/space/{spaceid}/{relative/path} alt username starting with a-k proxy->>+ocDAV1: PROPFIND /dav/space/{spaceid}/{relative/path} Note right of ocDAV1: translate ownCloud flavoured webdav
into CS3 API requests ocDAV1-->>-Client: 207 Multistatus else username starting with l-z proxy->>+ocDAV2: PROPFIND /dav/space/{spaceid}/{relative/path} ocDAV2-->>-Client: 207 Multistatus end
Gateway can do path or storage provider id based routing
The reva gateway acts as a facade to multiple storage providers that can be configured with the storage registry:
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant ocDAV participant Gateway participant StorageRegistry participant StorageProvider1 as StorageProvider [a-k] participant StorageProvider2 as StorageProvider [l-z] Note right of ocDAV: translate ownCloud flavoured webdav
into CS3 API requests ocDAV->>+Gateway: ListContainer({spaceid}, path: {relative/path}) Note right of Gateway: find address of the storage provider
that is responsible for the space Gateway->>+StorageRegistry: ListStorageProviders({spaceid}) StorageRegistry-->>-Gateway: []ProviderInfo Note right of Gateway: forward request to
correct storage provider alt username starting with a-k Gateway->>+StorageProvider1: ListContainer({spaceid}, path: {relative/path}) StorageProvider1-->>-Gateway: []ResourceInfo else username starting with l-z Gateway->>+StorageProvider2: ListContainer({spaceid}, path: {relative/path}) StorageProvider2-->>-Gateway: []ResourceInfo end Gateway-->>-ocDAV: []ResourceInfo
PROPFIND request against old webdav endpoints
To route a PROPFIND request against the old webdav endpoints like /dav/files/username
, ocdav first has to build a CS3 namespace prefix, e.g. /users/{{.Id.OpaqueId}}
to the users home.
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant Client participant ocDAV participant Gateway opt old /dav/files/{username} endpoint with username and a path relative to the users home Note right of Client: translate ownCloud flavoured webdav
into CS3 API requests Client->>+ocDAV: PROPFIND /dav/files/{username}/{relative/path} Note right of ocDAV: translate ownCloud flavoured webdav
into CS3 API requests ocDAV->>+Gateway: GetUser({username}) Gateway-->>-ocDAV: User Note right of ocDAV: build path prefix to user home ocDAV->>+ocDAV: {namespace/prefix} = ApplyLayout({path layout}, User), eg. /users/e/einstein Note right of ocDAV: look up the space responsible for a path ocDAV->>+Gateway: ListStorageSpaces(path: {namespace/prefix}/{relative/path}) Gateway-->>-ocDAV: []StorageSpace Note right of ocDAV: make actual request with space and relative path ocDAV->>+Gateway: ListContainer({spaceid}, path: {relative/path}) Gateway-->>-ocDAV: []ResourceInfo ocDAV-->>-Client: 207 Multistatus end
Handling legacy global namespace webdav endpoints
The reason ocis uses a path based lookup instead of looking up the current users home using the user id and a space type filter is, because there are deployments that use a global namespace at the legacy /webdav
endpoint. To support these use cases, the gateway allows looking up spaces using their mount path.
%%{init: {"sequence": { "showSequenceNumbers":true, "messageFontFamily":"courier", "messageFontWeight":"normal", "messageFontSize":"11"}}}%% %% font weight is a css bug: https://github.com/mermaid-js/mermaid/issues/1976 %% edit this diagram by pasting it into eg. https://mermaid.live sequenceDiagram participant Client participant ocDAV participant Gateway Note right of Client: translate ownCloud flavoured webdav
into CS3 API requests alt old /dav/files/{username} endpoint with username and a path relative to the users home Client->>+ocDAV: PROPFIND /dav/files/{username}/{relative/path} Note right of ocDAV: look up {username} in URL path ocDAV->>+Gateway: GetUser({username}) Gateway-->>-ocDAV: User Note right of ocDAV:build namespace prefix to user home ocDAV->>+ocDAV: {namespace/prefix} = ApplyLayout({namespace layout}, User), eg. /users/e/einstein else legacy /webdav/ endpoint with a path relative to the users home Client->>+ocDAV: PROPFIND /webdav/{relative/path} Note right of ocDAV: use currently logged in user ocDAV->>+ocDAV: ContextGetUser() Note right of ocDAV: build namespace prefix to user home ocDAV->>+ocDAV: {namespace/prefix} = ApplyLayout({namespace layout}, User), eg. /users/e/einstein else legacy /webdav/ endpoint with a path relative to a global namespace Client->>+ocDAV: PROPFIND /webdav/{relative/path} Note right of ocDAV: omit namespace prefix by using empty layout template ocDAV->>+ocDAV: {namespace/prefix} = ApplyLayout("/", u), always returns "/" end Note right of ocDAV: look up the space responsible for a path ocDAV->>+Gateway: ListStorageSpaces(path: {namespace/prefix}/{relative/path}) Gateway-->>-ocDAV: []StorageSpace Note right of ocDAV: make actual request with space and relative path ocDAV->>+Gateway: ListContainer({spaceid}, path: {relative/path}) Gateway-->>-ocDAV: []ResourceInfo ocDAV-->>-Client: 207 Multistatus