mirror of
				https://gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud
				synced 2025-11-04 05:11:46 +00:00 
			
		
		
		
	Merge branch '6-add-webdav-api-client' into 'master'
fix #6: added gowebdav and webdav interface (TODO: webdav tests) Closes #6 See merge request partitio/Nextcloud-Partitio/gonextcloud!2
This commit is contained in:
		
							
								
								
									
										5
									
								
								auth.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								auth.go
									
									
									
									
									
								
							@@ -2,7 +2,10 @@ package gonextcloud
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req "github.com/levigross/grequests"
 | 
						req "github.com/levigross/grequests"
 | 
				
			||||||
 | 
						"github.com/studio-b12/gowebdav"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types"
 | 
						"gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,6 +36,8 @@ func (c *Client) Login(username string, password string) error {
 | 
				
			|||||||
		e := types.APIError{Message: "authentication failed"}
 | 
							e := types.APIError{Message: "authentication failed"}
 | 
				
			||||||
		return &e
 | 
							return &e
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// Create webdav client
 | 
				
			||||||
 | 
						c.webdav = gowebdav.NewClient(c.baseURL.String()+"/remote.php/webdav", c.username, c.password)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								client.go
									
									
									
									
									
								
							@@ -1,9 +1,12 @@
 | 
				
			|||||||
package gonextcloud
 | 
					package gonextcloud
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	req "github.com/levigross/grequests"
 | 
					 | 
				
			||||||
	"gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types"
 | 
					 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req "github.com/levigross/grequests"
 | 
				
			||||||
 | 
						"github.com/studio-b12/gowebdav"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Client is the API client that performs all operations against a Nextcloud server.
 | 
					// Client is the API client that performs all operations against a Nextcloud server.
 | 
				
			||||||
