From 6df1f6fad1629191bca3403aaf7c2cc288334c33 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 23 Oct 2017 12:13:01 +0100 Subject: [PATCH] webdav: support put.io #580 * Add docs on how to set up * Fix the listing routine * Use Depth: 1 in otherwise we get a recursive listing * Detect collections properly rather than relying on them ending in / * Add / to collection URLs which don't have one --- docs/content/about.md | 1 + docs/content/webdav.md | 25 +++++++++++++++++++++++++ webdav/api/types.go | 10 +++++----- webdav/webdav.go | 24 +++++++++++++++++++++--- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/docs/content/about.md b/docs/content/about.md index 34e2c6f0e..4a4d97aa1 100644 --- a/docs/content/about.md +++ b/docs/content/about.md @@ -35,6 +35,7 @@ Rclone is a command line program to sync files and directories to and from: * {{< provider name="Oracle Cloud Storage" home="https://cloud.oracle.com/storage-opc" config="/swift/" >}} * {{< provider name="Ownloud" home="https://owncloud.org/" config="/webdav/#owncloud" >}} * {{< provider name="pCloud" home="https://www.pcloud.com/" config="/pcloud/" >}} +* {{< provider name="put.io" home="https://put.io/" config="/webdav/#put-io" >}} * {{< provider name="QingStor" home="https://www.qingcloud.com/products/storage" config="/qingstor/" >}} * {{< provider name="Rackspace Cloud Files" home="https://www.rackspace.com/cloud/files" config="/swift/" >}} * {{< provider name="SFTP" home="https://en.wikipedia.org/wiki/SFTP" config="/sftp/" >}} diff --git a/docs/content/webdav.md b/docs/content/webdav.md index 778a6db64..0c72e7ab6 100644 --- a/docs/content/webdav.md +++ b/docs/content/webdav.md @@ -146,3 +146,28 @@ Nextcloud does not support streaming of files (`rcat`) whereas Owncloud does. This [may be fixed](https://github.com/nextcloud/nextcloud-snap/issues/365) in the future. + +## Put.io ## + +put.io can be accessed in a read only way using webdav. + +Configure the `url` as `https://webdav.put.io` and use your normal +account username and password for `user` and `pass`. Set the `vendor` +to `other`. + +Your config file should end up looking like this: + +``` +[putio] +type = webdav +url = https://webdav.put.io +vendor = other +user = YourUserName +pass = encryptedpassword +``` + +If you are using `put.io` with `rclone mount` then use the +`--read-only` flag to signal to the OS that it can't write to the +mount. + +For more help see [the put.io webdav docs](http://help.put.io/apps-and-integrations/ftp-and-webdav). diff --git a/webdav/api/types.go b/webdav/api/types.go index 776b2e712..c856a3007 100644 --- a/webdav/api/types.go +++ b/webdav/api/types.go @@ -26,11 +26,11 @@ type Response struct { // Prop is the properties of a response type Prop struct { - Status string `xml:"DAV: status"` - Name string `xml:"DAV: prop>displayname,omitempty"` - Type xml.Name `xml:"DAV: prop>resourcetype>collection,omitempty"` - Size int64 `xml:"DAV: prop>getcontentlength,omitempty"` - Modified Time `xml:"DAV: prop>getlastmodified,omitempty"` + Status string `xml:"DAV: status"` + Name string `xml:"DAV: prop>displayname,omitempty"` + Type *xml.Name `xml:"DAV: prop>resourcetype>collection,omitempty"` + Size int64 `xml:"DAV: prop>getcontentlength,omitempty"` + Modified Time `xml:"DAV: prop>getlastmodified,omitempty"` } // Parse a status of the form "HTTP/1.1 200 OK", diff --git a/webdav/webdav.go b/webdav/webdav.go index 9372626f8..0466a54b6 100644 --- a/webdav/webdav.go +++ b/webdav/webdav.go @@ -360,6 +360,9 @@ func (f *Fs) listAll(dir string, directoriesOnly bool, filesOnly bool, fn listAl opts := rest.Opts{ Method: "PROPFIND", Path: f.dirPath(dir), // FIXME Should not start with / + ExtraHeaders: map[string]string{ + "Depth": "1", + }, } var result api.Multistatus var resp *http.Response @@ -384,8 +387,19 @@ func (f *Fs) listAll(dir string, directoriesOnly bool, filesOnly bool, fn listAl for i := range result.Responses { item := &result.Responses[i] - // Collections must end in / - isDir := strings.HasSuffix(item.Href, "/") + // Figure out what this is + isDir := false + if t := item.Props.Type; t != nil { + // When a client sees a resourcetype it + // doesn't recognize it should assume it is a + // regular non-collection resource. [WebDav + // book by Lisa Dusseault ch 7.5.8 p170] + if t.Space == "DAV:" && t.Local == "collection" { + isDir = true + } else { + fs.Debugf(nil, "Unknown resource type %q/%q on %q", t.Space, t.Local, item.Props.Name) + } + } // Find name u, err := rest.URLJoin(baseURL, item.Href) @@ -393,8 +407,12 @@ func (f *Fs) listAll(dir string, directoriesOnly bool, filesOnly bool, fn listAl fs.Errorf(nil, "URL Join failed for %q and %q: %v", baseURL, item.Href, err) continue } + // Make sure directories end with a / + if isDir { + u.Path = addSlash(u.Path) + } if !strings.HasPrefix(u.Path, baseURL.Path) { - fs.Debugf(nil, "Item with unknown path received: %q, %q", item.Href, u.Path) + fs.Debugf(nil, "Item with unknown path received: %q, %q", u.Path, baseURL.Path) continue } remote := path.Join(dir, u.Path[len(baseURL.Path):])