A pure Golang WebDAV client library that comes with a reference implementation.
Our gowebdav library allows to perform following actions on the remote WebDAV server:
- create path
- get files list
- download file
- upload file
- get information about specified file/folder
- move file to another location
- copy file to another location
- delete file
It also provides an authentication API that makes it easy to encapsulate and control complex authentication challenges. The default implementation negotiates the algorithm based on the user's preferences and the methods offered by the remote server.
Out-of-box authentication support for:
First of all you should create Client instance using NewClient() function:
root := "https://webdav.mydomain.me"
user := "user"
password := "password"
c := gowebdav.NewClient(root, user, password)
c.Connect()
// kick of your work!After you can use this Client to perform actions, described below.
NOTICE: We will not check for errors in the examples, to focus you on the gowebdav library's code, but you should do it in your code!
err := c.Mkdir("folder", 0644)In case you want to create several folders you can use c.MkdirAll():
err := c.MkdirAll("folder/subfolder/subfolder2", 0644)files, _ := c.ReadDir("folder/subfolder")
for _, file := range files {
//notice that [file] has os.FileInfo type
fmt.Println(file.Name())
}webdavFilePath := "folder/subfolder/file.txt"
localFilePath := "/tmp/webdav/file.txt"
bytes, _ := c.Read(webdavFilePath)
os.WriteFile(localFilePath, bytes, 0644)Also you can use c.ReadStream() method:
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)webdavFilePath := "folder/subfolder/file.txt"
localFilePath := "/tmp/webdav/file.txt"
bytes, _ := os.ReadFile(localFilePath)
c.Write(webdavFilePath, bytes, 0644)webdavFilePath := "folder/subfolder/file.txt"
localFilePath := "/tmp/webdav/file.txt"
file, _ := os.Open(localFilePath)
defer file.Close()
c.WriteStream(webdavFilePath, file, 0644)For non-seekable stream, this will read data into memory first to discover content length.
webdavFilePath := "folder/subfolder/file.txt"
bytes := []byte{0x20, 0x20}
c.WriteStreamWithLength(webdavFilePath, bytes.NewBuffer(bytes), int64(len(data)), 0644)webdavFilePath := "folder/subfolder/file.txt"
info := c.Stat(webdavFilePath)
//notice that [info] has os.FileInfo type
fmt.Println(info)oldPath := "folder/subfolder/file.txt"
newPath := "folder/subfolder/moved.txt"
isOverwrite := true
c.Rename(oldPath, newPath, isOverwrite)oldPath := "folder/subfolder/file.txt"
newPath := "folder/subfolder/file-copy.txt"
isOverwrite := true
c.Copy(oldPath, newPath, isOverwrite)webdavFilePath := "folder/subfolder/file.txt"
c.Remove(webdavFilePath)More details about WebDAV server you can read from following resources:
- RFC 4918 - HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)
- RFC 5689 - Extended MKCOL for Web Distributed Authoring and Versioning (WebDAV)
- RFC 2616 - HTTP/1.1 Status Code Definitions
- WebDav: Next Generation Collaborative Web Authoring By Lisa Dusseaul
NOTICE: RFC 2518 is obsoleted by RFC 4918 in June 2007
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!
This library is distributed under the BSD 3-Clause license found in the LICENSE file.
import "github.com/studio-b12/gowebdav"
Package gowebdav is a WebDAV client library with a command line tool included.
- Constants
- Variables
- func FixSlash(s string) string
- func FixSlashes(s string) string
- func IsErrCode(err error, code int) bool
- func IsErrNotFound(err error) bool
- func Join(path0 string, path1 string) string
- func NewPathError(op string, path string, statusCode int) error
- func NewPathErrorErr(op string, path string, err error) error
- func PathEscape(path string) string
- func ReadConfig(uri, netrc string) (string, string)
- func String(r io.Reader) string
- type AuthFactory
- type Authenticator
- type Authorizer
- type BasicAuth
- type Client
- func NewAuthClient(uri string, auth Authorizer) *Client
- func NewClient(uri, user, pw string) *Client
- func (c *Client) Connect() error
- func (c *Client) Copy(oldpath, newpath string, overwrite bool) error
- func (c *Client) Mkdir(path string, _ os.FileMode) (err error)
- func (c *Client) MkdirAll(path string, _ os.FileMode) (err error)
- func (c *Client) Read(path string) ([]byte, error)
- func (c *Client) ReadDir(path string) ([]os.FileInfo, error)
- func (c *Client) ReadStream(path string) (io.ReadCloser, error)
- func (c *Client) ReadStreamRange(path string, offset, length int64) (io.ReadCloser, error)
- func (c *Client) Remove(path string) error
- func (c *Client) RemoveAll(path string) error
- func (c *Client) Rename(oldpath, newpath string, overwrite bool) error
- func (c *Client) SetHeader(key, value string)
- func (c *Client) SetInterceptor(interceptor func(method string, rq *http.Request))
- func (c *Client) SetJar(jar http.CookieJar)
- func (c *Client) SetTimeout(timeout time.Duration)
- func (c *Client) SetTransport(transport http.RoundTripper)
- func (c *Client) Stat(path string) (os.FileInfo, error)
- func (c *Client) Write(path string, data []byte, _ os.FileMode) (err error)
- func (c *Client) WriteStream(path string, stream io.Reader, _ os.FileMode) (err error)
- func (c *Client) WriteStreamWithLength(path string, stream io.Reader, contentLength int64, _ os.FileMode) (err error)
- type DigestAuth
- type File
- func (f File) ContentType() string
- func (f File) ETag() string
- func (f File) IsDir() bool
- func (f File) ModTime() time.Time
- func (f File) Mode() os.FileMode
- func (f File) Name() string
- func (f File) Path() string
- func (f File) Size() int64
- func (f File) String() string
- func (f File) Sys() interface{}
- type PassportAuth
- func (p *PassportAuth) Authorize(c *http.Client, rq *http.Request, path string) error
- func (p *PassportAuth) Clone() Authenticator
- func (p *PassportAuth) Close() error
- func (p *PassportAuth) String() string
- func (p *PassportAuth) Verify(c *http.Client, rs *http.Response, path string) (redo bool, err error)
- type StatusError
auth.go basicAuth.go client.go digestAuth.go doc.go errors.go file.go netrc.go passportAuth.go requests.go utils.go
const XInhibitRedirect = "X-Gowebdav-Inhibit-Redirect"var ErrAuthChanged = errors.New("authentication failed, change algorithm")ErrAuthChanged must be returned from the Verify method as an error to trigger a re-authentication / negotiation with a new authenticator.
var ErrTooManyRedirects = errors.New("stopped after 10 redirects")ErrTooManyRedirects will be used as return error if a request exceeds 10 redirects.
func FixSlash(s string) stringFixSlash appends a trailing / to our string
func FixSlashes(s string) stringFixSlashes appends and prepends a / if they are missing
func IsErrCode(err error, code int) boolIsErrCode returns true if the given error is an os.PathError wrapping a StatusError with the given status code.
func IsErrNotFound(err error) boolIsErrNotFound is shorthand for IsErrCode for status 404.
func Join(path0 string, path1 string) stringJoin joins two paths
func NewPathError(op string, path string, statusCode int) errorfunc NewPathErrorErr(op string, path string, err error) errorfunc PathEscape(path string) stringPathEscape escapes all segments of a given path
func ReadConfig(uri, netrc string) (string, string)ReadConfig reads login and password configuration from ~/.netrc machine foo.com login username password 123456
func String(r io.Reader) stringString pulls a string out of our io.Reader
type AuthFactory func(c *http.Client, rs *http.Response, path string) (auth Authenticator, err error)AuthFactory prototype function to create a new Authenticator
type Authenticator interface {
// Authorizes a request. Usually by adding some authorization headers.
Authorize(c *http.Client, rq *http.Request, path string) error
// Verifies the response if the authorization was successful.
// May trigger some round trips to pass the authentication.
// May also trigger a new Authenticator negotiation by returning `ErrAuthChenged`
Verify(c *http.Client, rs *http.Response, path string) (redo bool, err error)
// Creates a copy of the underlying Authenticator.
Clone() Authenticator
io.Closer
}An Authenticator implements a specific way to authorize requests. Each request is bound to a separate Authenticator instance.
The authentication flow itself is broken down into Authorize
and Verify steps. The former method runs before, and the latter
runs after the Request is submitted.
This makes it easy to encapsulate and control complex
authentication challenges.
Some authentication flows causing authentication round trips,
which can be archived by returning the redo of the Verify
method. True restarts the authentication process for the
current action: A new Request is spawned, which must be
authorized, sent, and re-verified again, until the action
is successfully submitted.
The preferred way is to handle the authentication ping-pong
within Verify, and then redo with fresh credentials.
The result of the Verify method can also trigger an
Authenticator change by returning the ErrAuthChanged
as an error. Depending on the Authorizer this may trigger
an Authenticator negotiation.
Set the XInhibitRedirect header to '1' in the Authorize
method to get control over request redirection.
Attention! You must handle the incoming request yourself.
To store a shared session state the Clone method must
return a new instance, initialized with the shared state.
func NewDigestAuth(login, secret string, rs *http.Response) (Authenticator, error)NewDigestAuth creates a new instance of our Digest Authenticator
func NewPassportAuth(c *http.Client, user, pw, partnerURL string, header *http.Header) (Authenticator, error)constructor for PassportAuth creates a new PassportAuth object and automatically authenticates against the given partnerURL
type Authorizer interface {
// Creates a new Authenticator Shim per request.
// It may track request related states and perform payload buffering
// for authentication round trips.
// The underlying Authenticator will perform the real authentication.
NewAuthenticator(body io.Reader) (Authenticator, io.Reader)
// Registers a new Authenticator factory to a key.
AddAuthenticator(key string, fn AuthFactory)
}Authorizer our Authenticator factory which creates an
Authenticator per action/request.
func NewAutoAuth(login string, secret string) AuthorizerNewAutoAuth creates an auto Authenticator factory. It negotiates the default authentication method based on the order of the registered Authenticators and the remotely offered authentication methods. First In, First Out.
func NewEmptyAuth() AuthorizerNewEmptyAuth creates an empty Authenticator factory
The order of adding the Authenticator matters.
First In, First Out.
It offers the NewAutoAuth features.
func NewPreemptiveAuth(auth Authenticator) AuthorizerNewPreemptiveAuth creates a preemptive Authenticator
The preemptive authorizer uses the provided Authenticator
for every request regardless of any Www-Authenticate header.
It may only have one authentication method,
so calling AddAuthenticator will panic!
Look out!! This offers the skinniest and slickest implementation
without any synchronisation!!
Still applicable with BasicAuth within go routines.
type BasicAuth struct {
// contains filtered or unexported fields
}BasicAuth structure holds our credentials
func (b *BasicAuth) Authorize(c *http.Client, rq *http.Request, path string) errorAuthorize the current request
func (b *BasicAuth) Clone() AuthenticatorClone creates a Copy of itself
func (b *BasicAuth) Close() errorClose cleans up all resources
func (b *BasicAuth) String() stringString toString
func (b *BasicAuth) Verify(c *http.Client, rs *http.Response, path string) (redo bool, err error)Verify verifies if the authentication
type Client struct {
// contains filtered or unexported fields
}Client defines our structure
func NewAuthClient(uri string, auth Authorizer) *ClientNewAuthClient creates a new client instance with a custom Authorizer
func NewClient(uri, user, pw string) *ClientNewClient creates a new instance of client
func (c *Client) Connect() errorConnect connects to our dav server
func (c *Client) Copy(oldpath, newpath string, overwrite bool) errorCopy copies a file from A to B
func (c *Client) Mkdir(path string, _ os.FileMode) (err error)Mkdir makes a directory
func (c *Client) MkdirAll(path string, _ os.FileMode) (err error)MkdirAll like mkdir -p, but for webdav
func (c *Client) Read(path string) ([]byte, error)Read reads the contents of a remote file
func (c *Client) ReadDir(path string) ([]os.FileInfo, error)ReadDir reads the contents of a remote directory
func (*Client) ReadStream
func (c *Client) ReadStream(path string) (io.ReadCloser, error)ReadStream reads the stream for a given path
func (*Client) ReadStreamRange
func (c *Client) ReadStreamRange(path string, offset, length int64) (io.ReadCloser, error)ReadStreamRange reads the stream representing a subset of bytes for a given path, utilizing HTTP Range Requests if the server supports it. The range is expressed as offset from the start of the file and length, for example offset=10, length=10 will return bytes 10 through 19.
If the server does not support partial content requests and returns full content instead,
this function will emulate the behavior by skipping offset bytes and limiting the result
to length.
func (c *Client) Remove(path string) errorRemove removes a remote file
func (c *Client) RemoveAll(path string) errorRemoveAll removes remote files
func (c *Client) Rename(oldpath, newpath string, overwrite bool) errorRename moves a file from A to B
func (c *Client) SetHeader(key, value string)SetHeader lets us set arbitrary headers for a given client
func (*Client) SetInterceptor
func (c *Client) SetInterceptor(interceptor func(method string, rq *http.Request))SetInterceptor lets us set an arbitrary interceptor for a given client
func (c *Client) SetJar(jar http.CookieJar)SetJar exposes the ability to set a cookie jar to the client.
func (*Client) SetTimeout
func (c *Client) SetTimeout(timeout time.Duration)SetTimeout exposes the ability to set a time limit for requests
func (*Client) SetTransport
func (c *Client) SetTransport(transport http.RoundTripper)SetTransport exposes the ability to define custom transports
func (c *Client) Stat(path string) (os.FileInfo, error)Stat returns the file stats for a specified path
func (c *Client) Write(path string, data []byte, _ os.FileMode) (err error)Write writes data to a given path
func (*Client) WriteStream
func (c *Client) WriteStream(path string, stream io.Reader, _ os.FileMode) (err error)WriteStream writes a stream - it will copy to memory for non-seekable streams
func (*Client) WriteStreamWithLength
func (c *Client) WriteStreamWithLength(path string, stream io.Reader, contentLength int64, _ os.FileMode) (err error)WriteStream writes a stream with a known content length
type DigestAuth struct {
// contains filtered or unexported fields
}DigestAuth structure holds our credentials
func (d *DigestAuth) Authorize(c *http.Client, rq *http.Request, path string) errorAuthorize the current request
func (d *DigestAuth) Clone() AuthenticatorClone creates a copy of itself
func (d *DigestAuth) Close() errorClose cleans up all resources
func (d *DigestAuth) String() stringString toString
func (d *DigestAuth) Verify(c *http.Client, rs *http.Response, path string) (redo bool, err error)Verify checks for authentication issues and may trigger a re-authentication
type File struct {
// contains filtered or unexported fields
}File is our structure for a given file
func (File) ContentType
func (f File) ContentType() stringContentType returns the content type of a file
func (f File) ETag() stringETag returns the ETag of a file
func (f File) IsDir() boolIsDir let us see if a given file is a directory or not
func (f File) ModTime() time.TimeModTime returns the modified time of a file
func (f File) Mode() os.FileModeMode will return the mode of a given file
func (f File) Name() stringName returns the name of a file
func (f File) Path() stringPath returns the full path of a file
func (f File) Size() int64Size returns the size of a file
func (f File) String() stringString lets us see file information
func (f File) Sys() interface{}Sys ????
type PassportAuth struct {
// contains filtered or unexported fields
}PassportAuth structure holds our credentials
func (p *PassportAuth) Authorize(c *http.Client, rq *http.Request, path string) errorAuthorize the current request
func (p *PassportAuth) Clone() AuthenticatorClone creates a Copy of itself
func (p *PassportAuth) Close() errorClose cleans up all resources
func (p *PassportAuth) String() stringString toString
func (p *PassportAuth) Verify(c *http.Client, rs *http.Response, path string) (redo bool, err error)Verify verifies if the authentication is good
type StatusError struct {
Status int
}StatusError implements error and wraps an erroneous status code.
func (se StatusError) Error() stringGenerated by godoc2md