@@ -23,6 +26,7 @@ type Client struct {
 | 
				
			|||||||
	shares        *Shares
 | 
						shares        *Shares
 | 
				
			||||||
	users         *Users
 | 
						users         *Users
 | 
				
			||||||
	groups        *Groups
 | 
						groups        *Groups
 | 
				
			||||||
 | 
						webdav        *gowebdav.Client
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewClient create a new Client from the Nextcloud Instance URL
 | 
					// NewClient create a new Client from the Nextcloud Instance URL
 | 
				
			||||||
@@ -42,6 +46,7 @@ func NewClient(hostname string) (*Client, error) {
 | 
				
			|||||||
			"Accept":         "application/json",
 | 
								"Accept":         "application/json",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.apps = &Apps{c}
 | 
						c.apps = &Apps{c}
 | 
				
			||||||
	c.appsConfig = &AppsConfig{c}
 | 
						c.appsConfig = &AppsConfig{c}
 | 
				
			||||||
	c.groupFolders = &GroupFolders{c}
 | 
						c.groupFolders = &GroupFolders{c}
 | 
				
			||||||
@@ -49,6 +54,9 @@ func NewClient(hostname string) (*Client, error) {
 | 
				
			|||||||
	c.shares = &Shares{c}
 | 
						c.shares = &Shares{c}
 | 
				
			||||||
	c.users = &Users{c}
 | 
						c.users = &Users{c}
 | 
				
			||||||
	c.groups = &Groups{c}
 | 
						c.groups = &Groups{c}
 | 
				
			||||||
 | 
						// Create empty webdav client
 | 
				
			||||||
 | 
						// It will be replaced after login
 | 
				
			||||||
 | 
						c.webdav = &gowebdav.Client{}
 | 
				
			||||||
	return c, nil
 | 
						return c, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,3 +94,8 @@ func (c *Client) Users() types.Users {
 | 
				
			|||||||
func (c *Client) Groups() types.Groups {
 | 
					func (c *Client) Groups() types.Groups {
 | 
				
			||||||
	return c.groups
 | 
						return c.groups
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WebDav return the WebDav client Interface
 | 
				
			||||||
 | 
					func (c *Client) WebDav() types.WebDav {
 | 
				
			||||||
 | 
						return c.webdav
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@@ -9,6 +9,7 @@ require (
 | 
				
			|||||||
	github.com/pkg/errors v0.0.0-20181023235946-059132a15dd0
 | 
						github.com/pkg/errors v0.0.0-20181023235946-059132a15dd0
 | 
				
			||||||
	github.com/sirupsen/logrus v1.4.2
 | 
						github.com/sirupsen/logrus v1.4.2
 | 
				
			||||||
	github.com/stretchr/testify v1.2.2
 | 
						github.com/stretchr/testify v1.2.2
 | 
				
			||||||
 | 
						github.com/studio-b12/gowebdav v0.0.0-20190103184047-38f79aeaf1ac
 | 
				
			||||||
	golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 // indirect
 | 
						golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 // indirect
 | 
				
			||||||
	gopkg.in/yaml.v2 v2.2.1
 | 
						gopkg.in/yaml.v2 v2.2.1
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@@ -18,6 +18,8 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
 | 
				
			|||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
				
			||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 | 
					github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 | 
				
			||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
					github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
				
			||||||
 | 
					github.com/studio-b12/gowebdav v0.0.0-20190103184047-38f79aeaf1ac h1:xQ9gCVzqb939vjhxuES4IXYe4AlHB4Q71/K06aazQmQ=
 | 
				
			||||||
 | 
					github.com/studio-b12/gowebdav v0.0.0-20190103184047-38f79aeaf1ac/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s=
 | 
				
			||||||
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k=
 | 
					golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k=
 | 
				
			||||||
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
					golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
 | 
					golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ type Client interface {
 | 
				
			|||||||
	Shares() Shares
 | 
						Shares() Shares
 | 
				
			||||||
	Users() Users
 | 
						Users() Users
 | 
				
			||||||
	Groups() Groups
 | 
						Groups() Groups
 | 
				
			||||||
 | 
						WebDav() WebDav
 | 
				
			||||||
	Login(username string, password string) error
 | 
						Login(username string, password string) error
 | 
				
			||||||
	Logout() error
 | 
						Logout() error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								types/webdav.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								types/webdav.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WebDav available methods
 | 
				
			||||||
 | 
					type WebDav interface {
 | 
				
			||||||
 | 
						// ReadDir reads the contents of a remote directory
 | 
				
			||||||
 | 
						ReadDir(path string) ([]os.FileInfo, error)
 | 
				
			||||||
 | 
						// Stat returns the file stats for a specified path
 | 
				
			||||||
 | 
						Stat(path string) (os.FileInfo, error)
 | 
				
			||||||
 | 
						// Remove removes a remote file
 | 
				
			||||||
 | 
						Remove(path string) error
 | 
				
			||||||
 | 
						// RemoveAll removes remote files
 | 
				
			||||||
 | 
						RemoveAll(path string) error
 | 
				
			||||||
 | 
						// Mkdir makes a directory
 | 
				
			||||||
 | 
						Mkdir(path string, _ os.FileMode) error
 | 
				
			||||||
 | 
						// MkdirAll like mkdir -p, but for webdav
 | 
				
			||||||
 | 
						MkdirAll(path string, _ os.FileMode) error
 | 
				
			||||||
 | 
						// Rename moves a file from A to B
 | 
				
			||||||
 | 
						Rename(oldpath, newpath string, overwrite bool) error
 | 
				
			||||||
 | 
						// Copy copies a file from A to B
 | 
				
			||||||
 | 
						Copy(oldpath, newpath string, overwrite bool) error
 | 
				
			||||||
 | 
						// Read reads the contents of a remote file
 | 
				
			||||||
 | 
						Read(path string) ([]byte, error)
 | 
				
			||||||
 | 
						// ReadStream reads the stream for a given path
 | 
				
			||||||
 | 
						ReadStream(path string) (io.ReadCloser, error)
 | 
				
			||||||
 | 
						// Write writes data to a given path
 | 
				
			||||||
 | 
						Write(path string, data []byte, _ os.FileMode) error
 | 
				
			||||||
 | 
						// WriteStream writes a stream
 | 
				
			||||||
 | 
						WriteStream(path string, stream io.Reader, _ os.FileMode) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								vendor/github.com/studio-b12/gowebdav/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/studio-b12/gowebdav/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					# Folders to ignore
 | 
				
			||||||
 | 
					/src
 | 
				
			||||||
 | 
					/bin
 | 
				
			||||||
 | 
					/pkg
 | 
				
			||||||
 | 
					/gowebdav
 | 
				
			||||||
 | 
					/.idea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Binaries for programs and plugins
 | 
				
			||||||
 | 
					*.exe
 | 
				
			||||||
 | 
					*.exe~
 | 
				
			||||||
 | 
					*.dll
 | 
				
			||||||
 | 
					*.so
 | 
				
			||||||
 | 
					*.dylib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test binary, build with `go test -c`
 | 
				
			||||||
 | 
					*.test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Output of the go coverage tool, specifically when used with LiteIDE
 | 
				
			||||||
 | 
					*.out
 | 
				
			||||||
							
								
								
									
										10
									
								
								vendor/github.com/studio-b12/gowebdav/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/studio-b12/gowebdav/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					language: go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go:
 | 
				
			||||||
 | 
					  - "1.x"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install:
 | 
				
			||||||
 | 
					  - go get ./...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script:
 | 
				
			||||||
 | 
					  - go test -v --short ./...
 | 
				
			||||||
							
								
								
									
										27
									
								
								vendor/github.com/studio-b12/gowebdav/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/studio-b12/gowebdav/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					Copyright (c) 2014, Studio B12 GmbH
 | 
				
			||||||
 | 
					All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Redistributions of source code must retain the above copyright notice, this
 | 
				
			||||||
 | 
					   list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Redistributions in binary form must reproduce the above copyright notice,
 | 
				
			||||||
 | 
					   this list of conditions and the following disclaimer in the documentation
 | 
				
			||||||
 | 
					   and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Neither the name of the copyright holder nor the names of its contributors
 | 
				
			||||||
 | 
					   may be used to endorse or promote products derived from this software without
 | 
				
			||||||
 | 
					   specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
				
			||||||
 | 
					ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
				
			||||||
 | 
					OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
							
								
								
									
										33
									
								
								vendor/github.com/studio-b12/gowebdav/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/studio-b12/gowebdav/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					BIN := gowebdav
 | 
				
			||||||
 | 
					SRC := $(wildcard *.go) cmd/gowebdav/main.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: test cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cmd: ${BIN}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					${BIN}: ${SRC}
 | 
				
			||||||
 | 
						go build -o $@ ./cmd/gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test:
 | 
				
			||||||
 | 
						go test -v --short ./...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					api:
 | 
				
			||||||
 | 
						@sed '/^## API$$/,$$d' -i README.md
 | 
				
			||||||
 | 
						@echo '## API' >> README.md
 | 
				
			||||||
 | 
						@godoc2md github.com/studio-b12/gowebdav | sed '/^$$/N;/^\n$$/D' |\
 | 
				
			||||||
 | 
						sed '2d' |\
 | 
				
			||||||
 | 
						sed 's/\/src\/github.com\/studio-b12\/gowebdav\//https:\/\/github.com\/studio-b12\/gowebdav\/blob\/master\//g' |\
 | 
				
			||||||
 | 
						sed 's/\/src\/target\//https:\/\/github.com\/studio-b12\/gowebdav\/blob\/master\//g' |\
 | 
				
			||||||
 | 
						sed 's/^#/##/g' >> README.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check:
 | 
				
			||||||
 | 
						gofmt -w -s $(SRC)
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						gocyclo -over 15 .
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						golint ./...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						@rm -f ${BIN}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: all cmd clean test api check
 | 
				
			||||||
							
								
								
									
										147
									
								
								vendor/github.com/studio-b12/gowebdav/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								vendor/github.com/studio-b12/gowebdav/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					# GoWebDAV
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[](https://travis-ci.org/studio-b12/gowebdav)
 | 
				
			||||||
 | 
					[](https://godoc.org/github.com/studio-b12/gowebdav)
 | 
				
			||||||
 | 
					[](https://goreportcard.com/report/github.com/studio-b12/gowebdav)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A golang WebDAV client library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Main features
 | 
				
			||||||
 | 
					`gowebdav` library allows to perform following actions on the remote WebDAV server:
 | 
				
			||||||
 | 
					* [create path](#create-path-on-a-webdav-server)
 | 
				
			||||||
 | 
					* [get files list](#get-files-list)
 | 
				
			||||||
 | 
					* [download file](#download-file-to-byte-array)
 | 
				
			||||||
 | 
					* [upload file](#upload-file-from-byte-array)
 | 
				
			||||||
 | 
					* [get information about specified file/folder](#get-information-about-specified-filefolder)
 | 
				
			||||||
 | 
					* [move file to another location](#move-file-to-another-location)
 | 
				
			||||||
 | 
					* [copy file to another location](#copy-file-to-another-location)
 | 
				
			||||||
 | 
					* [delete file](#delete-file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First of all you should create `Client` instance using `NewClient()` function:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					root := "https://webdav.mydomain.me"
 | 
				
			||||||
 | 
					user := "user"
 | 
				
			||||||
 | 
					password := "password"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c := gowebdav.NewClient(root, user, password)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After you can use this `Client` to perform actions, described below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**NOTICE:** we will not check errors in examples, to focus you on the `gowebdav` library's code, but you should do it in your code!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Create path on a WebDAV server
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					err := c.Mkdir("folder", 0644)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					In case you want to create several folders you can use `c.MkdirAll()`:
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					err := c.MkdirAll("folder/subfolder/subfolder2", 0644)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Get files list
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					files, _ := c.ReadDir("folder/subfolder")
 | 
				
			||||||
 | 
					for _, file := range files {
 | 
				
			||||||
 | 
					    //notice that [file] has os.FileInfo type
 | 
				
			||||||
 | 
					    fmt.Println(file.Name())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Download file to byte array
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					localFilePath := "/tmp/webdav/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bytes, _ := c.Read(webdavFilePath)
 | 
				
			||||||
 | 
					ioutil.WriteFile(localFilePath, bytes, 0644)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Download file via reader
 | 
				
			||||||
 | 
					Also you can use `c.ReadStream()` method:
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					localFilePath := "/tmp/webdav/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reader, _ := c.ReadStream(webdavFilePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					file, _ := os.Create(localFilePath)
 | 
				
			||||||
 | 
					defer file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					io.Copy(file, reader)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Upload file from byte array
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					localFilePath := "/tmp/webdav/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bytes, _ := ioutil.ReadFile(localFilePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c.Write(webdavFilePath, bytes, 0644)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Upload file via writer
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					localFilePath := "/tmp/webdav/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					file, _ := os.Open(localFilePath)
 | 
				
			||||||
 | 
					defer file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c.WriteStream(webdavFilePath, file, 0644)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Get information about specified file/folder
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					info := c.Stat(webdavFilePath)
 | 
				
			||||||
 | 
					//notice that [info] has os.FileInfo type
 | 
				
			||||||
 | 
					fmt.Println(info)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Move file to another location
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					oldPath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					newPath := "folder/subfolder/moved.txt"
 | 
				
			||||||
 | 
					isOverwrite := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c.Rename(oldPath, newPath, isOverwrite)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Copy file to another location
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					oldPath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					newPath := "folder/subfolder/file-copy.txt"
 | 
				
			||||||
 | 
					isOverwrite := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c.Copy(oldPath, newPath, isOverwrite)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Delete file
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					webdavFilePath := "folder/subfolder/file.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					c.Remove(webdavFilePath)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Links
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More details about WebDAV server you can read from following resources:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [RFC 4918 - HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)](https://tools.ietf.org/html/rfc4918)
 | 
				
			||||||
 | 
					* [RFC 5689 - Extended MKCOL for Web Distributed Authoring and Versioning (WebDAV)](https://tools.ietf.org/html/rfc5689)
 | 
				
			||||||
 | 
					* [RFC 2616 - HTTP/1.1 Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html "HTTP/1.1 Status Code Definitions")
 | 
				
			||||||
 | 
					* [WebDav: Next Generation Collaborative Web Authoring By Lisa Dusseaul](https://books.google.de/books?isbn=0130652083 "WebDav: Next Generation Collaborative Web Authoring By Lisa Dusseault")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**NOTICE**: RFC 2518 is obsoleted by RFC 4918 in June 2007
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributing
 | 
				
			||||||
 | 
					All contributing are welcome. If you have any suggestions or find some bug - please create an Issue to let us make this project better. We appreciate your help!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## License
 | 
				
			||||||
 | 
					This library is distributed under the BSD 3-Clause license found in the [LICENSE](https://github.com/studio-b12/gowebdav/blob/master/LICENSE) file.
 | 
				
			||||||
							
								
								
									
										33
									
								
								vendor/github.com/studio-b12/gowebdav/basicAuth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/studio-b12/gowebdav/basicAuth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BasicAuth structure holds our credentials
 | 
				
			||||||
 | 
					type BasicAuth struct {
 | 
				
			||||||
 | 
						user string
 | 
				
			||||||
 | 
						pw   string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type identifies the BasicAuthenticator
 | 
				
			||||||
 | 
					func (b *BasicAuth) Type() string {
 | 
				
			||||||
 | 
						return "BasicAuth"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// User holds the BasicAuth username
 | 
				
			||||||
 | 
					func (b *BasicAuth) User() string {
 | 
				
			||||||
 | 
						return b.user
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pass holds the BasicAuth password
 | 
				
			||||||
 | 
					func (b *BasicAuth) Pass() string {
 | 
				
			||||||
 | 
						return b.pw
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Authorize the current request
 | 
				
			||||||
 | 
					func (b *BasicAuth) Authorize(c *Client, method string, path string) {
 | 
				
			||||||
 | 
						a := b.user + ":" + b.pw
 | 
				
			||||||
 | 
						auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(a))
 | 
				
			||||||
 | 
						c.headers.Set("Authorization", auth)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										380
									
								
								vendor/github.com/studio-b12/gowebdav/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								vendor/github.com/studio-b12/gowebdav/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,380 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/xml"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						pathpkg "path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Client defines our structure
 | 
				
			||||||
 | 
					type Client struct {
 | 
				
			||||||
 | 
						root    string
 | 
				
			||||||
 | 
						headers http.Header
 | 
				
			||||||
 | 
						c       *http.Client
 | 
				
			||||||
 | 
						auth    Authenticator
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Authenticator stub
 | 
				
			||||||
 | 
					type Authenticator interface {
 | 
				
			||||||
 | 
						Type() string
 | 
				
			||||||
 | 
						User() string
 | 
				
			||||||
 | 
						Pass() string
 | 
				
			||||||
 | 
						Authorize(*Client, string, string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NoAuth structure holds our credentials
 | 
				
			||||||
 | 
					type NoAuth struct {
 | 
				
			||||||
 | 
						user string
 | 
				
			||||||
 | 
						pw   string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type identifies the authenticator
 | 
				
			||||||
 | 
					func (n *NoAuth) Type() string {
 | 
				
			||||||
 | 
						return "NoAuth"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// User returns the current user
 | 
				
			||||||
 | 
					func (n *NoAuth) User() string {
 | 
				
			||||||
 | 
						return n.user
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pass returns the current password
 | 
				
			||||||
 | 
					func (n *NoAuth) Pass() string {
 | 
				
			||||||
 | 
						return n.pw
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Authorize the current request
 | 
				
			||||||
 | 
					func (n *NoAuth) Authorize(c *Client, method string, path string) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewClient creates a new instance of client
 | 
				
			||||||
 | 
					func NewClient(uri, user, pw string) *Client {
 | 
				
			||||||
 | 
						return &Client{FixSlash(uri), make(http.Header), &http.Client{}, &NoAuth{user, pw}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetHeader lets us set arbitrary headers for a given client
 | 
				
			||||||
 | 
					func (c *Client) SetHeader(key, value string) {
 | 
				
			||||||
 | 
						c.headers.Add(key, value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetTimeout exposes the ability to set a time limit for requests
 | 
				
			||||||
 | 
					func (c *Client) SetTimeout(timeout time.Duration) {
 | 
				
			||||||
 | 
						c.c.Timeout = timeout
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetTransport exposes the ability to define custom transports
 | 
				
			||||||
 | 
					func (c *Client) SetTransport(transport http.RoundTripper) {
 | 
				
			||||||
 | 
						c.c.Transport = transport
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Connect connects to our dav server
 | 
				
			||||||
 | 
					func (c *Client) Connect() error {
 | 
				
			||||||
 | 
						rs, err := c.options("/")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = rs.Body.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode != 200 {
 | 
				
			||||||
 | 
							return newPathError("Connect", c.root, rs.StatusCode)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type props struct {
 | 
				
			||||||
 | 
						Status      string   `xml:"DAV: status"`
 | 
				
			||||||
 | 
						Name        string   `xml:"DAV: prop>displayname,omitempty"`
 | 
				
			||||||
 | 
						Type        xml.Name `xml:"DAV: prop>resourcetype>collection,omitempty"`
 | 
				
			||||||
 | 
						Size        string   `xml:"DAV: prop>getcontentlength,omitempty"`
 | 
				
			||||||
 | 
						ContentType string   `xml:"DAV: prop>getcontenttype,omitempty"`
 | 
				
			||||||
 | 
						ETag        string   `xml:"DAV: prop>getetag,omitempty"`
 | 
				
			||||||
 | 
						Modified    string   `xml:"DAV: prop>getlastmodified,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type response struct {
 | 
				
			||||||
 | 
						Href  string  `xml:"DAV: href"`
 | 
				
			||||||
 | 
						Props []props `xml:"DAV: propstat"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getProps(r *response, status string) *props {
 | 
				
			||||||
 | 
						for _, prop := range r.Props {
 | 
				
			||||||
 | 
							if strings.Contains(prop.Status, status) {
 | 
				
			||||||
 | 
								return &prop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReadDir reads the contents of a remote directory
 | 
				
			||||||
 | 
					func (c *Client) ReadDir(path string) ([]os.FileInfo, error) {
 | 
				
			||||||
 | 
						path = FixSlashes(path)
 | 
				
			||||||
 | 
						files := make([]os.FileInfo, 0)
 | 
				
			||||||
 | 
						skipSelf := true
 | 
				
			||||||
 | 
						parse := func(resp interface{}) error {
 | 
				
			||||||
 | 
							r := resp.(*response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if skipSelf {
 | 
				
			||||||
 | 
								skipSelf = false
 | 
				
			||||||
 | 
								if p := getProps(r, "200"); p != nil && p.Type.Local == "collection" {
 | 
				
			||||||
 | 
									r.Props = nil
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return newPathError("ReadDir", path, 405)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if p := getProps(r, "200"); p != nil {
 | 
				
			||||||
 | 
								f := new(File)
 | 
				
			||||||
 | 
								if ps, err := url.QueryUnescape(r.Href); err == nil {
 | 
				
			||||||
 | 
									f.name = pathpkg.Base(ps)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									f.name = p.Name
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								f.path = path + f.name
 | 
				
			||||||
 | 
								f.modified = parseModified(&p.Modified)
 | 
				
			||||||
 | 
								f.etag = p.ETag
 | 
				
			||||||
 | 
								f.contentType = p.ContentType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if p.Type.Local == "collection" {
 | 
				
			||||||
 | 
									f.path += "/"
 | 
				
			||||||
 | 
									f.size = 0
 | 
				
			||||||
 | 
									f.isdir = true
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									f.size = parseInt64(&p.Size)
 | 
				
			||||||
 | 
									f.isdir = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								files = append(files, *f)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r.Props = nil
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := c.propfind(path, false,
 | 
				
			||||||
 | 
							`<d:propfind xmlns:d='DAV:'>
 | 
				
			||||||
 | 
								<d:prop>
 | 
				
			||||||
 | 
									<d:displayname/>
 | 
				
			||||||
 | 
									<d:resourcetype/>
 | 
				
			||||||
 | 
									<d:getcontentlength/>
 | 
				
			||||||
 | 
									<d:getcontenttype/>
 | 
				
			||||||
 | 
									<d:getetag/>
 | 
				
			||||||
 | 
									<d:getlastmodified/>
 | 
				
			||||||
 | 
								</d:prop>
 | 
				
			||||||
 | 
							</d:propfind>`,
 | 
				
			||||||
 | 
							&response{},
 | 
				
			||||||
 | 
							parse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if _, ok := err.(*os.PathError); !ok {
 | 
				
			||||||
 | 
								err = newPathErrorErr("ReadDir", path, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return files, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stat returns the file stats for a specified path
 | 
				
			||||||
 | 
					func (c *Client) Stat(path string) (os.FileInfo, error) {
 | 
				
			||||||
 | 
						var f *File
 | 
				
			||||||
 | 
						parse := func(resp interface{}) error {
 | 
				
			||||||
 | 
							r := resp.(*response)
 | 
				
			||||||
 | 
							if p := getProps(r, "200"); p != nil && f == nil {
 | 
				
			||||||
 | 
								f = new(File)
 | 
				
			||||||
 | 
								f.name = p.Name
 | 
				
			||||||
 | 
								f.path = path
 | 
				
			||||||
 | 
								f.etag = p.ETag
 | 
				
			||||||
 | 
								f.contentType = p.ContentType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if p.Type.Local == "collection" {
 | 
				
			||||||
 | 
									if !strings.HasSuffix(f.path, "/") {
 | 
				
			||||||
 | 
										f.path += "/"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									f.size = 0
 | 
				
			||||||
 | 
									f.modified = time.Unix(0, 0)
 | 
				
			||||||
 | 
									f.isdir = true
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									f.size = parseInt64(&p.Size)
 | 
				
			||||||
 | 
									f.modified = parseModified(&p.Modified)
 | 
				
			||||||
 | 
									f.isdir = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r.Props = nil
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := c.propfind(path, true,
 | 
				
			||||||
 | 
							`<d:propfind xmlns:d='DAV:'>
 | 
				
			||||||
 | 
								<d:prop>
 | 
				
			||||||
 | 
									<d:displayname/>
 | 
				
			||||||
 | 
									<d:resourcetype/>
 | 
				
			||||||
 | 
									<d:getcontentlength/>
 | 
				
			||||||
 | 
									<d:getcontenttype/>
 | 
				
			||||||
 | 
									<d:getetag/>
 | 
				
			||||||
 | 
									<d:getlastmodified/>
 | 
				
			||||||
 | 
								</d:prop>
 | 
				
			||||||
 | 
							</d:propfind>`,
 | 
				
			||||||
 | 
							&response{},
 | 
				
			||||||
 | 
							parse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if _, ok := err.(*os.PathError); !ok {
 | 
				
			||||||
 | 
								err = newPathErrorErr("ReadDir", path, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return f, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Remove removes a remote file
 | 
				
			||||||
 | 
					func (c *Client) Remove(path string) error {
 | 
				
			||||||
 | 
						return c.RemoveAll(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveAll removes remote files
 | 
				
			||||||
 | 
					func (c *Client) RemoveAll(path string) error {
 | 
				
			||||||
 | 
						rs, err := c.req("DELETE", path, nil, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return newPathError("Remove", path, 400)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = rs.Body.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode == 200 || rs.StatusCode == 204 || rs.StatusCode == 404 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newPathError("Remove", path, rs.StatusCode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mkdir makes a directory
 | 
				
			||||||
 | 
					func (c *Client) Mkdir(path string, _ os.FileMode) error {
 | 
				
			||||||
 | 
						path = FixSlashes(path)
 | 
				
			||||||
 | 
						status := c.mkcol(path)
 | 
				
			||||||
 | 
						if status == 201 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newPathError("Mkdir", path, status)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MkdirAll like mkdir -p, but for webdav
 | 
				
			||||||
 | 
					func (c *Client) MkdirAll(path string, _ os.FileMode) error {
 | 
				
			||||||
 | 
						path = FixSlashes(path)
 | 
				
			||||||
 | 
						status := c.mkcol(path)
 | 
				
			||||||
 | 
						if status == 201 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						} else if status == 409 {
 | 
				
			||||||
 | 
							paths := strings.Split(path, "/")
 | 
				
			||||||
 | 
							sub := "/"
 | 
				
			||||||
 | 
							for _, e := range paths {
 | 
				
			||||||
 | 
								if e == "" {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								sub += e + "/"
 | 
				
			||||||
 | 
								status = c.mkcol(sub)
 | 
				
			||||||
 | 
								if status != 201 {
 | 
				
			||||||
 | 
									return newPathError("MkdirAll", sub, status)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newPathError("MkdirAll", path, status)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Rename moves a file from A to B
 | 
				
			||||||
 | 
					func (c *Client) Rename(oldpath, newpath string, overwrite bool) error {
 | 
				
			||||||
 | 
						return c.copymove("MOVE", oldpath, newpath, overwrite)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copy copies a file from A to B
 | 
				
			||||||
 | 
					func (c *Client) Copy(oldpath, newpath string, overwrite bool) error {
 | 
				
			||||||
 | 
						return c.copymove("COPY", oldpath, newpath, overwrite)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Read reads the contents of a remote file
 | 
				
			||||||
 | 
					func (c *Client) Read(path string) ([]byte, error) {
 | 
				
			||||||
 | 
						var stream io.ReadCloser
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if stream, err = c.ReadStream(path); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer stream.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						_, err = buf.ReadFrom(stream)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return buf.Bytes(), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReadStream reads the stream for a given path
 | 
				
			||||||
 | 
					func (c *Client) ReadStream(path string) (io.ReadCloser, error) {
 | 
				
			||||||
 | 
						rs, err := c.req("GET", path, nil, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, newPathErrorErr("ReadStream", path, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode == 200 {
 | 
				
			||||||
 | 
							return rs.Body, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rs.Body.Close()
 | 
				
			||||||
 | 
						return nil, newPathError("ReadStream", path, rs.StatusCode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Write writes data to a given path
 | 
				
			||||||
 | 
					func (c *Client) Write(path string, data []byte, _ os.FileMode) error {
 | 
				
			||||||
 | 
						s := c.put(path, bytes.NewReader(data))
 | 
				
			||||||
 | 
						switch s {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 200, 201, 204:
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 409:
 | 
				
			||||||
 | 
							err := c.createParentCollection(path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							s = c.put(path, bytes.NewReader(data))
 | 
				
			||||||
 | 
							if s == 200 || s == 201 || s == 204 {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newPathError("Write", path, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WriteStream writes a stream
 | 
				
			||||||
 | 
					func (c *Client) WriteStream(path string, stream io.Reader, _ os.FileMode) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := c.createParentCollection(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						s := c.put(path, stream)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch s {
 | 
				
			||||||
 | 
						case 200, 201, 204:
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return newPathError("WriteStream", path, s)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										146
									
								
								vendor/github.com/studio-b12/gowebdav/digestAuth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								vendor/github.com/studio-b12/gowebdav/digestAuth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DigestAuth structure holds our credentials
 | 
				
			||||||
 | 
					type DigestAuth struct {
 | 
				
			||||||
 | 
						user        string
 | 
				
			||||||
 | 
						pw          string
 | 
				
			||||||
 | 
						digestParts map[string]string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type identifies the DigestAuthenticator
 | 
				
			||||||
 | 
					func (d *DigestAuth) Type() string {
 | 
				
			||||||
 | 
						return "DigestAuth"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// User holds the DigestAuth username
 | 
				
			||||||
 | 
					func (d *DigestAuth) User() string {
 | 
				
			||||||
 | 
						return d.user
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pass holds the DigestAuth password
 | 
				
			||||||
 | 
					func (d *DigestAuth) Pass() string {
 | 
				
			||||||
 | 
						return d.pw
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Authorize the current request
 | 
				
			||||||
 | 
					func (d *DigestAuth) Authorize(c *Client, method string, path string) {
 | 
				
			||||||
 | 
						d.digestParts["uri"] = path
 | 
				
			||||||
 | 
						d.digestParts["method"] = method
 | 
				
			||||||
 | 
						d.digestParts["username"] = d.user
 | 
				
			||||||
 | 
						d.digestParts["password"] = d.pw
 | 
				
			||||||
 | 
						c.headers.Set("Authorization", getDigestAuthorization(d.digestParts))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func digestParts(resp *http.Response) map[string]string {
 | 
				
			||||||
 | 
						result := map[string]string{}
 | 
				
			||||||
 | 
						if len(resp.Header["Www-Authenticate"]) > 0 {
 | 
				
			||||||
 | 
							wantedHeaders := []string{"nonce", "realm", "qop", "opaque", "algorithm", "entityBody"}
 | 
				
			||||||
 | 
							responseHeaders := strings.Split(resp.Header["Www-Authenticate"][0], ",")
 | 
				
			||||||
 | 
							for _, r := range responseHeaders {
 | 
				
			||||||
 | 
								for _, w := range wantedHeaders {
 | 
				
			||||||
 | 
									if strings.Contains(r, w) {
 | 
				
			||||||
 | 
										result[w] = strings.Trim(
 | 
				
			||||||
 | 
											strings.SplitN(r, `=`, 2)[1],
 | 
				
			||||||
 | 
											`"`,
 | 
				
			||||||
 | 
										)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getMD5(text string) string {
 | 
				
			||||||
 | 
						hasher := md5.New()
 | 
				
			||||||
 | 
						hasher.Write([]byte(text))
 | 
				
			||||||
 | 
						return hex.EncodeToString(hasher.Sum(nil))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getCnonce() string {
 | 
				
			||||||
 | 
						b := make([]byte, 8)
 | 
				
			||||||
 | 
						io.ReadFull(rand.Reader, b)
 | 
				
			||||||
 | 
						return fmt.Sprintf("%x", b)[:16]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getDigestAuthorization(digestParts map[string]string) string {
 | 
				
			||||||
 | 
						d := digestParts
 | 
				
			||||||
 | 
						// These are the correct ha1 and ha2 for qop=auth. We should probably check for other types of qop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							ha1        string
 | 
				
			||||||
 | 
							ha2        string
 | 
				
			||||||
 | 
							nonceCount = 00000001
 | 
				
			||||||
 | 
							cnonce     = getCnonce()
 | 
				
			||||||
 | 
							response   string
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 'ha1' value depends on value of "algorithm" field
 | 
				
			||||||
 | 
						switch d["algorithm"] {
 | 
				
			||||||
 | 
						case "MD5", "":
 | 
				
			||||||
 | 
							ha1 = getMD5(d["username"] + ":" + d["realm"] + ":" + d["password"])
 | 
				
			||||||
 | 
						case "MD5-sess":
 | 
				
			||||||
 | 
							ha1 = getMD5(
 | 
				
			||||||
 | 
								fmt.Sprintf("%s:%v:%s",
 | 
				
			||||||
 | 
									getMD5(d["username"]+":"+d["realm"]+":"+d["password"]),
 | 
				
			||||||
 | 
									nonceCount,
 | 
				
			||||||
 | 
									cnonce,
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 'ha2' value depends on value of "qop" field
 | 
				
			||||||
 | 
						switch d["qop"] {
 | 
				
			||||||
 | 
						case "auth", "":
 | 
				
			||||||
 | 
							ha2 = getMD5(d["method"] + ":" + d["uri"])
 | 
				
			||||||
 | 
						case "auth-int":
 | 
				
			||||||
 | 
							if d["entityBody"] != "" {
 | 
				
			||||||
 | 
								ha2 = getMD5(d["method"] + ":" + d["uri"] + ":" + getMD5(d["entityBody"]))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 'response' value depends on value of "qop" field
 | 
				
			||||||
 | 
						switch d["qop"] {
 | 
				
			||||||
 | 
						case "":
 | 
				
			||||||
 | 
							response = getMD5(
 | 
				
			||||||
 | 
								fmt.Sprintf("%s:%s:%s",
 | 
				
			||||||
 | 
									ha1,
 | 
				
			||||||
 | 
									d["nonce"],
 | 
				
			||||||
 | 
									ha2,
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						case "auth", "auth-int":
 | 
				
			||||||
 | 
							response = getMD5(
 | 
				
			||||||
 | 
								fmt.Sprintf("%s:%s:%v:%s:%s:%s",
 | 
				
			||||||
 | 
									ha1,
 | 
				
			||||||
 | 
									d["nonce"],
 | 
				
			||||||
 | 
									nonceCount,
 | 
				
			||||||
 | 
									cnonce,
 | 
				
			||||||
 | 
									d["qop"],
 | 
				
			||||||
 | 
									ha2,
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						authorization := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", nc=%v, cnonce="%s", response="%s"`,
 | 
				
			||||||
 | 
							d["username"], d["realm"], d["nonce"], d["uri"], nonceCount, cnonce, response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d["qop"] != "" {
 | 
				
			||||||
 | 
							authorization += fmt.Sprintf(`, qop=%s`, d["qop"])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d["opaque"] != "" {
 | 
				
			||||||
 | 
							authorization += fmt.Sprintf(`, opaque="%s"`, d["opaque"])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return authorization
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								vendor/github.com/studio-b12/gowebdav/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/studio-b12/gowebdav/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					// Package gowebdav is a WebDAV client library with a command line tool
 | 
				
			||||||
 | 
					// included.
 | 
				
			||||||
 | 
					package gowebdav
 | 
				
			||||||
							
								
								
									
										72
									
								
								vendor/github.com/studio-b12/gowebdav/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/studio-b12/gowebdav/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// File is our structure for a given file
 | 
				
			||||||
 | 
					type File struct {
 | 
				
			||||||
 | 
						path        string
 | 
				
			||||||
 | 
						name        string
 | 
				
			||||||
 | 
						contentType string
 | 
				
			||||||
 | 
						size        int64
 | 
				
			||||||
 | 
						modified    time.Time
 | 
				
			||||||
 | 
						etag        string
 | 
				
			||||||
 | 
						isdir       bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Name returns the name of a file
 | 
				
			||||||
 | 
					func (f File) Name() string {
 | 
				
			||||||
 | 
						return f.name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ContentType returns the content type of a file
 | 
				
			||||||
 | 
					func (f File) ContentType() string {
 | 
				
			||||||
 | 
						return f.contentType
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Size returns the size of a file
 | 
				
			||||||
 | 
					func (f File) Size() int64 {
 | 
				
			||||||
 | 
						return f.size
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mode will return the mode of a given file
 | 
				
			||||||
 | 
					func (f File) Mode() os.FileMode {
 | 
				
			||||||
 | 
						// TODO check webdav perms
 | 
				
			||||||
 | 
						if f.isdir {
 | 
				
			||||||
 | 
							return 0775 | os.ModeDir
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0664
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ModTime returns the modified time of a file
 | 
				
			||||||
 | 
					func (f File) ModTime() time.Time {
 | 
				
			||||||
 | 
						return f.modified
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ETag returns the ETag of a file
 | 
				
			||||||
 | 
					func (f File) ETag() string {
 | 
				
			||||||
 | 
						return f.etag
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsDir let us see if a given file is a directory or not
 | 
				
			||||||
 | 
					func (f File) IsDir() bool {
 | 
				
			||||||
 | 
						return f.isdir
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sys ????
 | 
				
			||||||
 | 
					func (f File) Sys() interface{} {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// String lets us see file information
 | 
				
			||||||
 | 
					func (f File) String() string {
 | 
				
			||||||
 | 
						if f.isdir {
 | 
				
			||||||
 | 
							return fmt.Sprintf("Dir : '%s' - '%s'", f.path, f.name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fmt.Sprintf("File: '%s' SIZE: %d MODIFIED: %s ETAG: %s CTYPE: %s", f.path, f.size, f.modified.String(), f.etag, f.contentType)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								vendor/github.com/studio-b12/gowebdav/netrc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/studio-b12/gowebdav/netrc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseLine(s string) (login, pass string) {
 | 
				
			||||||
 | 
						fields := strings.Fields(s)
 | 
				
			||||||
 | 
						for i, f := range fields {
 | 
				
			||||||
 | 
							if f == "login" {
 | 
				
			||||||
 | 
								login = fields[i+1]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if f == "password" {
 | 
				
			||||||
 | 
								pass = fields[i+1]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return login, pass
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReadConfig reads login and password configuration from ~/.netrc
 | 
				
			||||||
 | 
					// machine foo.com login username password 123456
 | 
				
			||||||
 | 
					func ReadConfig(uri, netrc string) (string, string) {
 | 
				
			||||||
 | 
						u, err := url.Parse(uri)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						file, err := os.Open(netrc)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						re := fmt.Sprintf(`^.*machine %s.*$`, u.Host)
 | 
				
			||||||
 | 
						scanner := bufio.NewScanner(file)
 | 
				
			||||||
 | 
						for scanner.Scan() {
 | 
				
			||||||
 | 
							s := scanner.Text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							matched, err := regexp.MatchString(re, s)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return "", ""
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if matched {
 | 
				
			||||||
 | 
								return parseLine(s)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return "", ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										164
									
								
								vendor/github.com/studio-b12/gowebdav/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								vendor/github.com/studio-b12/gowebdav/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) req(method, path string, body io.Reader, intercept func(*http.Request)) (req *http.Response, err error) {
 | 
				
			||||||
 | 
						// Tee the body, because if authorization fails we will need to read from it again.
 | 
				
			||||||
 | 
						var r *http.Request
 | 
				
			||||||
 | 
						var ba bytes.Buffer
 | 
				
			||||||
 | 
						bb := io.TeeReader(body, &ba)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if body == nil {
 | 
				
			||||||
 | 
							r, err = http.NewRequest(method, PathEscape(Join(c.root, path)), nil)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							r, err = http.NewRequest(method, PathEscape(Join(c.root, path)), bb)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.auth.Authorize(c, method, path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for k, vals := range c.headers {
 | 
				
			||||||
 | 
							for _, v := range vals {
 | 
				
			||||||
 | 
								r.Header.Add(k, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if intercept != nil {
 | 
				
			||||||
 | 
							intercept(r)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rs, err := c.c.Do(r)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode == 401 && c.auth.Type() == "NoAuth" {
 | 
				
			||||||
 | 
							if strings.Index(rs.Header.Get("Www-Authenticate"), "Digest") > -1 {
 | 
				
			||||||
 | 
								c.auth = &DigestAuth{c.auth.User(), c.auth.Pass(), digestParts(rs)}
 | 
				
			||||||
 | 
							} else if strings.Index(rs.Header.Get("Www-Authenticate"), "Basic") > -1 {
 | 
				
			||||||
 | 
								c.auth = &BasicAuth{c.auth.User(), c.auth.Pass()}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return rs, newPathError("Authorize", c.root, rs.StatusCode)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if body == nil {
 | 
				
			||||||
 | 
								return c.req(method, path, nil, intercept)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return c.req(method, path, &ba, intercept)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else if rs.StatusCode == 401 {
 | 
				
			||||||
 | 
							return rs, newPathError("Authorize", c.root, rs.StatusCode)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rs, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) mkcol(path string) int {
 | 
				
			||||||
 | 
						rs, err := c.req("MKCOL", path, nil, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 400
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer rs.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode == 201 || rs.StatusCode == 405 {
 | 
				
			||||||
 | 
							return 201
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rs.StatusCode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) options(path string) (*http.Response, error) {
 | 
				
			||||||
 | 
						return c.req("OPTIONS", path, nil, func(rq *http.Request) {
 | 
				
			||||||
 | 
							rq.Header.Add("Depth", "0")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) propfind(path string, self bool, body string, resp interface{}, parse func(resp interface{}) error) error {
 | 
				
			||||||
 | 
						rs, err := c.req("PROPFIND", path, strings.NewReader(body), func(rq *http.Request) {
 | 
				
			||||||
 | 
							if self {
 | 
				
			||||||
 | 
								rq.Header.Add("Depth", "0")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rq.Header.Add("Depth", "1")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rq.Header.Add("Content-Type", "application/xml;charset=UTF-8")
 | 
				
			||||||
 | 
							rq.Header.Add("Accept", "application/xml,text/xml")
 | 
				
			||||||
 | 
							rq.Header.Add("Accept-Charset", "utf-8")
 | 
				
			||||||
 | 
							// TODO add support for 'gzip,deflate;q=0.8,q=0.7'
 | 
				
			||||||
 | 
							rq.Header.Add("Accept-Encoding", "")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer rs.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rs.StatusCode != 207 {
 | 
				
			||||||
 | 
							return fmt.Errorf("%s - %s %s", rs.Status, "PROPFIND", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return parseXML(rs.Body, resp, parse)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) doCopyMove(method string, oldpath string, newpath string, overwrite bool) (int, io.ReadCloser) {
 | 
				
			||||||
 | 
						rs, err := c.req(method, oldpath, nil, func(rq *http.Request) {
 | 
				
			||||||
 | 
							rq.Header.Add("Destination", Join(c.root, newpath))
 | 
				
			||||||
 | 
							if overwrite {
 | 
				
			||||||
 | 
								rq.Header.Add("Overwrite", "T")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rq.Header.Add("Overwrite", "F")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 400, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rs.StatusCode, rs.Body
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) copymove(method string, oldpath string, newpath string, overwrite bool) error {
 | 
				
			||||||
 | 
						s, data := c.doCopyMove(method, oldpath, newpath, overwrite)
 | 
				
			||||||
 | 
						defer data.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch s {
 | 
				
			||||||
 | 
						case 201, 204:
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 207:
 | 
				
			||||||
 | 
							// TODO handle multistat errors, worst case ...
 | 
				
			||||||
 | 
							log(fmt.Sprintf(" TODO handle %s - %s multistatus result %s", method, oldpath, String(data)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 409:
 | 
				
			||||||
 | 
							err := c.createParentCollection(newpath)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return c.copymove(method, oldpath, newpath, overwrite)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newPathError(method, oldpath, s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) put(path string, stream io.Reader) int {
 | 
				
			||||||
 | 
						rs, err := c.req("PUT", path, stream, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 400
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer rs.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rs.StatusCode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Client) createParentCollection(itemPath string) (err error) {
 | 
				
			||||||
 | 
						parentPath := path.Dir(itemPath)
 | 
				
			||||||
 | 
						return c.MkdirAll(parentPath, 0755)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								vendor/github.com/studio-b12/gowebdav/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/studio-b12/gowebdav/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					package gowebdav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/xml"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func log(msg interface{}) {
 | 
				
			||||||
 | 
						fmt.Println(msg)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newPathError(op string, path string, statusCode int) error {
 | 
				
			||||||
 | 
						return &os.PathError{
 | 
				
			||||||
 | 
							Op:   op,
 | 
				
			||||||
 | 
							Path: path,
 | 
				
			||||||
 | 
							Err:  fmt.Errorf("%d", statusCode),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newPathErrorErr(op string, path string, err error) error {
 | 
				
			||||||
 | 
						return &os.PathError{
 | 
				
			||||||
 | 
							Op:   op,
 | 
				
			||||||
 | 
							Path: path,
 | 
				
			||||||
 | 
							Err:  err,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PathEscape escapes all segemnts of a given path
 | 
				
			||||||
 | 
					func PathEscape(path string) string {
 | 
				
			||||||
 | 
						s := strings.Split(path, "/")
 | 
				
			||||||
 | 
						for i, e := range s {
 | 
				
			||||||
 | 
							s[i] = url.PathEscape(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strings.Join(s, "/")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FixSlash appends a trailing / to our string
 | 
				
			||||||
 | 
					func FixSlash(s string) string {
 | 
				
			||||||
 | 
						if !strings.HasSuffix(s, "/") {
 | 
				
			||||||
 | 
							s += "/"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FixSlashes appends and prepends a / if they are missing
 | 
				
			||||||
 | 
					func FixSlashes(s string) string {
 | 
				
			||||||
 | 
						if s[0] != '/' {
 | 
				
			||||||
 | 
							s = "/" + s
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return FixSlash(s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Join joins two paths
 | 
				
			||||||
 | 
					func Join(path0 string, path1 string) string {
 | 
				
			||||||
 | 
						return strings.TrimSuffix(path0, "/") + "/" + strings.TrimPrefix(path1, "/")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// String pulls a string out of our io.Reader
 | 
				
			||||||
 | 
					func String(r io.Reader) string {
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						// TODO - make String return an error as well
 | 
				
			||||||
 | 
						_, _ = buf.ReadFrom(r)
 | 
				
			||||||
 | 
						return buf.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseUint(s *string) uint {
 | 
				
			||||||
 | 
						if n, e := strconv.ParseUint(*s, 10, 32); e == nil {
 | 
				
			||||||
 | 
							return uint(n)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseInt64(s *string) int64 {
 | 
				
			||||||
 | 
						if n, e := strconv.ParseInt(*s, 10, 64); e == nil {
 | 
				
			||||||
 | 
							return n
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseModified(s *string) time.Time {
 | 
				
			||||||
 | 
						if t, e := time.Parse(time.RFC1123, *s); e == nil {
 | 
				
			||||||
 | 
							return t
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return time.Unix(0, 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseXML(data io.Reader, resp interface{}, parse func(resp interface{}) error) error {
 | 
				
			||||||
 | 
						decoder := xml.NewDecoder(data)
 | 
				
			||||||
 | 
						for t, _ := decoder.Token(); t != nil; t, _ = decoder.Token() {
 | 
				
			||||||
 | 
							switch se := t.(type) {
 | 
				
			||||||
 | 
							case xml.StartElement:
 | 
				
			||||||
 | 
								if se.Name.Local == "response" {
 | 
				
			||||||
 | 
									if e := decoder.DecodeElement(resp, &se); e == nil {
 | 
				
			||||||
 | 
										if err := parse(resp); err != nil {
 | 
				
			||||||
 | 
											return err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -19,6 +19,8 @@ github.com/stretchr/objx
 | 
				
			|||||||
# github.com/stretchr/testify v1.2.2
 | 
					# github.com/stretchr/testify v1.2.2
 | 
				
			||||||
github.com/stretchr/testify/mock
 | 
					github.com/stretchr/testify/mock
 | 
				
			||||||
github.com/stretchr/testify/assert
 | 
					github.com/stretchr/testify/assert
 | 
				
			||||||
 | 
					# github.com/studio-b12/gowebdav v0.0.0-20190103184047-38f79aeaf1ac
 | 
				
			||||||
 | 
					github.com/studio-b12/gowebdav
 | 
				
			||||||
# golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76
 | 
					# golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76
 | 
				
			||||||
golang.org/x/net/publicsuffix
 | 
					golang.org/x/net/publicsuffix
 | 
				
			||||||
# golang.org/x/sys v0.0.0-20190422165155-953cdadca894
 | 
					# golang.org/x/sys v0.0.0-20190422165155-953cdadca894
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user