mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 09:54:44 +01:00
Remove vendor directory #4032
This commit is contained in:
parent
ddfde68140
commit
2b50d44a2f
2
vendor/bazil.org/fuse/.gitattributes
generated
vendored
2
vendor/bazil.org/fuse/.gitattributes
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
*.go filter=gofmt
|
|
||||||
*.cgo filter=gofmt
|
|
11
vendor/bazil.org/fuse/.gitignore
generated
vendored
11
vendor/bazil.org/fuse/.gitignore
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
*~
|
|
||||||
.#*
|
|
||||||
## the next line needs to start with a backslash to avoid looking like
|
|
||||||
## a comment
|
|
||||||
\#*#
|
|
||||||
.*.swp
|
|
||||||
|
|
||||||
*.test
|
|
||||||
|
|
||||||
/clockfs
|
|
||||||
/hellofs
|
|
93
vendor/bazil.org/fuse/LICENSE
generated
vendored
93
vendor/bazil.org/fuse/LICENSE
generated
vendored
@ -1,93 +0,0 @@
|
|||||||
Copyright (c) 2013-2019 Tommi Virtanen.
|
|
||||||
Copyright (c) 2009, 2011, 2012 The Go Authors.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* 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.
|
|
||||||
* Neither the name of Google Inc. 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
|
|
||||||
OWNER 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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The following included software components have additional copyright
|
|
||||||
notices and license terms that may differ from the above.
|
|
||||||
|
|
||||||
|
|
||||||
File fuse.go:
|
|
||||||
|
|
||||||
// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
|
|
||||||
// which carries this notice:
|
|
||||||
//
|
|
||||||
// The files in this directory are subject to the following license.
|
|
||||||
//
|
|
||||||
// The author of this software is Russ Cox.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2006 Russ Cox
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose without fee is hereby granted, provided that this entire notice
|
|
||||||
// is included in all copies of any software which is or includes a copy
|
|
||||||
// or modification of this software and in all copies of the supporting
|
|
||||||
// documentation for such software.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
|
||||||
// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
|
|
||||||
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
|
|
||||||
// FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
|
|
||||||
File fuse_kernel.go:
|
|
||||||
|
|
||||||
// Derived from FUSE's fuse_kernel.h
|
|
||||||
/*
|
|
||||||
This file defines the kernel interface of FUSE
|
|
||||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
|
||||||
|
|
||||||
|
|
||||||
This -- and only this -- header file may also be distributed under
|
|
||||||
the terms of the BSD Licence as follows:
|
|
||||||
|
|
||||||
Copyright (C) 2001-2007 Miklos Szeredi. 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.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
|
|
||||||
*/
|
|
23
vendor/bazil.org/fuse/README.md
generated
vendored
23
vendor/bazil.org/fuse/README.md
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
bazil.org/fuse -- Filesystems in Go
|
|
||||||
===================================
|
|
||||||
|
|
||||||
`bazil.org/fuse` is a Go library for writing FUSE userspace
|
|
||||||
filesystems.
|
|
||||||
|
|
||||||
It is a from-scratch implementation of the kernel-userspace
|
|
||||||
communication protocol, and does not use the C library from the
|
|
||||||
project called FUSE. `bazil.org/fuse` embraces Go fully for safety and
|
|
||||||
ease of programming.
|
|
||||||
|
|
||||||
Here’s how to get going:
|
|
||||||
|
|
||||||
go get bazil.org/fuse
|
|
||||||
|
|
||||||
Website: http://bazil.org/fuse/
|
|
||||||
|
|
||||||
Github repository: https://github.com/bazil/fuse
|
|
||||||
|
|
||||||
API docs: http://godoc.org/bazil.org/fuse
|
|
||||||
|
|
||||||
Our thanks to Russ Cox for his fuse library, which this project is
|
|
||||||
based on.
|
|
35
vendor/bazil.org/fuse/buffer.go
generated
vendored
35
vendor/bazil.org/fuse/buffer.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
// buffer provides a mechanism for constructing a message from
|
|
||||||
// multiple segments.
|
|
||||||
type buffer []byte
|
|
||||||
|
|
||||||
// alloc allocates size bytes and returns a pointer to the new
|
|
||||||
// segment.
|
|
||||||
func (w *buffer) alloc(size uintptr) unsafe.Pointer {
|
|
||||||
s := int(size)
|
|
||||||
if len(*w)+s > cap(*w) {
|
|
||||||
old := *w
|
|
||||||
*w = make([]byte, len(*w), 2*cap(*w)+s)
|
|
||||||
copy(*w, old)
|
|
||||||
}
|
|
||||||
l := len(*w)
|
|
||||||
*w = (*w)[:l+s]
|
|
||||||
return unsafe.Pointer(&(*w)[l])
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset clears out the contents of the buffer.
|
|
||||||
func (w *buffer) reset() {
|
|
||||||
for i := range (*w)[:cap(*w)] {
|
|
||||||
(*w)[i] = 0
|
|
||||||
}
|
|
||||||
*w = (*w)[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBuffer(extra uintptr) buffer {
|
|
||||||
const hdrSize = unsafe.Sizeof(outHeader{})
|
|
||||||
buf := make(buffer, hdrSize, hdrSize+extra)
|
|
||||||
return buf
|
|
||||||
}
|
|
21
vendor/bazil.org/fuse/debug.go
generated
vendored
21
vendor/bazil.org/fuse/debug.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func stack() string {
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
return string(buf[:runtime.Stack(buf, false)])
|
|
||||||
}
|
|
||||||
|
|
||||||
func nop(msg interface{}) {}
|
|
||||||
|
|
||||||
// Debug is called to output debug messages, including protocol
|
|
||||||
// traces. The default behavior is to do nothing.
|
|
||||||
//
|
|
||||||
// The messages have human-friendly string representations and are
|
|
||||||
// safe to marshal to JSON.
|
|
||||||
//
|
|
||||||
// Implementations must not retain msg.
|
|
||||||
var Debug func(msg interface{}) = nop
|
|
17
vendor/bazil.org/fuse/error_darwin.go
generated
vendored
17
vendor/bazil.org/fuse/error_darwin.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ENOATTR = Errno(syscall.ENOATTR)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
errNoXattr = ENOATTR
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
errnoNames[errNoXattr] = "ENOATTR"
|
|
||||||
}
|
|
15
vendor/bazil.org/fuse/error_freebsd.go
generated
vendored
15
vendor/bazil.org/fuse/error_freebsd.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const (
|
|
||||||
ENOATTR = Errno(syscall.ENOATTR)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
errNoXattr = ENOATTR
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
errnoNames[errNoXattr] = "ENOATTR"
|
|
||||||
}
|
|
17
vendor/bazil.org/fuse/error_linux.go
generated
vendored
17
vendor/bazil.org/fuse/error_linux.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ENODATA = Errno(syscall.ENODATA)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
errNoXattr = ENODATA
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
errnoNames[errNoXattr] = "ENODATA"
|
|
||||||
}
|
|
31
vendor/bazil.org/fuse/error_std.go
generated
vendored
31
vendor/bazil.org/fuse/error_std.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
// There is very little commonality in extended attribute errors
|
|
||||||
// across platforms.
|
|
||||||
//
|
|
||||||
// getxattr return value for "extended attribute does not exist" is
|
|
||||||
// ENOATTR on OS X, and ENODATA on Linux and apparently at least
|
|
||||||
// NetBSD. There may be a #define ENOATTR on Linux too, but the value
|
|
||||||
// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no
|
|
||||||
// ENODATA, only ENOATTR. ENOATTR is not in any of the standards,
|
|
||||||
// ENODATA exists but is only used for STREAMs.
|
|
||||||
//
|
|
||||||
// Each platform will define it a errNoXattr constant, and this file
|
|
||||||
// will enforce that it implements the right interfaces and hide the
|
|
||||||
// implementation.
|
|
||||||
//
|
|
||||||
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html
|
|
||||||
// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html
|
|
||||||
// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html
|
|
||||||
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
|
||||||
// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2
|
|
||||||
// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html
|
|
||||||
|
|
||||||
// ErrNoXattr is a platform-independent error value meaning the
|
|
||||||
// extended attribute was not found. It can be used to respond to
|
|
||||||
// GetxattrRequest and such.
|
|
||||||
const ErrNoXattr = errNoXattr
|
|
||||||
|
|
||||||
var _ error = ErrNoXattr
|
|
||||||
var _ Errno = ErrNoXattr
|
|
||||||
var _ ErrorNumber = ErrNoXattr
|
|
1562
vendor/bazil.org/fuse/fs/serve.go
generated
vendored
1562
vendor/bazil.org/fuse/fs/serve.go
generated
vendored
File diff suppressed because it is too large
Load Diff
97
vendor/bazil.org/fuse/fs/tree.go
generated
vendored
97
vendor/bazil.org/fuse/fs/tree.go
generated
vendored
@ -1,97 +0,0 @@
|
|||||||
// FUSE directory tree, for servers that wish to use it with the service loop.
|
|
||||||
|
|
||||||
package fs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
pathpkg "path"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"bazil.org/fuse"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Tree implements a basic read-only directory tree for FUSE.
|
|
||||||
// The Nodes contained in it may still be writable.
|
|
||||||
type Tree struct {
|
|
||||||
tree
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) Root() (Node, error) {
|
|
||||||
return &t.tree, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds the path to the tree, resolving to the given node.
|
|
||||||
// If path or a prefix of path has already been added to the tree,
|
|
||||||
// Add panics.
|
|
||||||
//
|
|
||||||
// Add is only safe to call before starting to serve requests.
|
|
||||||
func (t *Tree) Add(path string, node Node) {
|
|
||||||
path = pathpkg.Clean("/" + path)[1:]
|
|
||||||
elems := strings.Split(path, "/")
|
|
||||||
dir := Node(&t.tree)
|
|
||||||
for i, elem := range elems {
|
|
||||||
dt, ok := dir.(*tree)
|
|
||||||
if !ok {
|
|
||||||
panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path)
|
|
||||||
}
|
|
||||||
n := dt.lookup(elem)
|
|
||||||
if n != nil {
|
|
||||||
if i+1 == len(elems) {
|
|
||||||
panic("fuse: Tree.Add for " + path + " conflicts with " + elem)
|
|
||||||
}
|
|
||||||
dir = n
|
|
||||||
} else {
|
|
||||||
if i+1 == len(elems) {
|
|
||||||
dt.add(elem, node)
|
|
||||||
} else {
|
|
||||||
dir = &tree{}
|
|
||||||
dt.add(elem, dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type treeDir struct {
|
|
||||||
name string
|
|
||||||
node Node
|
|
||||||
}
|
|
||||||
|
|
||||||
type tree struct {
|
|
||||||
dir []treeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tree) lookup(name string) Node {
|
|
||||||
for _, d := range t.dir {
|
|
||||||
if d.name == name {
|
|
||||||
return d.node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tree) add(name string, n Node) {
|
|
||||||
t.dir = append(t.dir, treeDir{name, n})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
|
|
||||||
a.Mode = os.ModeDir | 0555
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
|
|
||||||
n := t.lookup(name)
|
|
||||||
if n != nil {
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
return nil, syscall.ENOENT
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
|
||||||
var out []fuse.Dirent
|
|
||||||
for _, d := range t.dir {
|
|
||||||
out = append(out, fuse.Dirent{Name: d.name})
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
2338
vendor/bazil.org/fuse/fuse.go
generated
vendored
2338
vendor/bazil.org/fuse/fuse.go
generated
vendored
File diff suppressed because it is too large
Load Diff
9
vendor/bazil.org/fuse/fuse_darwin.go
generated
vendored
9
vendor/bazil.org/fuse/fuse_darwin.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
// Maximum file write size we are prepared to receive from the kernel.
|
|
||||||
//
|
|
||||||
// This value has to be >=16MB or OSXFUSE (3.4.0 observed) will
|
|
||||||
// forcibly close the /dev/fuse file descriptor on a Setxattr with a
|
|
||||||
// 16MB value. See TestSetxattr16MB and
|
|
||||||
// https://github.com/bazil/fuse/issues/42
|
|
||||||
const maxWrite = 16 * 1024 * 1024
|
|
6
vendor/bazil.org/fuse/fuse_freebsd.go
generated
vendored
6
vendor/bazil.org/fuse/fuse_freebsd.go
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
// Maximum file write size we are prepared to receive from the kernel.
|
|
||||||
//
|
|
||||||
// This number is just a guess.
|
|
||||||
const maxWrite = 128 * 1024
|
|
772
vendor/bazil.org/fuse/fuse_kernel.go
generated
vendored
772
vendor/bazil.org/fuse/fuse_kernel.go
generated
vendored
@ -1,772 +0,0 @@
|
|||||||
// See the file LICENSE for copyright and licensing information.
|
|
||||||
|
|
||||||
// Derived from FUSE's fuse_kernel.h, which carries this notice:
|
|
||||||
/*
|
|
||||||
This file defines the kernel interface of FUSE
|
|
||||||
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
|
||||||
|
|
||||||
|
|
||||||
This -- and only this -- header file may also be distributed under
|
|
||||||
the terms of the BSD Licence as follows:
|
|
||||||
|
|
||||||
Copyright (C) 2001-2007 Miklos Szeredi. 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.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The FUSE version implemented by the package.
|
|
||||||
const (
|
|
||||||
protoVersionMinMajor = 7
|
|
||||||
protoVersionMinMinor = 8
|
|
||||||
protoVersionMaxMajor = 7
|
|
||||||
protoVersionMaxMinor = 12
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
rootID = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
type kstatfs struct {
|
|
||||||
Blocks uint64
|
|
||||||
Bfree uint64
|
|
||||||
Bavail uint64
|
|
||||||
Files uint64
|
|
||||||
Ffree uint64
|
|
||||||
Bsize uint32
|
|
||||||
Namelen uint32
|
|
||||||
Frsize uint32
|
|
||||||
_ uint32
|
|
||||||
Spare [6]uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type fileLock struct {
|
|
||||||
Start uint64
|
|
||||||
End uint64
|
|
||||||
Type uint32
|
|
||||||
Pid uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetattrFlags are bit flags that can be seen in GetattrRequest.
|
|
||||||
type GetattrFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Indicates the handle is valid.
|
|
||||||
GetattrFh GetattrFlags = 1 << 0
|
|
||||||
)
|
|
||||||
|
|
||||||
var getattrFlagsNames = []flagName{
|
|
||||||
{uint32(GetattrFh), "GetattrFh"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl GetattrFlags) String() string {
|
|
||||||
return flagString(uint32(fl), getattrFlagsNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The SetattrValid are bit flags describing which fields in the SetattrRequest
|
|
||||||
// are included in the change.
|
|
||||||
type SetattrValid uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
SetattrMode SetattrValid = 1 << 0
|
|
||||||
SetattrUid SetattrValid = 1 << 1
|
|
||||||
SetattrGid SetattrValid = 1 << 2
|
|
||||||
SetattrSize SetattrValid = 1 << 3
|
|
||||||
SetattrAtime SetattrValid = 1 << 4
|
|
||||||
SetattrMtime SetattrValid = 1 << 5
|
|
||||||
SetattrHandle SetattrValid = 1 << 6
|
|
||||||
|
|
||||||
// Linux only(?)
|
|
||||||
SetattrAtimeNow SetattrValid = 1 << 7
|
|
||||||
SetattrMtimeNow SetattrValid = 1 << 8
|
|
||||||
SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
|
|
||||||
|
|
||||||
// OS X only
|
|
||||||
SetattrCrtime SetattrValid = 1 << 28
|
|
||||||
SetattrChgtime SetattrValid = 1 << 29
|
|
||||||
SetattrBkuptime SetattrValid = 1 << 30
|
|
||||||
SetattrFlags SetattrValid = 1 << 31
|
|
||||||
)
|
|
||||||
|
|
||||||
func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 }
|
|
||||||
func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 }
|
|
||||||
func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 }
|
|
||||||
func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 }
|
|
||||||
func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 }
|
|
||||||
func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 }
|
|
||||||
func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 }
|
|
||||||
func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 }
|
|
||||||
func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 }
|
|
||||||
func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 }
|
|
||||||
func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 }
|
|
||||||
func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 }
|
|
||||||
func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 }
|
|
||||||
func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 }
|
|
||||||
|
|
||||||
func (fl SetattrValid) String() string {
|
|
||||||
return flagString(uint32(fl), setattrValidNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
var setattrValidNames = []flagName{
|
|
||||||
{uint32(SetattrMode), "SetattrMode"},
|
|
||||||
{uint32(SetattrUid), "SetattrUid"},
|
|
||||||
{uint32(SetattrGid), "SetattrGid"},
|
|
||||||
{uint32(SetattrSize), "SetattrSize"},
|
|
||||||
{uint32(SetattrAtime), "SetattrAtime"},
|
|
||||||
{uint32(SetattrMtime), "SetattrMtime"},
|
|
||||||
{uint32(SetattrHandle), "SetattrHandle"},
|
|
||||||
{uint32(SetattrAtimeNow), "SetattrAtimeNow"},
|
|
||||||
{uint32(SetattrMtimeNow), "SetattrMtimeNow"},
|
|
||||||
{uint32(SetattrLockOwner), "SetattrLockOwner"},
|
|
||||||
{uint32(SetattrCrtime), "SetattrCrtime"},
|
|
||||||
{uint32(SetattrChgtime), "SetattrChgtime"},
|
|
||||||
{uint32(SetattrBkuptime), "SetattrBkuptime"},
|
|
||||||
{uint32(SetattrFlags), "SetattrFlags"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flags that can be seen in OpenRequest.Flags.
|
|
||||||
const (
|
|
||||||
// Access modes. These are not 1-bit flags, but alternatives where
|
|
||||||
// only one can be chosen. See the IsReadOnly etc convenience
|
|
||||||
// methods.
|
|
||||||
OpenReadOnly OpenFlags = syscall.O_RDONLY
|
|
||||||
OpenWriteOnly OpenFlags = syscall.O_WRONLY
|
|
||||||
OpenReadWrite OpenFlags = syscall.O_RDWR
|
|
||||||
|
|
||||||
// File was opened in append-only mode, all writes will go to end
|
|
||||||
// of file. OS X does not provide this information.
|
|
||||||
OpenAppend OpenFlags = syscall.O_APPEND
|
|
||||||
OpenCreate OpenFlags = syscall.O_CREAT
|
|
||||||
OpenDirectory OpenFlags = syscall.O_DIRECTORY
|
|
||||||
OpenExclusive OpenFlags = syscall.O_EXCL
|
|
||||||
OpenNonblock OpenFlags = syscall.O_NONBLOCK
|
|
||||||
OpenSync OpenFlags = syscall.O_SYNC
|
|
||||||
OpenTruncate OpenFlags = syscall.O_TRUNC
|
|
||||||
)
|
|
||||||
|
|
||||||
// OpenAccessModeMask is a bitmask that separates the access mode
|
|
||||||
// from the other flags in OpenFlags.
|
|
||||||
const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE
|
|
||||||
|
|
||||||
// OpenFlags are the O_FOO flags passed to open/create/etc calls. For
|
|
||||||
// example, os.O_WRONLY | os.O_APPEND.
|
|
||||||
type OpenFlags uint32
|
|
||||||
|
|
||||||
func (fl OpenFlags) String() string {
|
|
||||||
// O_RDONLY, O_RWONLY, O_RDWR are not flags
|
|
||||||
s := accModeName(fl & OpenAccessModeMask)
|
|
||||||
flags := uint32(fl &^ OpenAccessModeMask)
|
|
||||||
if flags != 0 {
|
|
||||||
s = s + "+" + flagString(flags, openFlagNames)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if OpenReadOnly is set.
|
|
||||||
func (fl OpenFlags) IsReadOnly() bool {
|
|
||||||
return fl&OpenAccessModeMask == OpenReadOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if OpenWriteOnly is set.
|
|
||||||
func (fl OpenFlags) IsWriteOnly() bool {
|
|
||||||
return fl&OpenAccessModeMask == OpenWriteOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if OpenReadWrite is set.
|
|
||||||
func (fl OpenFlags) IsReadWrite() bool {
|
|
||||||
return fl&OpenAccessModeMask == OpenReadWrite
|
|
||||||
}
|
|
||||||
|
|
||||||
func accModeName(flags OpenFlags) string {
|
|
||||||
switch flags {
|
|
||||||
case OpenReadOnly:
|
|
||||||
return "OpenReadOnly"
|
|
||||||
case OpenWriteOnly:
|
|
||||||
return "OpenWriteOnly"
|
|
||||||
case OpenReadWrite:
|
|
||||||
return "OpenReadWrite"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var openFlagNames = []flagName{
|
|
||||||
{uint32(OpenAppend), "OpenAppend"},
|
|
||||||
{uint32(OpenCreate), "OpenCreate"},
|
|
||||||
{uint32(OpenDirectory), "OpenDirectory"},
|
|
||||||
{uint32(OpenExclusive), "OpenExclusive"},
|
|
||||||
{uint32(OpenNonblock), "OpenNonblock"},
|
|
||||||
{uint32(OpenSync), "OpenSync"},
|
|
||||||
{uint32(OpenTruncate), "OpenTruncate"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// The OpenResponseFlags are returned in the OpenResponse.
|
|
||||||
type OpenResponseFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file
|
|
||||||
OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
|
|
||||||
OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X or FreeBSD)
|
|
||||||
|
|
||||||
OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
|
|
||||||
OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X
|
|
||||||
)
|
|
||||||
|
|
||||||
func (fl OpenResponseFlags) String() string {
|
|
||||||
return flagString(uint32(fl), openResponseFlagNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
var openResponseFlagNames = []flagName{
|
|
||||||
{uint32(OpenDirectIO), "OpenDirectIO"},
|
|
||||||
{uint32(OpenKeepCache), "OpenKeepCache"},
|
|
||||||
{uint32(OpenNonSeekable), "OpenNonSeekable"},
|
|
||||||
{uint32(OpenPurgeAttr), "OpenPurgeAttr"},
|
|
||||||
{uint32(OpenPurgeUBC), "OpenPurgeUBC"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// The InitFlags are used in the Init exchange.
|
|
||||||
type InitFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
InitAsyncRead InitFlags = 1 << 0
|
|
||||||
InitPosixLocks InitFlags = 1 << 1
|
|
||||||
InitFileOps InitFlags = 1 << 2
|
|
||||||
InitAtomicTrunc InitFlags = 1 << 3
|
|
||||||
InitExportSupport InitFlags = 1 << 4
|
|
||||||
InitBigWrites InitFlags = 1 << 5
|
|
||||||
// Do not mask file access modes with umask. Not supported on OS X.
|
|
||||||
InitDontMask InitFlags = 1 << 6
|
|
||||||
InitSpliceWrite InitFlags = 1 << 7
|
|
||||||
InitSpliceMove InitFlags = 1 << 8
|
|
||||||
InitSpliceRead InitFlags = 1 << 9
|
|
||||||
InitFlockLocks InitFlags = 1 << 10
|
|
||||||
InitHasIoctlDir InitFlags = 1 << 11
|
|
||||||
InitAutoInvalData InitFlags = 1 << 12
|
|
||||||
InitDoReaddirplus InitFlags = 1 << 13
|
|
||||||
InitReaddirplusAuto InitFlags = 1 << 14
|
|
||||||
InitAsyncDIO InitFlags = 1 << 15
|
|
||||||
InitWritebackCache InitFlags = 1 << 16
|
|
||||||
InitNoOpenSupport InitFlags = 1 << 17
|
|
||||||
|
|
||||||
InitCaseSensitive InitFlags = 1 << 29 // OS X only
|
|
||||||
InitVolRename InitFlags = 1 << 30 // OS X only
|
|
||||||
InitXtimes InitFlags = 1 << 31 // OS X only
|
|
||||||
)
|
|
||||||
|
|
||||||
type flagName struct {
|
|
||||||
bit uint32
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
var initFlagNames = []flagName{
|
|
||||||
{uint32(InitAsyncRead), "InitAsyncRead"},
|
|
||||||
{uint32(InitPosixLocks), "InitPosixLocks"},
|
|
||||||
{uint32(InitFileOps), "InitFileOps"},
|
|
||||||
{uint32(InitAtomicTrunc), "InitAtomicTrunc"},
|
|
||||||
{uint32(InitExportSupport), "InitExportSupport"},
|
|
||||||
{uint32(InitBigWrites), "InitBigWrites"},
|
|
||||||
{uint32(InitDontMask), "InitDontMask"},
|
|
||||||
{uint32(InitSpliceWrite), "InitSpliceWrite"},
|
|
||||||
{uint32(InitSpliceMove), "InitSpliceMove"},
|
|
||||||
{uint32(InitSpliceRead), "InitSpliceRead"},
|
|
||||||
{uint32(InitFlockLocks), "InitFlockLocks"},
|
|
||||||
{uint32(InitHasIoctlDir), "InitHasIoctlDir"},
|
|
||||||
{uint32(InitAutoInvalData), "InitAutoInvalData"},
|
|
||||||
{uint32(InitDoReaddirplus), "InitDoReaddirplus"},
|
|
||||||
{uint32(InitReaddirplusAuto), "InitReaddirplusAuto"},
|
|
||||||
{uint32(InitAsyncDIO), "InitAsyncDIO"},
|
|
||||||
{uint32(InitWritebackCache), "InitWritebackCache"},
|
|
||||||
{uint32(InitNoOpenSupport), "InitNoOpenSupport"},
|
|
||||||
|
|
||||||
{uint32(InitCaseSensitive), "InitCaseSensitive"},
|
|
||||||
{uint32(InitVolRename), "InitVolRename"},
|
|
||||||
{uint32(InitXtimes), "InitXtimes"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl InitFlags) String() string {
|
|
||||||
return flagString(uint32(fl), initFlagNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagString(f uint32, names []flagName) string {
|
|
||||||
var s string
|
|
||||||
|
|
||||||
if f == 0 {
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range names {
|
|
||||||
if f&n.bit != 0 {
|
|
||||||
s += "+" + n.name
|
|
||||||
f &^= n.bit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if f != 0 {
|
|
||||||
s += fmt.Sprintf("%+#x", f)
|
|
||||||
}
|
|
||||||
return s[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ReleaseFlags are used in the Release exchange.
|
|
||||||
type ReleaseFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ReleaseFlush ReleaseFlags = 1 << 0
|
|
||||||
)
|
|
||||||
|
|
||||||
func (fl ReleaseFlags) String() string {
|
|
||||||
return flagString(uint32(fl), releaseFlagNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
var releaseFlagNames = []flagName{
|
|
||||||
{uint32(ReleaseFlush), "ReleaseFlush"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opcodes
|
|
||||||
const (
|
|
||||||
opLookup = 1
|
|
||||||
opForget = 2 // no reply
|
|
||||||
opGetattr = 3
|
|
||||||
opSetattr = 4
|
|
||||||
opReadlink = 5
|
|
||||||
opSymlink = 6
|
|
||||||
opMknod = 8
|
|
||||||
opMkdir = 9
|
|
||||||
opUnlink = 10
|
|
||||||
opRmdir = 11
|
|
||||||
opRename = 12
|
|
||||||
opLink = 13
|
|
||||||
opOpen = 14
|
|
||||||
opRead = 15
|
|
||||||
opWrite = 16
|
|
||||||
opStatfs = 17
|
|
||||||
opRelease = 18
|
|
||||||
opFsync = 20
|
|
||||||
opSetxattr = 21
|
|
||||||
opGetxattr = 22
|
|
||||||
opListxattr = 23
|
|
||||||
opRemovexattr = 24
|
|
||||||
opFlush = 25
|
|
||||||
opInit = 26
|
|
||||||
opOpendir = 27
|
|
||||||
opReaddir = 28
|
|
||||||
opReleasedir = 29
|
|
||||||
opFsyncdir = 30
|
|
||||||
opGetlk = 31
|
|
||||||
opSetlk = 32
|
|
||||||
opSetlkw = 33
|
|
||||||
opAccess = 34
|
|
||||||
opCreate = 35
|
|
||||||
opInterrupt = 36
|
|
||||||
opBmap = 37
|
|
||||||
opDestroy = 38
|
|
||||||
opIoctl = 39 // Linux?
|
|
||||||
opPoll = 40 // Linux?
|
|
||||||
|
|
||||||
// OS X
|
|
||||||
opSetvolname = 61
|
|
||||||
opGetxtimes = 62
|
|
||||||
opExchange = 63
|
|
||||||
)
|
|
||||||
|
|
||||||
type entryOut struct {
|
|
||||||
Nodeid uint64 // Inode ID
|
|
||||||
Generation uint64 // Inode generation
|
|
||||||
EntryValid uint64 // Cache timeout for the name
|
|
||||||
AttrValid uint64 // Cache timeout for the attributes
|
|
||||||
EntryValidNsec uint32
|
|
||||||
AttrValidNsec uint32
|
|
||||||
Attr attr
|
|
||||||
}
|
|
||||||
|
|
||||||
func entryOutSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 9}):
|
|
||||||
return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(entryOut{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type forgetIn struct {
|
|
||||||
Nlookup uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type getattrIn struct {
|
|
||||||
GetattrFlags uint32
|
|
||||||
_ uint32
|
|
||||||
Fh uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type attrOut struct {
|
|
||||||
AttrValid uint64 // Cache timeout for the attributes
|
|
||||||
AttrValidNsec uint32
|
|
||||||
_ uint32
|
|
||||||
Attr attr
|
|
||||||
}
|
|
||||||
|
|
||||||
func attrOutSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 9}):
|
|
||||||
return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(attrOut{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OS X
|
|
||||||
type getxtimesOut struct {
|
|
||||||
Bkuptime uint64
|
|
||||||
Crtime uint64
|
|
||||||
BkuptimeNsec uint32
|
|
||||||
CrtimeNsec uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type mknodIn struct {
|
|
||||||
Mode uint32
|
|
||||||
Rdev uint32
|
|
||||||
Umask uint32
|
|
||||||
_ uint32
|
|
||||||
// "filename\x00" follows.
|
|
||||||
}
|
|
||||||
|
|
||||||
func mknodInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 12}):
|
|
||||||
return unsafe.Offsetof(mknodIn{}.Umask)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(mknodIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type mkdirIn struct {
|
|
||||||
Mode uint32
|
|
||||||
Umask uint32
|
|
||||||
// filename follows
|
|
||||||
}
|
|
||||||
|
|
||||||
func mkdirInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 12}):
|
|
||||||
return unsafe.Offsetof(mkdirIn{}.Umask) + 4
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(mkdirIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type renameIn struct {
|
|
||||||
Newdir uint64
|
|
||||||
// "oldname\x00newname\x00" follows
|
|
||||||
}
|
|
||||||
|
|
||||||
// OS X
|
|
||||||
type exchangeIn struct {
|
|
||||||
Olddir uint64
|
|
||||||
Newdir uint64
|
|
||||||
Options uint64
|
|
||||||
// "oldname\x00newname\x00" follows
|
|
||||||
}
|
|
||||||
|
|
||||||
type linkIn struct {
|
|
||||||
Oldnodeid uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type setattrInCommon struct {
|
|
||||||
Valid uint32
|
|
||||||
_ uint32
|
|
||||||
Fh uint64
|
|
||||||
Size uint64
|
|
||||||
LockOwner uint64 // unused on OS X?
|
|
||||||
Atime uint64
|
|
||||||
Mtime uint64
|
|
||||||
Unused2 uint64
|
|
||||||
AtimeNsec uint32
|
|
||||||
MtimeNsec uint32
|
|
||||||
Unused3 uint32
|
|
||||||
Mode uint32
|
|
||||||
Unused4 uint32
|
|
||||||
Uid uint32
|
|
||||||
Gid uint32
|
|
||||||
Unused5 uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type openIn struct {
|
|
||||||
Flags uint32
|
|
||||||
Unused uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type openOut struct {
|
|
||||||
Fh uint64
|
|
||||||
OpenFlags uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type createIn struct {
|
|
||||||
Flags uint32
|
|
||||||
Mode uint32
|
|
||||||
Umask uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func createInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 12}):
|
|
||||||
return unsafe.Offsetof(createIn{}.Umask)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(createIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type releaseIn struct {
|
|
||||||
Fh uint64
|
|
||||||
Flags uint32
|
|
||||||
ReleaseFlags uint32
|
|
||||||
LockOwner uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type flushIn struct {
|
|
||||||
Fh uint64
|
|
||||||
FlushFlags uint32
|
|
||||||
_ uint32
|
|
||||||
LockOwner uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type readIn struct {
|
|
||||||
Fh uint64
|
|
||||||
Offset uint64
|
|
||||||
Size uint32
|
|
||||||
ReadFlags uint32
|
|
||||||
LockOwner uint64
|
|
||||||
Flags uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func readInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 9}):
|
|
||||||
return unsafe.Offsetof(readIn{}.ReadFlags) + 4
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(readIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ReadFlags are passed in ReadRequest.
|
|
||||||
type ReadFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
// LockOwner field is valid.
|
|
||||||
ReadLockOwner ReadFlags = 1 << 1
|
|
||||||
)
|
|
||||||
|
|
||||||
var readFlagNames = []flagName{
|
|
||||||
{uint32(ReadLockOwner), "ReadLockOwner"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl ReadFlags) String() string {
|
|
||||||
return flagString(uint32(fl), readFlagNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
type writeIn struct {
|
|
||||||
Fh uint64
|
|
||||||
Offset uint64
|
|
||||||
Size uint32
|
|
||||||
WriteFlags uint32
|
|
||||||
LockOwner uint64
|
|
||||||
Flags uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 9}):
|
|
||||||
return unsafe.Offsetof(writeIn{}.LockOwner)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(writeIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type writeOut struct {
|
|
||||||
Size uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// The WriteFlags are passed in WriteRequest.
|
|
||||||
type WriteFlags uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
WriteCache WriteFlags = 1 << 0
|
|
||||||
// LockOwner field is valid.
|
|
||||||
WriteLockOwner WriteFlags = 1 << 1
|
|
||||||
)
|
|
||||||
|
|
||||||
var writeFlagNames = []flagName{
|
|
||||||
{uint32(WriteCache), "WriteCache"},
|
|
||||||
{uint32(WriteLockOwner), "WriteLockOwner"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl WriteFlags) String() string {
|
|
||||||
return flagString(uint32(fl), writeFlagNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
type statfsOut struct {
|
|
||||||
St kstatfs
|
|
||||||
}
|
|
||||||
|
|
||||||
type fsyncIn struct {
|
|
||||||
Fh uint64
|
|
||||||
FsyncFlags uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type setxattrInCommon struct {
|
|
||||||
Size uint32
|
|
||||||
Flags uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (setxattrInCommon) position() uint32 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type getxattrInCommon struct {
|
|
||||||
Size uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (getxattrInCommon) position() uint32 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type getxattrOut struct {
|
|
||||||
Size uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type lkIn struct {
|
|
||||||
Fh uint64
|
|
||||||
Owner uint64
|
|
||||||
Lk fileLock
|
|
||||||
LkFlags uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func lkInSize(p Protocol) uintptr {
|
|
||||||
switch {
|
|
||||||
case p.LT(Protocol{7, 9}):
|
|
||||||
return unsafe.Offsetof(lkIn{}.LkFlags)
|
|
||||||
default:
|
|
||||||
return unsafe.Sizeof(lkIn{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type lkOut struct {
|
|
||||||
Lk fileLock
|
|
||||||
}
|
|
||||||
|
|
||||||
type accessIn struct {
|
|
||||||
Mask uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type initIn struct {
|
|
||||||
Major uint32
|
|
||||||
Minor uint32
|
|
||||||
MaxReadahead uint32
|
|
||||||
Flags uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
const initInSize = int(unsafe.Sizeof(initIn{}))
|
|
||||||
|
|
||||||
type initOut struct {
|
|
||||||
Major uint32
|
|
||||||
Minor uint32
|
|
||||||
MaxReadahead uint32
|
|
||||||
Flags uint32
|
|
||||||
Unused uint32
|
|
||||||
MaxWrite uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type interruptIn struct {
|
|
||||||
Unique uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type bmapIn struct {
|
|
||||||
Block uint64
|
|
||||||
BlockSize uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type bmapOut struct {
|
|
||||||
Block uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type inHeader struct {
|
|
||||||
Len uint32
|
|
||||||
Opcode uint32
|
|
||||||
Unique uint64
|
|
||||||
Nodeid uint64
|
|
||||||
Uid uint32
|
|
||||||
Gid uint32
|
|
||||||
Pid uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
|
|
||||||
|
|
||||||
type outHeader struct {
|
|
||||||
Len uint32
|
|
||||||
Error int32
|
|
||||||
Unique uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type dirent struct {
|
|
||||||
Ino uint64
|
|
||||||
Off uint64
|
|
||||||
Namelen uint32
|
|
||||||
Type uint32
|
|
||||||
Name [0]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const direntSize = 8 + 8 + 4 + 4
|
|
||||||
|
|
||||||
const (
|
|
||||||
notifyCodePoll int32 = 1
|
|
||||||
notifyCodeInvalInode int32 = 2
|
|
||||||
notifyCodeInvalEntry int32 = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
type notifyInvalInodeOut struct {
|
|
||||||
Ino uint64
|
|
||||||
Off int64
|
|
||||||
Len int64
|
|
||||||
}
|
|
||||||
|
|
||||||
type notifyInvalEntryOut struct {
|
|
||||||
Parent uint64
|
|
||||||
Namelen uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
88
vendor/bazil.org/fuse/fuse_kernel_darwin.go
generated
vendored
88
vendor/bazil.org/fuse/fuse_kernel_darwin.go
generated
vendored
@ -1,88 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type attr struct {
|
|
||||||
Ino uint64
|
|
||||||
Size uint64
|
|
||||||
Blocks uint64
|
|
||||||
Atime uint64
|
|
||||||
Mtime uint64
|
|
||||||
Ctime uint64
|
|
||||||
Crtime_ uint64 // OS X only
|
|
||||||
AtimeNsec uint32
|
|
||||||
MtimeNsec uint32
|
|
||||||
CtimeNsec uint32
|
|
||||||
CrtimeNsec uint32 // OS X only
|
|
||||||
Mode uint32
|
|
||||||
Nlink uint32
|
|
||||||
Uid uint32
|
|
||||||
Gid uint32
|
|
||||||
Rdev uint32
|
|
||||||
Flags_ uint32 // OS X only; see chflags(2)
|
|
||||||
Blksize uint32
|
|
||||||
padding uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetCrtime(s uint64, ns uint32) {
|
|
||||||
a.Crtime_, a.CrtimeNsec = s, ns
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetFlags(f uint32) {
|
|
||||||
a.Flags_ = f
|
|
||||||
}
|
|
||||||
|
|
||||||
type setattrIn struct {
|
|
||||||
setattrInCommon
|
|
||||||
|
|
||||||
// OS X only
|
|
||||||
Bkuptime_ uint64
|
|
||||||
Chgtime_ uint64
|
|
||||||
Crtime uint64
|
|
||||||
BkuptimeNsec uint32
|
|
||||||
ChgtimeNsec uint32
|
|
||||||
CrtimeNsec uint32
|
|
||||||
Flags_ uint32 // see chflags(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) BkupTime() time.Time {
|
|
||||||
return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Chgtime() time.Time {
|
|
||||||
return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Flags() uint32 {
|
|
||||||
return in.Flags_
|
|
||||||
}
|
|
||||||
|
|
||||||
func openFlags(flags uint32) OpenFlags {
|
|
||||||
return OpenFlags(flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
type getxattrIn struct {
|
|
||||||
getxattrInCommon
|
|
||||||
|
|
||||||
// OS X only
|
|
||||||
Position uint32
|
|
||||||
Padding uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *getxattrIn) position() uint32 {
|
|
||||||
return g.Position
|
|
||||||
}
|
|
||||||
|
|
||||||
type setxattrIn struct {
|
|
||||||
setxattrInCommon
|
|
||||||
|
|
||||||
// OS X only
|
|
||||||
Position uint32
|
|
||||||
Padding uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *setxattrIn) position() uint32 {
|
|
||||||
return s.Position
|
|
||||||
}
|
|
62
vendor/bazil.org/fuse/fuse_kernel_freebsd.go
generated
vendored
62
vendor/bazil.org/fuse/fuse_kernel_freebsd.go
generated
vendored
@ -1,62 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type attr struct {
|
|
||||||
Ino uint64
|
|
||||||
Size uint64
|
|
||||||
Blocks uint64
|
|
||||||
Atime uint64
|
|
||||||
Mtime uint64
|
|
||||||
Ctime uint64
|
|
||||||
AtimeNsec uint32
|
|
||||||
MtimeNsec uint32
|
|
||||||
CtimeNsec uint32
|
|
||||||
Mode uint32
|
|
||||||
Nlink uint32
|
|
||||||
Uid uint32
|
|
||||||
Gid uint32
|
|
||||||
Rdev uint32
|
|
||||||
Blksize uint32
|
|
||||||
padding uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) Crtime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetCrtime(s uint64, ns uint32) {
|
|
||||||
// ignored on freebsd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetFlags(f uint32) {
|
|
||||||
// ignored on freebsd
|
|
||||||
}
|
|
||||||
|
|
||||||
type setattrIn struct {
|
|
||||||
setattrInCommon
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) BkupTime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Chgtime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Flags() uint32 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func openFlags(flags uint32) OpenFlags {
|
|
||||||
return OpenFlags(flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
type getxattrIn struct {
|
|
||||||
getxattrInCommon
|
|
||||||
}
|
|
||||||
|
|
||||||
type setxattrIn struct {
|
|
||||||
setxattrInCommon
|
|
||||||
}
|
|
70
vendor/bazil.org/fuse/fuse_kernel_linux.go
generated
vendored
70
vendor/bazil.org/fuse/fuse_kernel_linux.go
generated
vendored
@ -1,70 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type attr struct {
|
|
||||||
Ino uint64
|
|
||||||
Size uint64
|
|
||||||
Blocks uint64
|
|
||||||
Atime uint64
|
|
||||||
Mtime uint64
|
|
||||||
Ctime uint64
|
|
||||||
AtimeNsec uint32
|
|
||||||
MtimeNsec uint32
|
|
||||||
CtimeNsec uint32
|
|
||||||
Mode uint32
|
|
||||||
Nlink uint32
|
|
||||||
Uid uint32
|
|
||||||
Gid uint32
|
|
||||||
Rdev uint32
|
|
||||||
Blksize uint32
|
|
||||||
_ uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) Crtime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetCrtime(s uint64, ns uint32) {
|
|
||||||
// Ignored on Linux.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *attr) SetFlags(f uint32) {
|
|
||||||
// Ignored on Linux.
|
|
||||||
}
|
|
||||||
|
|
||||||
type setattrIn struct {
|
|
||||||
setattrInCommon
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) BkupTime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Chgtime() time.Time {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (in *setattrIn) Flags() uint32 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func openFlags(flags uint32) OpenFlags {
|
|
||||||
// on amd64, the 32-bit O_LARGEFILE flag is always seen;
|
|
||||||
// on i386, the flag probably depends on the app
|
|
||||||
// requesting, but in any case should be utterly
|
|
||||||
// uninteresting to us here; our kernel protocol messages
|
|
||||||
// are not directly related to the client app's kernel
|
|
||||||
// API/ABI
|
|
||||||
flags &^= 0x8000
|
|
||||||
|
|
||||||
return OpenFlags(flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
type getxattrIn struct {
|
|
||||||
getxattrInCommon
|
|
||||||
}
|
|
||||||
|
|
||||||
type setxattrIn struct {
|
|
||||||
setxattrInCommon
|
|
||||||
}
|
|
1
vendor/bazil.org/fuse/fuse_kernel_std.go
generated
vendored
1
vendor/bazil.org/fuse/fuse_kernel_std.go
generated
vendored
@ -1 +0,0 @@
|
|||||||
package fuse
|
|
7
vendor/bazil.org/fuse/fuse_linux.go
generated
vendored
7
vendor/bazil.org/fuse/fuse_linux.go
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
// Maximum file write size we are prepared to receive from the kernel.
|
|
||||||
//
|
|
||||||
// Linux 4.2.0 has been observed to cap this value at 128kB
|
|
||||||
// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages).
|
|
||||||
const maxWrite = 128 * 1024
|
|
20
vendor/bazil.org/fuse/fuseutil/fuseutil.go
generated
vendored
20
vendor/bazil.org/fuse/fuseutil/fuseutil.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
package fuseutil // import "bazil.org/fuse/fuseutil"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bazil.org/fuse"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleRead handles a read request assuming that data is the entire file content.
|
|
||||||
// It adjusts the amount returned in resp according to req.Offset and req.Size.
|
|
||||||
func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) {
|
|
||||||
if req.Offset >= int64(len(data)) {
|
|
||||||
data = nil
|
|
||||||
} else {
|
|
||||||
data = data[req.Offset:]
|
|
||||||
}
|
|
||||||
if len(data) > req.Size {
|
|
||||||
data = data[:req.Size]
|
|
||||||
}
|
|
||||||
n := copy(resp.Data[:req.Size], data)
|
|
||||||
resp.Data = resp.Data[:n]
|
|
||||||
}
|
|
8
vendor/bazil.org/fuse/go.mod
generated
vendored
8
vendor/bazil.org/fuse/go.mod
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
module bazil.org/fuse
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c
|
|
||||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449
|
|
||||||
)
|
|
4
vendor/bazil.org/fuse/go.sum
generated
vendored
4
vendor/bazil.org/fuse/go.sum
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
|
||||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
|
|
||||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
38
vendor/bazil.org/fuse/mount.go
generated
vendored
38
vendor/bazil.org/fuse/mount.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrOSXFUSENotFound is returned from Mount when the OSXFUSE
|
|
||||||
// installation is not detected.
|
|
||||||
//
|
|
||||||
// Only happens on OS X. Make sure OSXFUSE is installed, or see
|
|
||||||
// OSXFUSELocations for customization.
|
|
||||||
ErrOSXFUSENotFound = errors.New("cannot locate OSXFUSE")
|
|
||||||
)
|
|
||||||
|
|
||||||
func neverIgnoreLine(line string) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func lineLogger(wg *sync.WaitGroup, prefix string, ignore func(line string) bool, r io.ReadCloser) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
if ignore(line) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("%s: %s", prefix, line)
|
|
||||||
}
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
log.Printf("%s, error reading: %v", prefix, err)
|
|
||||||
}
|
|
||||||
}
|
|
208
vendor/bazil.org/fuse/mount_darwin.go
generated
vendored
208
vendor/bazil.org/fuse/mount_darwin.go
generated
vendored
@ -1,208 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNoAvail = errors.New("no available fuse devices")
|
|
||||||
errNotLoaded = errors.New("osxfuse is not loaded")
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadOSXFUSE(bin string) error {
|
|
||||||
cmd := exec.Command(bin)
|
|
||||||
cmd.Dir = "/"
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
err := cmd.Run()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func openOSXFUSEDev(devPrefix string) (*os.File, error) {
|
|
||||||
var f *os.File
|
|
||||||
var err error
|
|
||||||
for i := uint64(0); ; i++ {
|
|
||||||
path := devPrefix + strconv.FormatUint(i, 10)
|
|
||||||
f, err = os.OpenFile(path, os.O_RDWR, 0000)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if i == 0 {
|
|
||||||
// not even the first device was found -> fuse is not loaded
|
|
||||||
return nil, errNotLoaded
|
|
||||||
}
|
|
||||||
|
|
||||||
// we've run out of kernel-provided devices
|
|
||||||
return nil, errNoAvail
|
|
||||||
}
|
|
||||||
|
|
||||||
if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
|
|
||||||
// try the next one
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMountOSXFUSE(helperName string, errCh chan<- error) func(line string) (ignore bool) {
|
|
||||||
var noMountpointPrefix = helperName + `: `
|
|
||||||
const noMountpointSuffix = `: No such file or directory`
|
|
||||||
return func(line string) (ignore bool) {
|
|
||||||
if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
|
|
||||||
// re-extract it from the error message in case some layer
|
|
||||||
// changed the path
|
|
||||||
mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
|
|
||||||
err := &MountpointDoesNotExistError{
|
|
||||||
Path: mountpoint,
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case errCh <- err:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
// not the first error; fall back to logging it
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBoringMountOSXFUSEError returns whether the Wait error is
|
|
||||||
// uninteresting; exit status 64 is.
|
|
||||||
func isBoringMountOSXFUSEError(err error) bool {
|
|
||||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
|
||||||
if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 64 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func callMount(bin string, daemonVar string, dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
|
|
||||||
for k, v := range conf.options {
|
|
||||||
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
|
||||||
// Silly limitation but the mount helper does not
|
|
||||||
// understand any escaping. See TestMountOptionCommaError.
|
|
||||||
return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd := exec.Command(
|
|
||||||
bin,
|
|
||||||
"-o", conf.getOptions(),
|
|
||||||
// Tell osxfuse-kext how large our buffer is. It must split
|
|
||||||
// writes larger than this into multiple writes.
|
|
||||||
//
|
|
||||||
// OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
|
|
||||||
// this instead.
|
|
||||||
"-o", "iosize="+strconv.FormatUint(maxWrite, 10),
|
|
||||||
// refers to fd passed in cmd.ExtraFiles
|
|
||||||
"3",
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
cmd.ExtraFiles = []*os.File{f}
|
|
||||||
cmd.Env = os.Environ()
|
|
||||||
// OSXFUSE <3.3.0
|
|
||||||
cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
|
|
||||||
// OSXFUSE >=3.3.0
|
|
||||||
cmd.Env = append(cmd.Env, "MOUNT_OSXFUSE_CALL_BY_LIB=")
|
|
||||||
|
|
||||||
daemon := os.Args[0]
|
|
||||||
if daemonVar != "" {
|
|
||||||
cmd.Env = append(cmd.Env, daemonVar+"="+daemon)
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
|
|
||||||
}
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return fmt.Errorf("mount_osxfusefs: %v", err)
|
|
||||||
}
|
|
||||||
helperErrCh := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(2)
|
|
||||||
go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
|
|
||||||
helperName := path.Base(bin)
|
|
||||||
go lineLogger(&wg, "mount helper error", handleMountOSXFUSE(helperName, helperErrCh), stderr)
|
|
||||||
wg.Wait()
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
// see if we have a better error to report
|
|
||||||
select {
|
|
||||||
case helperErr := <-helperErrCh:
|
|
||||||
// log the Wait error if it's not what we expected
|
|
||||||
if !isBoringMountOSXFUSEError(err) {
|
|
||||||
log.Printf("mount helper failed: %v", err)
|
|
||||||
}
|
|
||||||
// and now return what we grabbed from stderr as the real
|
|
||||||
// error
|
|
||||||
*errp = helperErr
|
|
||||||
close(ready)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
// nope, fall back to generic message
|
|
||||||
}
|
|
||||||
|
|
||||||
*errp = fmt.Errorf("mount_osxfusefs: %v", err)
|
|
||||||
close(ready)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
*errp = nil
|
|
||||||
close(ready)
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
|
||||||
locations := conf.osxfuseLocations
|
|
||||||
if locations == nil {
|
|
||||||
locations = []OSXFUSEPaths{
|
|
||||||
OSXFUSELocationV3,
|
|
||||||
OSXFUSELocationV2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, loc := range locations {
|
|
||||||
if _, err := os.Stat(loc.Mount); os.IsNotExist(err) {
|
|
||||||
// try the other locations
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := openOSXFUSEDev(loc.DevicePrefix)
|
|
||||||
if err == errNotLoaded {
|
|
||||||
err = loadOSXFUSE(loc.Load)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// try again
|
|
||||||
f, err = openOSXFUSEDev(loc.DevicePrefix)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = callMount(loc.Mount, loc.DaemonVar, dir, conf, f, ready, errp)
|
|
||||||
if err != nil {
|
|
||||||
f.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
return nil, ErrOSXFUSENotFound
|
|
||||||
}
|
|
111
vendor/bazil.org/fuse/mount_freebsd.go
generated
vendored
111
vendor/bazil.org/fuse/mount_freebsd.go
generated
vendored
@ -1,111 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handleMountFusefsStderr(errCh chan<- error) func(line string) (ignore bool) {
|
|
||||||
return func(line string) (ignore bool) {
|
|
||||||
const (
|
|
||||||
noMountpointPrefix = `mount_fusefs: `
|
|
||||||
noMountpointSuffix = `: No such file or directory`
|
|
||||||
)
|
|
||||||
if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
|
|
||||||
// re-extract it from the error message in case some layer
|
|
||||||
// changed the path
|
|
||||||
mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
|
|
||||||
err := &MountpointDoesNotExistError{
|
|
||||||
Path: mountpoint,
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case errCh <- err:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
// not the first error; fall back to logging it
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBoringMountFusefsError returns whether the Wait error is
|
|
||||||
// uninteresting; exit status 1 is.
|
|
||||||
func isBoringMountFusefsError(err error) bool {
|
|
||||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
|
||||||
if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
|
|
||||||
for k, v := range conf.options {
|
|
||||||
if strings.Contains(k, ",") || strings.Contains(v, ",") {
|
|
||||||
// Silly limitation but the mount helper does not
|
|
||||||
// understand any escaping. See TestMountOptionCommaError.
|
|
||||||
return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000)
|
|
||||||
if err != nil {
|
|
||||||
*errp = err
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(
|
|
||||||
"/sbin/mount_fusefs",
|
|
||||||
"--safe",
|
|
||||||
"-o", conf.getOptions(),
|
|
||||||
"3",
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
cmd.ExtraFiles = []*os.File{f}
|
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
|
|
||||||
}
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, fmt.Errorf("mount_fusefs: %v", err)
|
|
||||||
}
|
|
||||||
helperErrCh := make(chan error, 1)
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(2)
|
|
||||||
go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
|
|
||||||
go lineLogger(&wg, "mount helper error", handleMountFusefsStderr(helperErrCh), stderr)
|
|
||||||
wg.Wait()
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
// see if we have a better error to report
|
|
||||||
select {
|
|
||||||
case helperErr := <-helperErrCh:
|
|
||||||
// log the Wait error if it's not what we expected
|
|
||||||
if !isBoringMountFusefsError(err) {
|
|
||||||
log.Printf("mount helper failed: %v", err)
|
|
||||||
}
|
|
||||||
// and now return what we grabbed from stderr as the real
|
|
||||||
// error
|
|
||||||
return nil, helperErr
|
|
||||||
default:
|
|
||||||
// nope, fall back to generic message
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("mount_fusefs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
close(ready)
|
|
||||||
return f, nil
|
|
||||||
}
|
|
150
vendor/bazil.org/fuse/mount_linux.go
generated
vendored
150
vendor/bazil.org/fuse/mount_linux.go
generated
vendored
@ -1,150 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handleFusermountStderr(errCh chan<- error) func(line string) (ignore bool) {
|
|
||||||
return func(line string) (ignore bool) {
|
|
||||||
if line == `fusermount: failed to open /etc/fuse.conf: Permission denied` {
|
|
||||||
// Silence this particular message, it occurs way too
|
|
||||||
// commonly and isn't very relevant to whether the mount
|
|
||||||
// succeeds or not.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
noMountpointPrefix = `fusermount: failed to access mountpoint `
|
|
||||||
noMountpointSuffix = `: No such file or directory`
|
|
||||||
)
|
|
||||||
if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
|
|
||||||
// re-extract it from the error message in case some layer
|
|
||||||
// changed the path
|
|
||||||
mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
|
|
||||||
err := &MountpointDoesNotExistError{
|
|
||||||
Path: mountpoint,
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case errCh <- err:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
// not the first error; fall back to logging it
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBoringFusermountError returns whether the Wait error is
|
|
||||||
// uninteresting; exit status 1 is.
|
|
||||||
func isBoringFusermountError(err error) bool {
|
|
||||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
|
||||||
if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
|
|
||||||
// linux mount is never delayed
|
|
||||||
close(ready)
|
|
||||||
|
|
||||||
fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("socketpair error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
|
|
||||||
defer writeFile.Close()
|
|
||||||
|
|
||||||
readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
|
|
||||||
defer readFile.Close()
|
|
||||||
|
|
||||||
cmd := exec.Command(
|
|
||||||
"fusermount",
|
|
||||||
"-o", conf.getOptions(),
|
|
||||||
"--",
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
|
|
||||||
|
|
||||||
cmd.ExtraFiles = []*os.File{writeFile}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
|
||||||
}
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, fmt.Errorf("fusermount: %v", err)
|
|
||||||
}
|
|
||||||
helperErrCh := make(chan error, 1)
|
|
||||||
wg.Add(2)
|
|
||||||
go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
|
|
||||||
go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr)
|
|
||||||
wg.Wait()
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
// see if we have a better error to report
|
|
||||||
select {
|
|
||||||
case helperErr := <-helperErrCh:
|
|
||||||
// log the Wait error if it's not what we expected
|
|
||||||
if !isBoringFusermountError(err) {
|
|
||||||
log.Printf("mount helper failed: %v", err)
|
|
||||||
}
|
|
||||||
// and now return what we grabbed from stderr as the real
|
|
||||||
// error
|
|
||||||
return nil, helperErr
|
|
||||||
default:
|
|
||||||
// nope, fall back to generic message
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("fusermount: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := net.FileConn(readFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
uc, ok := c.(*net.UnixConn)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 32) // expect 1 byte
|
|
||||||
oob := make([]byte, 32) // expect 24 bytes
|
|
||||||
_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
|
|
||||||
scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
|
|
||||||
}
|
|
||||||
if len(scms) != 1 {
|
|
||||||
return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
|
|
||||||
}
|
|
||||||
scm := scms[0]
|
|
||||||
gotFds, err := syscall.ParseUnixRights(&scm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
|
|
||||||
}
|
|
||||||
if len(gotFds) != 1 {
|
|
||||||
return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
|
|
||||||
}
|
|
||||||
f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
|
|
||||||
return f, nil
|
|
||||||
}
|
|
296
vendor/bazil.org/fuse/options.go
generated
vendored
296
vendor/bazil.org/fuse/options.go
generated
vendored
@ -1,296 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func dummyOption(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mountConfig holds the configuration for a mount operation.
|
|
||||||
// Use it by passing MountOption values to Mount.
|
|
||||||
type mountConfig struct {
|
|
||||||
options map[string]string
|
|
||||||
maxReadahead uint32
|
|
||||||
initFlags InitFlags
|
|
||||||
osxfuseLocations []OSXFUSEPaths
|
|
||||||
}
|
|
||||||
|
|
||||||
func escapeComma(s string) string {
|
|
||||||
s = strings.Replace(s, `\`, `\\`, -1)
|
|
||||||
s = strings.Replace(s, `,`, `\,`, -1)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// getOptions makes a string of options suitable for passing to FUSE
|
|
||||||
// mount flag `-o`. Returns an empty string if no options were set.
|
|
||||||
// Any platform specific adjustments should happen before the call.
|
|
||||||
func (m *mountConfig) getOptions() string {
|
|
||||||
var opts []string
|
|
||||||
for k, v := range m.options {
|
|
||||||
k = escapeComma(k)
|
|
||||||
if v != "" {
|
|
||||||
k += "=" + escapeComma(v)
|
|
||||||
}
|
|
||||||
opts = append(opts, k)
|
|
||||||
}
|
|
||||||
return strings.Join(opts, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
type mountOption func(*mountConfig) error
|
|
||||||
|
|
||||||
// MountOption is passed to Mount to change the behavior of the mount.
|
|
||||||
type MountOption mountOption
|
|
||||||
|
|
||||||
// FSName sets the file system name (also called source) that is
|
|
||||||
// visible in the list of mounted file systems.
|
|
||||||
//
|
|
||||||
// FreeBSD ignores this option.
|
|
||||||
func FSName(name string) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["fsname"] = name
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtype sets the subtype of the mount. The main type is always
|
|
||||||
// `fuse`. The type in a list of mounted file systems will look like
|
|
||||||
// `fuse.foo`.
|
|
||||||
//
|
|
||||||
// OS X ignores this option.
|
|
||||||
// FreeBSD ignores this option.
|
|
||||||
func Subtype(fstype string) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["subtype"] = fstype
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalVolume sets the volume to be local (instead of network),
|
|
||||||
// changing the behavior of Finder, Spotlight, and such.
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func LocalVolume() MountOption {
|
|
||||||
return localVolume
|
|
||||||
}
|
|
||||||
|
|
||||||
// VolumeName sets the volume name shown in Finder.
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func VolumeName(name string) MountOption {
|
|
||||||
return volumeName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoAppleDouble makes OSXFUSE disallow files with names used by OS X
|
|
||||||
// to store extended attributes on file systems that do not support
|
|
||||||
// them natively.
|
|
||||||
//
|
|
||||||
// Such file names are:
|
|
||||||
//
|
|
||||||
// ._*
|
|
||||||
// .DS_Store
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func NoAppleDouble() MountOption {
|
|
||||||
return noAppleDouble
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoAppleXattr makes OSXFUSE disallow extended attributes with the
|
|
||||||
// prefix "com.apple.". This disables persistent Finder state and
|
|
||||||
// other such information.
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func NoAppleXattr() MountOption {
|
|
||||||
return noAppleXattr
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoBrowse makes OSXFUSE mark the volume as non-browsable, so that
|
|
||||||
// Finder won't automatically browse it.
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func NoBrowse() MountOption {
|
|
||||||
return noBrowse
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates,
|
|
||||||
// i.e. create calls for which the initiator explicitly set the O_EXCL flag.
|
|
||||||
//
|
|
||||||
// OSXFUSE expects all create calls to return EEXIST in case the file
|
|
||||||
// already exists, regardless of whether O_EXCL was specified or not.
|
|
||||||
// To ensure this behavior, it normally sets OpenExclusive for all
|
|
||||||
// Create calls, regardless of whether the original call had it set.
|
|
||||||
// For distributed filesystems, that may force every file create to be
|
|
||||||
// a distributed consensus action, causing undesirable delays.
|
|
||||||
//
|
|
||||||
// This option makes the FUSE filesystem see the original flag value,
|
|
||||||
// and better decide when to ensure global consensus.
|
|
||||||
//
|
|
||||||
// Note that returning EEXIST on existing file create is still
|
|
||||||
// expected with OSXFUSE, regardless of the presence of the
|
|
||||||
// OpenExclusive flag.
|
|
||||||
//
|
|
||||||
// For more information, see
|
|
||||||
// https://github.com/osxfuse/osxfuse/issues/209
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this options.
|
|
||||||
// Requires OSXFUSE 3.4.1 or newer.
|
|
||||||
func ExclCreate() MountOption {
|
|
||||||
return exclCreate
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonTimeout sets the time in seconds between a request and a reply before
|
|
||||||
// the FUSE mount is declared dead.
|
|
||||||
//
|
|
||||||
// OS X and FreeBSD only. Others ignore this option.
|
|
||||||
func DaemonTimeout(name string) MountOption {
|
|
||||||
return daemonTimeout(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowOther allows other users to access the file system.
|
|
||||||
func AllowOther() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["allow_other"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowDev enables interpreting character or block special devices on the
|
|
||||||
// filesystem.
|
|
||||||
func AllowDev() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["dev"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowSUID allows set-user-identifier or set-group-identifier bits to take
|
|
||||||
// effect.
|
|
||||||
func AllowSUID() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["suid"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultPermissions makes the kernel enforce access control based on
|
|
||||||
// the file mode (as in chmod).
|
|
||||||
//
|
|
||||||
// Without this option, the Node itself decides what is and is not
|
|
||||||
// allowed. This is normally ok because FUSE file systems cannot be
|
|
||||||
// accessed by other users without AllowOther.
|
|
||||||
//
|
|
||||||
// FreeBSD ignores this option.
|
|
||||||
func DefaultPermissions() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["default_permissions"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadOnly makes the mount read-only.
|
|
||||||
func ReadOnly() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["ro"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxReadahead sets the number of bytes that can be prefetched for
|
|
||||||
// sequential reads. The kernel can enforce a maximum value lower than
|
|
||||||
// this.
|
|
||||||
//
|
|
||||||
// This setting makes the kernel perform speculative reads that do not
|
|
||||||
// originate from any client process. This usually tremendously
|
|
||||||
// improves read performance.
|
|
||||||
func MaxReadahead(n uint32) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.maxReadahead = n
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AsyncRead enables multiple outstanding read requests for the same
|
|
||||||
// handle. Without this, there is at most one request in flight at a
|
|
||||||
// time.
|
|
||||||
func AsyncRead() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.initFlags |= InitAsyncRead
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WritebackCache enables the kernel to buffer writes before sending
|
|
||||||
// them to the FUSE server. Without this, writethrough caching is
|
|
||||||
// used.
|
|
||||||
func WritebackCache() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.initFlags |= InitWritebackCache
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OSXFUSEPaths describes the paths used by an installed OSXFUSE
|
|
||||||
// version. See OSXFUSELocationV3 for typical values.
|
|
||||||
type OSXFUSEPaths struct {
|
|
||||||
// Prefix for the device file. At mount time, an incrementing
|
|
||||||
// number is suffixed until a free FUSE device is found.
|
|
||||||
DevicePrefix string
|
|
||||||
// Path of the load helper, used to load the kernel extension if
|
|
||||||
// no device files are found.
|
|
||||||
Load string
|
|
||||||
// Path of the mount helper, used for the actual mount operation.
|
|
||||||
Mount string
|
|
||||||
// Environment variable used to pass the path to the executable
|
|
||||||
// calling the mount helper.
|
|
||||||
DaemonVar string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default paths for OSXFUSE. See OSXFUSELocations.
|
|
||||||
var (
|
|
||||||
OSXFUSELocationV3 = OSXFUSEPaths{
|
|
||||||
DevicePrefix: "/dev/osxfuse",
|
|
||||||
Load: "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse",
|
|
||||||
Mount: "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
|
|
||||||
DaemonVar: "MOUNT_OSXFUSE_DAEMON_PATH",
|
|
||||||
}
|
|
||||||
OSXFUSELocationV2 = OSXFUSEPaths{
|
|
||||||
DevicePrefix: "/dev/osxfuse",
|
|
||||||
Load: "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs",
|
|
||||||
Mount: "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
|
|
||||||
DaemonVar: "MOUNT_FUSEFS_DAEMON_PATH",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// OSXFUSELocations sets where to look for OSXFUSE files. The
|
|
||||||
// arguments are all the possible locations. The previous locations
|
|
||||||
// are replaced.
|
|
||||||
//
|
|
||||||
// Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are
|
|
||||||
// used.
|
|
||||||
//
|
|
||||||
// OS X only. Others ignore this option.
|
|
||||||
func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
if len(paths) == 0 {
|
|
||||||
return errors.New("must specify at least one location for OSXFUSELocations")
|
|
||||||
}
|
|
||||||
// replace previous values, but make a copy so there's no
|
|
||||||
// worries about caller mutating their slice
|
|
||||||
conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowNonEmptyMount allows the mounting over a non-empty directory.
|
|
||||||
//
|
|
||||||
// The files in it will be shadowed by the freshly created mount. By
|
|
||||||
// default these mounts are rejected to prevent accidental covering up
|
|
||||||
// of data, which could for example prevent automatic backup.
|
|
||||||
func AllowNonEmptyMount() MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["nonempty"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
40
vendor/bazil.org/fuse/options_darwin.go
generated
vendored
40
vendor/bazil.org/fuse/options_darwin.go
generated
vendored
@ -1,40 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
func localVolume(conf *mountConfig) error {
|
|
||||||
conf.options["local"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func volumeName(name string) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["volname"] = name
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func daemonTimeout(name string) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["daemon_timeout"] = name
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleXattr(conf *mountConfig) error {
|
|
||||||
conf.options["noapplexattr"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleDouble(conf *mountConfig) error {
|
|
||||||
conf.options["noappledouble"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func exclCreate(conf *mountConfig) error {
|
|
||||||
conf.options["excl_create"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noBrowse(conf *mountConfig) error {
|
|
||||||
conf.options["nobrowse"] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
32
vendor/bazil.org/fuse/options_freebsd.go
generated
vendored
32
vendor/bazil.org/fuse/options_freebsd.go
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
func localVolume(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func volumeName(name string) MountOption {
|
|
||||||
return dummyOption
|
|
||||||
}
|
|
||||||
|
|
||||||
func daemonTimeout(name string) MountOption {
|
|
||||||
return func(conf *mountConfig) error {
|
|
||||||
conf.options["timeout"] = name
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleXattr(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleDouble(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func exclCreate(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noBrowse(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
29
vendor/bazil.org/fuse/options_linux.go
generated
vendored
29
vendor/bazil.org/fuse/options_linux.go
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
func localVolume(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func volumeName(name string) MountOption {
|
|
||||||
return dummyOption
|
|
||||||
}
|
|
||||||
|
|
||||||
func daemonTimeout(name string) MountOption {
|
|
||||||
return dummyOption
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleXattr(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noAppleDouble(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func exclCreate(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func noBrowse(conf *mountConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
75
vendor/bazil.org/fuse/protocol.go
generated
vendored
75
vendor/bazil.org/fuse/protocol.go
generated
vendored
@ -1,75 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Protocol is a FUSE protocol version number.
|
|
||||||
type Protocol struct {
|
|
||||||
Major uint32
|
|
||||||
Minor uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Protocol) String() string {
|
|
||||||
return fmt.Sprintf("%d.%d", p.Major, p.Minor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LT returns whether a is less than b.
|
|
||||||
func (a Protocol) LT(b Protocol) bool {
|
|
||||||
return a.Major < b.Major ||
|
|
||||||
(a.Major == b.Major && a.Minor < b.Minor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GE returns whether a is greater than or equal to b.
|
|
||||||
func (a Protocol) GE(b Protocol) bool {
|
|
||||||
return a.Major > b.Major ||
|
|
||||||
(a.Major == b.Major && a.Minor >= b.Minor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Protocol) is79() bool {
|
|
||||||
return a.GE(Protocol{7, 9})
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasAttrBlockSize returns whether Attr.BlockSize is respected by the
|
|
||||||
// kernel.
|
|
||||||
func (a Protocol) HasAttrBlockSize() bool {
|
|
||||||
return a.is79()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasReadWriteFlags returns whether ReadRequest/WriteRequest
|
|
||||||
// fields Flags and FileFlags are valid.
|
|
||||||
func (a Protocol) HasReadWriteFlags() bool {
|
|
||||||
return a.is79()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasGetattrFlags returns whether GetattrRequest field Flags is
|
|
||||||
// valid.
|
|
||||||
func (a Protocol) HasGetattrFlags() bool {
|
|
||||||
return a.is79()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Protocol) is710() bool {
|
|
||||||
return a.GE(Protocol{7, 10})
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasOpenNonSeekable returns whether OpenResponse field Flags flag
|
|
||||||
// OpenNonSeekable is supported.
|
|
||||||
func (a Protocol) HasOpenNonSeekable() bool {
|
|
||||||
return a.is710()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Protocol) is712() bool {
|
|
||||||
return a.GE(Protocol{7, 12})
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasUmask returns whether CreateRequest/MkdirRequest/MknodRequest
|
|
||||||
// field Umask is valid.
|
|
||||||
func (a Protocol) HasUmask() bool {
|
|
||||||
return a.is712()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasInvalidate returns whether InvalidateNode/InvalidateEntry are
|
|
||||||
// supported.
|
|
||||||
func (a Protocol) HasInvalidate() bool {
|
|
||||||
return a.is712()
|
|
||||||
}
|
|
6
vendor/bazil.org/fuse/unmount.go
generated
vendored
6
vendor/bazil.org/fuse/unmount.go
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
// Unmount tries to unmount the filesystem mounted at dir.
|
|
||||||
func Unmount(dir string) error {
|
|
||||||
return unmount(dir)
|
|
||||||
}
|
|
21
vendor/bazil.org/fuse/unmount_linux.go
generated
vendored
21
vendor/bazil.org/fuse/unmount_linux.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
func unmount(dir string) error {
|
|
||||||
cmd := exec.Command("fusermount", "-u", dir)
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
if len(output) > 0 {
|
|
||||||
output = bytes.TrimRight(output, "\n")
|
|
||||||
msg := err.Error() + ": " + string(output)
|
|
||||||
err = errors.New(msg)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
17
vendor/bazil.org/fuse/unmount_std.go
generated
vendored
17
vendor/bazil.org/fuse/unmount_std.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
// +build !linux
|
|
||||||
|
|
||||||
package fuse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func unmount(dir string) error {
|
|
||||||
err := syscall.Unmount(dir, 0)
|
|
||||||
if err != nil {
|
|
||||||
err = &os.PathError{Op: "unmount", Path: dir, Err: err}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
518
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
518
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
@ -1,518 +0,0 @@
|
|||||||
// Copyright 2014 Google LLC
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package metadata provides access to Google Compute Engine (GCE)
|
|
||||||
// metadata and API service accounts.
|
|
||||||
//
|
|
||||||
// This package is a wrapper around the GCE metadata service,
|
|
||||||
// as documented at https://developers.google.com/compute/docs/metadata.
|
|
||||||
package metadata // import "cloud.google.com/go/compute/metadata"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// metadataIP is the documented metadata server IP address.
|
|
||||||
metadataIP = "169.254.169.254"
|
|
||||||
|
|
||||||
// metadataHostEnv is the environment variable specifying the
|
|
||||||
// GCE metadata hostname. If empty, the default value of
|
|
||||||
// metadataIP ("169.254.169.254") is used instead.
|
|
||||||
// This is variable name is not defined by any spec, as far as
|
|
||||||
// I know; it was made up for the Go package.
|
|
||||||
metadataHostEnv = "GCE_METADATA_HOST"
|
|
||||||
|
|
||||||
userAgent = "gcloud-golang/0.1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type cachedValue struct {
|
|
||||||
k string
|
|
||||||
trim bool
|
|
||||||
mu sync.Mutex
|
|
||||||
v string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
projID = &cachedValue{k: "project/project-id", trim: true}
|
|
||||||
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
|
||||||
instID = &cachedValue{k: "instance/id", trim: true}
|
|
||||||
)
|
|
||||||
|
|
||||||
var defaultClient = &Client{hc: &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Dial: (&net.Dialer{
|
|
||||||
Timeout: 2 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
}).Dial,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
// NotDefinedError is returned when requested metadata is not defined.
|
|
||||||
//
|
|
||||||
// The underlying string is the suffix after "/computeMetadata/v1/".
|
|
||||||
//
|
|
||||||
// This error is not returned if the value is defined to be the empty
|
|
||||||
// string.
|
|
||||||
type NotDefinedError string
|
|
||||||
|
|
||||||
func (suffix NotDefinedError) Error() string {
|
|
||||||
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cachedValue) get(cl *Client) (v string, err error) {
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.mu.Lock()
|
|
||||||
if c.v != "" {
|
|
||||||
return c.v, nil
|
|
||||||
}
|
|
||||||
if c.trim {
|
|
||||||
v, err = cl.getTrimmed(c.k)
|
|
||||||
} else {
|
|
||||||
v, err = cl.Get(c.k)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
c.v = v
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
onGCEOnce sync.Once
|
|
||||||
onGCE bool
|
|
||||||
)
|
|
||||||
|
|
||||||
// OnGCE reports whether this process is running on Google Compute Engine.
|
|
||||||
func OnGCE() bool {
|
|
||||||
onGCEOnce.Do(initOnGCE)
|
|
||||||
return onGCE
|
|
||||||
}
|
|
||||||
|
|
||||||
func initOnGCE() {
|
|
||||||
onGCE = testOnGCE()
|
|
||||||
}
|
|
||||||
|
|
||||||
func testOnGCE() bool {
|
|
||||||
// The user explicitly said they're on GCE, so trust them.
|
|
||||||
if os.Getenv(metadataHostEnv) != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
resc := make(chan bool, 2)
|
|
||||||
|
|
||||||
// Try two strategies in parallel.
|
|
||||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
|
||||||
go func() {
|
|
||||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
|
||||||
req.Header.Set("User-Agent", userAgent)
|
|
||||||
res, err := defaultClient.hc.Do(req.WithContext(ctx))
|
|
||||||
if err != nil {
|
|
||||||
resc <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
addrs, err := net.DefaultResolver.LookupHost(ctx, "metadata.google.internal")
|
|
||||||
if err != nil || len(addrs) == 0 {
|
|
||||||
resc <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resc <- strsContains(addrs, metadataIP)
|
|
||||||
}()
|
|
||||||
|
|
||||||
tryHarder := systemInfoSuggestsGCE()
|
|
||||||
if tryHarder {
|
|
||||||
res := <-resc
|
|
||||||
if res {
|
|
||||||
// The first strategy succeeded, so let's use it.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Wait for either the DNS or metadata server probe to
|
|
||||||
// contradict the other one and say we are running on
|
|
||||||
// GCE. Give it a lot of time to do so, since the system
|
|
||||||
// info already suggests we're running on a GCE BIOS.
|
|
||||||
timer := time.NewTimer(5 * time.Second)
|
|
||||||
defer timer.Stop()
|
|
||||||
select {
|
|
||||||
case res = <-resc:
|
|
||||||
return res
|
|
||||||
case <-timer.C:
|
|
||||||
// Too slow. Who knows what this system is.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no hint from the system info that we're running on
|
|
||||||
// GCE, so use the first probe's result as truth, whether it's
|
|
||||||
// true or false. The goal here is to optimize for speed for
|
|
||||||
// users who are NOT running on GCE. We can't assume that
|
|
||||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
|
||||||
// address is fast. Worst case this should return when the
|
|
||||||
// metaClient's Transport.ResponseHeaderTimeout or
|
|
||||||
// Transport.Dial.Timeout fires (in two seconds).
|
|
||||||
return <-resc
|
|
||||||
}
|
|
||||||
|
|
||||||
// systemInfoSuggestsGCE reports whether the local system (without
|
|
||||||
// doing network requests) suggests that we're running on GCE. If this
|
|
||||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
|
||||||
// server.
|
|
||||||
func systemInfoSuggestsGCE() bool {
|
|
||||||
if runtime.GOOS != "linux" {
|
|
||||||
// We don't have any non-Linux clues available, at least yet.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
|
||||||
name := strings.TrimSpace(string(slurp))
|
|
||||||
return name == "Google" || name == "Google Compute Engine"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe calls Client.Subscribe on the default client.
|
|
||||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
|
||||||
return defaultClient.Subscribe(suffix, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get calls Client.Get on the default client.
|
|
||||||
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
|
|
||||||
|
|
||||||
// ProjectID returns the current instance's project ID string.
|
|
||||||
func ProjectID() (string, error) { return defaultClient.ProjectID() }
|
|
||||||
|
|
||||||
// NumericProjectID returns the current instance's numeric project ID.
|
|
||||||
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
|
|
||||||
|
|
||||||
// InternalIP returns the instance's primary internal IP address.
|
|
||||||
func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
|
||||||
|
|
||||||
// ExternalIP returns the instance's primary external (public) IP address.
|
|
||||||
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
|
||||||
|
|
||||||
// Email calls Client.Email on the default client.
|
|
||||||
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
|
||||||
|
|
||||||
// Hostname returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
func Hostname() (string, error) { return defaultClient.Hostname() }
|
|
||||||
|
|
||||||
// InstanceTags returns the list of user-defined instance tags,
|
|
||||||
// assigned when initially creating a GCE instance.
|
|
||||||
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
|
|
||||||
|
|
||||||
// InstanceID returns the current VM's numeric instance ID.
|
|
||||||
func InstanceID() (string, error) { return defaultClient.InstanceID() }
|
|
||||||
|
|
||||||
// InstanceName returns the current VM's instance ID string.
|
|
||||||
func InstanceName() (string, error) { return defaultClient.InstanceName() }
|
|
||||||
|
|
||||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
|
||||||
func Zone() (string, error) { return defaultClient.Zone() }
|
|
||||||
|
|
||||||
// InstanceAttributes calls Client.InstanceAttributes on the default client.
|
|
||||||
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
|
|
||||||
|
|
||||||
// ProjectAttributes calls Client.ProjectAttributes on the default client.
|
|
||||||
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
|
|
||||||
|
|
||||||
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
|
|
||||||
func InstanceAttributeValue(attr string) (string, error) {
|
|
||||||
return defaultClient.InstanceAttributeValue(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
|
|
||||||
func ProjectAttributeValue(attr string) (string, error) {
|
|
||||||
return defaultClient.ProjectAttributeValue(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scopes calls Client.Scopes on the default client.
|
|
||||||
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
|
|
||||||
|
|
||||||
func strsContains(ss []string, s string) bool {
|
|
||||||
for _, v := range ss {
|
|
||||||
if v == s {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Client provides metadata.
|
|
||||||
type Client struct {
|
|
||||||
hc *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient returns a Client that can be used to fetch metadata.
|
|
||||||
// Returns the client that uses the specified http.Client for HTTP requests.
|
|
||||||
// If nil is specified, returns the default client.
|
|
||||||
func NewClient(c *http.Client) *Client {
|
|
||||||
if c == nil {
|
|
||||||
return defaultClient
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Client{hc: c}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getETag returns a value from the metadata service as well as the associated ETag.
|
|
||||||
// This func is otherwise equivalent to Get.
|
|
||||||
func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
|
||||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
|
||||||
// a container, which is an important use-case for local testing of cloud
|
|
||||||
// deployments. To enable spoofing of the metadata service, the environment
|
|
||||||
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
|
||||||
// requests shall go.
|
|
||||||
host := os.Getenv(metadataHostEnv)
|
|
||||||
if host == "" {
|
|
||||||
// Using 169.254.169.254 instead of "metadata" here because Go
|
|
||||||
// binaries built with the "netgo" tag and without cgo won't
|
|
||||||
// know the search suffix for "metadata" is
|
|
||||||
// ".google.internal", and this IP address is documented as
|
|
||||||
// being stable anyway.
|
|
||||||
host = metadataIP
|
|
||||||
}
|
|
||||||
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
|
||||||
req, err := http.NewRequest("GET", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
req.Header.Set("Metadata-Flavor", "Google")
|
|
||||||
req.Header.Set("User-Agent", userAgent)
|
|
||||||
res, err := c.hc.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode == http.StatusNotFound {
|
|
||||||
return "", "", NotDefinedError(suffix)
|
|
||||||
}
|
|
||||||
all, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
|
||||||
}
|
|
||||||
return string(all), res.Header.Get("Etag"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
//
|
|
||||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
|
||||||
// 169.254.169.254 will be used instead.
|
|
||||||
//
|
|
||||||
// If the requested metadata is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
func (c *Client) Get(suffix string) (string, error) {
|
|
||||||
val, _, err := c.getETag(suffix)
|
|
||||||
return val, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) getTrimmed(suffix string) (s string, err error) {
|
|
||||||
s, err = c.Get(suffix)
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) lines(suffix string) ([]string, error) {
|
|
||||||
j, err := c.Get(suffix)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s := strings.Split(strings.TrimSpace(j), "\n")
|
|
||||||
for i := range s {
|
|
||||||
s[i] = strings.TrimSpace(s[i])
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectID returns the current instance's project ID string.
|
|
||||||
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
|
|
||||||
|
|
||||||
// NumericProjectID returns the current instance's numeric project ID.
|
|
||||||
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
|
|
||||||
|
|
||||||
// InstanceID returns the current VM's numeric instance ID.
|
|
||||||
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
|
|
||||||
|
|
||||||
// InternalIP returns the instance's primary internal IP address.
|
|
||||||
func (c *Client) InternalIP() (string, error) {
|
|
||||||
return c.getTrimmed("instance/network-interfaces/0/ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email returns the email address associated with the service account.
|
|
||||||
// The account may be empty or the string "default" to use the instance's
|
|
||||||
// main account.
|
|
||||||
func (c *Client) Email(serviceAccount string) (string, error) {
|
|
||||||
if serviceAccount == "" {
|
|
||||||
serviceAccount = "default"
|
|
||||||
}
|
|
||||||
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExternalIP returns the instance's primary external (public) IP address.
|
|
||||||
func (c *Client) ExternalIP() (string, error) {
|
|
||||||
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hostname returns the instance's hostname. This will be of the form
|
|
||||||
// "<instanceID>.c.<projID>.internal".
|
|
||||||
func (c *Client) Hostname() (string, error) {
|
|
||||||
return c.getTrimmed("instance/hostname")
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceTags returns the list of user-defined instance tags,
|
|
||||||
// assigned when initially creating a GCE instance.
|
|
||||||
func (c *Client) InstanceTags() ([]string, error) {
|
|
||||||
var s []string
|
|
||||||
j, err := c.Get("instance/tags")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceName returns the current VM's instance ID string.
|
|
||||||
func (c *Client) InstanceName() (string, error) {
|
|
||||||
return c.getTrimmed("instance/name")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zone returns the current VM's zone, such as "us-central1-b".
|
|
||||||
func (c *Client) Zone() (string, error) {
|
|
||||||
zone, err := c.getTrimmed("instance/zone")
|
|
||||||
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return zone[strings.LastIndex(zone, "/")+1:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceAttributes returns the list of user-defined attributes,
|
|
||||||
// assigned when initially creating a GCE VM instance. The value of an
|
|
||||||
// attribute can be obtained with InstanceAttributeValue.
|
|
||||||
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
|
|
||||||
|
|
||||||
// ProjectAttributes returns the list of user-defined attributes
|
|
||||||
// applying to the project as a whole, not just this VM. The value of
|
|
||||||
// an attribute can be obtained with ProjectAttributeValue.
|
|
||||||
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
|
|
||||||
|
|
||||||
// InstanceAttributeValue returns the value of the provided VM
|
|
||||||
// instance attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// InstanceAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
|
||||||
return c.Get("instance/attributes/" + attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectAttributeValue returns the value of the provided
|
|
||||||
// project attribute.
|
|
||||||
//
|
|
||||||
// If the requested attribute is not defined, the returned error will
|
|
||||||
// be of type NotDefinedError.
|
|
||||||
//
|
|
||||||
// ProjectAttributeValue may return ("", nil) if the attribute was
|
|
||||||
// defined to be the empty string.
|
|
||||||
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
|
||||||
return c.Get("project/attributes/" + attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scopes returns the service account scopes for the given account.
|
|
||||||
// The account may be empty or the string "default" to use the instance's
|
|
||||||
// main account.
|
|
||||||
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
|
||||||
if serviceAccount == "" {
|
|
||||||
serviceAccount = "default"
|
|
||||||
}
|
|
||||||
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe subscribes to a value from the metadata service.
|
|
||||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
|
||||||
// The suffix may contain query parameters.
|
|
||||||
//
|
|
||||||
// Subscribe calls fn with the latest metadata value indicated by the provided
|
|
||||||
// suffix. If the metadata value is deleted, fn is called with the empty string
|
|
||||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
|
||||||
// is deleted. Subscribe returns the error value returned from the last call to
|
|
||||||
// fn, which may be nil when ok == false.
|
|
||||||
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
|
||||||
const failedSubscribeSleep = time.Second * 5
|
|
||||||
|
|
||||||
// First check to see if the metadata value exists at all.
|
|
||||||
val, lastETag, err := c.getETag(suffix)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fn(val, true); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := true
|
|
||||||
if strings.ContainsRune(suffix, '?') {
|
|
||||||
suffix += "&wait_for_change=true&last_etag="
|
|
||||||
} else {
|
|
||||||
suffix += "?wait_for_change=true&last_etag="
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
|
|
||||||
if err != nil {
|
|
||||||
if _, deleted := err.(NotDefinedError); !deleted {
|
|
||||||
time.Sleep(failedSubscribeSleep)
|
|
||||||
continue // Retry on other errors.
|
|
||||||
}
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
lastETag = etag
|
|
||||||
|
|
||||||
if err := fn(val, ok); err != nil || !ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error contains an error response from the server.
|
|
||||||
type Error struct {
|
|
||||||
// Code is the HTTP response status code.
|
|
||||||
Code int
|
|
||||||
// Message is the server response message.
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
|
||||||
}
|
|
21
vendor/github.com/Azure/azure-pipeline-go/LICENSE
generated
vendored
21
vendor/github.com/Azure/azure-pipeline-go/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE
|
|
284
vendor/github.com/Azure/azure-pipeline-go/pipeline/core.go
generated
vendored
284
vendor/github.com/Azure/azure-pipeline-go/pipeline/core.go
generated
vendored
@ -1,284 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/mattn/go-ieproxy"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The Factory interface represents an object that can create its Policy object. Each HTTP request sent
|
|
||||||
// requires that this Factory create a new instance of its Policy object.
|
|
||||||
type Factory interface {
|
|
||||||
New(next Policy, po *PolicyOptions) Policy
|
|
||||||
}
|
|
||||||
|
|
||||||
// FactoryFunc is an adapter that allows the use of an ordinary function as a Factory interface.
|
|
||||||
type FactoryFunc func(next Policy, po *PolicyOptions) PolicyFunc
|
|
||||||
|
|
||||||
// New calls f(next,po).
|
|
||||||
func (f FactoryFunc) New(next Policy, po *PolicyOptions) Policy {
|
|
||||||
return f(next, po)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Policy interface represents a mutable Policy object created by a Factory. The object can mutate/process
|
|
||||||
// the HTTP request and then forward it on to the next Policy object in the linked-list. The returned
|
|
||||||
// Response goes backward through the linked-list for additional processing.
|
|
||||||
// NOTE: Request is passed by value so changes do not change the caller's version of
|
|
||||||
// the request. However, Request has some fields that reference mutable objects (not strings).
|
|
||||||
// These references are copied; a deep copy is not performed. Specifically, this means that
|
|
||||||
// you should avoid modifying the objects referred to by these fields: URL, Header, Body,
|
|
||||||
// GetBody, TransferEncoding, Form, MultipartForm, Trailer, TLS, Cancel, and Response.
|
|
||||||
type Policy interface {
|
|
||||||
Do(ctx context.Context, request Request) (Response, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PolicyFunc is an adapter that allows the use of an ordinary function as a Policy interface.
|
|
||||||
type PolicyFunc func(ctx context.Context, request Request) (Response, error)
|
|
||||||
|
|
||||||
// Do calls f(ctx, request).
|
|
||||||
func (f PolicyFunc) Do(ctx context.Context, request Request) (Response, error) {
|
|
||||||
return f(ctx, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options configures a Pipeline's behavior.
|
|
||||||
type Options struct {
|
|
||||||
HTTPSender Factory // If sender is nil, then the pipeline's default client is used to send the HTTP requests.
|
|
||||||
Log LogOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogLevel tells a logger the minimum level to log. When code reports a log entry,
|
|
||||||
// the LogLevel indicates the level of the log entry. The logger only records entries
|
|
||||||
// whose level is at least the level it was told to log. See the Log* constants.
|
|
||||||
// For example, if a logger is configured with LogError, then LogError, LogPanic,
|
|
||||||
// and LogFatal entries will be logged; lower level entries are ignored.
|
|
||||||
type LogLevel uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
// LogNone tells a logger not to log any entries passed to it.
|
|
||||||
LogNone LogLevel = iota
|
|
||||||
|
|
||||||
// LogFatal tells a logger to log all LogFatal entries passed to it.
|
|
||||||
LogFatal
|
|
||||||
|
|
||||||
// LogPanic tells a logger to log all LogPanic and LogFatal entries passed to it.
|
|
||||||
LogPanic
|
|
||||||
|
|
||||||
// LogError tells a logger to log all LogError, LogPanic and LogFatal entries passed to it.
|
|
||||||
LogError
|
|
||||||
|
|
||||||
// LogWarning tells a logger to log all LogWarning, LogError, LogPanic and LogFatal entries passed to it.
|
|
||||||
LogWarning
|
|
||||||
|
|
||||||
// LogInfo tells a logger to log all LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it.
|
|
||||||
LogInfo
|
|
||||||
|
|
||||||
// LogDebug tells a logger to log all LogDebug, LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it.
|
|
||||||
LogDebug
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogOptions configures the pipeline's logging mechanism & level filtering.
|
|
||||||
type LogOptions struct {
|
|
||||||
Log func(level LogLevel, message string)
|
|
||||||
|
|
||||||
// ShouldLog is called periodically allowing you to return whether the specified LogLevel should be logged or not.
|
|
||||||
// An application can return different values over the its lifetime; this allows the application to dynamically
|
|
||||||
// alter what is logged. NOTE: This method can be called by multiple goroutines simultaneously so make sure
|
|
||||||
// you implement it in a goroutine-safe way. If nil, nothing is logged (the equivalent of returning LogNone).
|
|
||||||
// Usually, the function will be implemented simply like this: return level <= LogWarning
|
|
||||||
ShouldLog func(level LogLevel) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type pipeline struct {
|
|
||||||
factories []Factory
|
|
||||||
options Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Pipeline interface represents an ordered list of Factory objects and an object implementing the HTTPSender interface.
|
|
||||||
// You construct a Pipeline by calling the pipeline.NewPipeline function. To send an HTTP request, call pipeline.NewRequest
|
|
||||||
// and then call Pipeline's Do method passing a context, the request, and a method-specific Factory (or nil). Passing a
|
|
||||||
// method-specific Factory allows this one call to Do to inject a Policy into the linked-list. The policy is injected where
|
|
||||||
// the MethodFactoryMarker (see the pipeline.MethodFactoryMarker function) is in the slice of Factory objects.
|
|
||||||
//
|
|
||||||
// When Do is called, the Pipeline object asks each Factory object to construct its Policy object and adds each Policy to a linked-list.
|
|
||||||
// THen, Do sends the Context and Request through all the Policy objects. The final Policy object sends the request over the network
|
|
||||||
// (via the HTTPSender object passed to NewPipeline) and the response is returned backwards through all the Policy objects.
|
|
||||||
// Since Pipeline and Factory objects are goroutine-safe, you typically create 1 Pipeline object and reuse it to make many HTTP requests.
|
|
||||||
type Pipeline interface {
|
|
||||||
Do(ctx context.Context, methodFactory Factory, request Request) (Response, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPipeline creates a new goroutine-safe Pipeline object from the slice of Factory objects and the specified options.
|
|
||||||
func NewPipeline(factories []Factory, o Options) Pipeline {
|
|
||||||
if o.HTTPSender == nil {
|
|
||||||
o.HTTPSender = newDefaultHTTPClientFactory()
|
|
||||||
}
|
|
||||||
if o.Log.Log == nil {
|
|
||||||
o.Log.Log = func(LogLevel, string) {} // No-op logger
|
|
||||||
}
|
|
||||||
return &pipeline{factories: factories, options: o}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do is called for each and every HTTP request. It tells each Factory to create its own (mutable) Policy object
|
|
||||||
// replacing a MethodFactoryMarker factory (if it exists) with the methodFactory passed in. Then, the Context and Request
|
|
||||||
// are sent through the pipeline of Policy objects (which can transform the Request's URL/query parameters/headers) and
|
|
||||||
// ultimately sends the transformed HTTP request over the network.
|
|
||||||
func (p *pipeline) Do(ctx context.Context, methodFactory Factory, request Request) (Response, error) {
|
|
||||||
response, err := p.newPolicies(methodFactory).Do(ctx, request)
|
|
||||||
request.close()
|
|
||||||
return response, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *pipeline) newPolicies(methodFactory Factory) Policy {
|
|
||||||
// The last Policy is the one that actually sends the request over the wire and gets the response.
|
|
||||||
// It is overridable via the Options' HTTPSender field.
|
|
||||||
po := &PolicyOptions{pipeline: p} // One object shared by all policy objects
|
|
||||||
next := p.options.HTTPSender.New(nil, po)
|
|
||||||
|
|
||||||
// Walk over the slice of Factory objects in reverse (from wire to API)
|
|
||||||
markers := 0
|
|
||||||
for i := len(p.factories) - 1; i >= 0; i-- {
|
|
||||||
factory := p.factories[i]
|
|
||||||
if _, ok := factory.(methodFactoryMarker); ok {
|
|
||||||
markers++
|
|
||||||
if markers > 1 {
|
|
||||||
panic("MethodFactoryMarker can only appear once in the pipeline")
|
|
||||||
}
|
|
||||||
if methodFactory != nil {
|
|
||||||
// Replace MethodFactoryMarker with passed-in methodFactory
|
|
||||||
next = methodFactory.New(next, po)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Use the slice's Factory to construct its Policy
|
|
||||||
next = factory.New(next, po)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each Factory has created its Policy
|
|
||||||
if markers == 0 && methodFactory != nil {
|
|
||||||
panic("Non-nil methodFactory requires MethodFactoryMarker in the pipeline")
|
|
||||||
}
|
|
||||||
return next // Return head of the Policy object linked-list
|
|
||||||
}
|
|
||||||
|
|
||||||
// A PolicyOptions represents optional information that can be used by a node in the
|
|
||||||
// linked-list of Policy objects. A PolicyOptions is passed to the Factory's New method
|
|
||||||
// which passes it (if desired) to the Policy object it creates. Today, the Policy object
|
|
||||||
// uses the options to perform logging. But, in the future, this could be used for more.
|
|
||||||
type PolicyOptions struct {
|
|
||||||
pipeline *pipeline
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShouldLog returns true if the specified log level should be logged.
|
|
||||||
func (po *PolicyOptions) ShouldLog(level LogLevel) bool {
|
|
||||||
if po.pipeline.options.Log.ShouldLog != nil {
|
|
||||||
return po.pipeline.options.Log.ShouldLog(level)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log logs a string to the Pipeline's Logger.
|
|
||||||
func (po *PolicyOptions) Log(level LogLevel, msg string) {
|
|
||||||
if !po.ShouldLog(level) {
|
|
||||||
return // Short circuit message formatting if we're not logging it
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are logging it, ensure trailing newline
|
|
||||||
if len(msg) == 0 || msg[len(msg)-1] != '\n' {
|
|
||||||
msg += "\n" // Ensure trailing newline
|
|
||||||
}
|
|
||||||
po.pipeline.options.Log.Log(level, msg)
|
|
||||||
|
|
||||||
// If logger doesn't handle fatal/panic, we'll do it here.
|
|
||||||
if level == LogFatal {
|
|
||||||
os.Exit(1)
|
|
||||||
} else if level == LogPanic {
|
|
||||||
panic(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pipelineHTTPClient = newDefaultHTTPClient()
|
|
||||||
|
|
||||||
func newDefaultHTTPClient() *http.Client {
|
|
||||||
// We want the Transport to have a large connection pool
|
|
||||||
return &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: ieproxy.GetProxyFunc(),
|
|
||||||
// We use Dial instead of DialContext as DialContext has been reported to cause slower performance.
|
|
||||||
Dial /*Context*/ : (&net.Dialer{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
DualStack: true,
|
|
||||||
}).Dial, /*Context*/
|
|
||||||
MaxIdleConns: 0, // No limit
|
|
||||||
MaxIdleConnsPerHost: 100,
|
|
||||||
IdleConnTimeout: 90 * time.Second,
|
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
|
||||||
DisableKeepAlives: false,
|
|
||||||
DisableCompression: false,
|
|
||||||
MaxResponseHeaderBytes: 0,
|
|
||||||
//ResponseHeaderTimeout: time.Duration{},
|
|
||||||
//ExpectContinueTimeout: time.Duration{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDefaultHTTPClientFactory creates a DefaultHTTPClientPolicyFactory object that sends HTTP requests to a Go's default http.Client.
|
|
||||||
func newDefaultHTTPClientFactory() Factory {
|
|
||||||
return FactoryFunc(func(next Policy, po *PolicyOptions) PolicyFunc {
|
|
||||||
return func(ctx context.Context, request Request) (Response, error) {
|
|
||||||
r, err := pipelineHTTPClient.Do(request.WithContext(ctx))
|
|
||||||
if err != nil {
|
|
||||||
err = NewError(err, "HTTP request failed")
|
|
||||||
}
|
|
||||||
return NewHTTPResponse(r), err
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var mfm = methodFactoryMarker{} // Singleton
|
|
||||||
|
|
||||||
// MethodFactoryMarker returns a special marker Factory object. When Pipeline's Do method is called, any
|
|
||||||
// MethodMarkerFactory object is replaced with the specified methodFactory object. If nil is passed fro Do's
|
|
||||||
// methodFactory parameter, then the MethodFactoryMarker is ignored as the linked-list of Policy objects is created.
|
|
||||||
func MethodFactoryMarker() Factory {
|
|
||||||
return mfm
|
|
||||||
}
|
|
||||||
|
|
||||||
type methodFactoryMarker struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (methodFactoryMarker) New(next Policy, po *PolicyOptions) Policy {
|
|
||||||
panic("methodFactoryMarker policy should have been replaced with a method policy")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogSanitizer can be implemented to clean secrets from lines logged by ForceLog
|
|
||||||
// By default no implemetation is provided here, because pipeline may be used in many different
|
|
||||||
// contexts, so the correct implementation is context-dependent
|
|
||||||
type LogSanitizer interface {
|
|
||||||
SanitizeLogMessage(raw string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
var sanitizer LogSanitizer
|
|
||||||
var enableForceLog bool = true
|
|
||||||
|
|
||||||
// SetLogSanitizer can be called to supply a custom LogSanitizer.
|
|
||||||
// There is no threadsafety or locking on the underlying variable,
|
|
||||||
// so call this function just once at startup of your application
|
|
||||||
// (Don't later try to change the sanitizer on the fly).
|
|
||||||
func SetLogSanitizer(s LogSanitizer)(){
|
|
||||||
sanitizer = s
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetForceLogEnabled can be used to disable ForceLog
|
|
||||||
// There is no threadsafety or locking on the underlying variable,
|
|
||||||
// so call this function just once at startup of your application
|
|
||||||
// (Don't later try to change the setting on the fly).
|
|
||||||
func SetForceLogEnabled(enable bool)() {
|
|
||||||
enableForceLog = enable
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
14
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog.go
generated
vendored
14
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
|
|
||||||
// ForceLog should rarely be used. It forceable logs an entry to the
|
|
||||||
// Windows Event Log (on Windows) or to the SysLog (on Linux)
|
|
||||||
func ForceLog(level LogLevel, msg string) {
|
|
||||||
if !enableForceLog {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if sanitizer != nil {
|
|
||||||
msg = sanitizer.SanitizeLogMessage(msg)
|
|
||||||
}
|
|
||||||
forceLog(level, msg)
|
|
||||||
}
|
|
33
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_syslog.go
generated
vendored
33
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_syslog.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
// +build !windows,!nacl,!plan9
|
|
||||||
|
|
||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"log/syslog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// forceLog should rarely be used. It forceable logs an entry to the
|
|
||||||
// Windows Event Log (on Windows) or to the SysLog (on Linux)
|
|
||||||
func forceLog(level LogLevel, msg string) {
|
|
||||||
if defaultLogger == nil {
|
|
||||||
return // Return fast if we failed to create the logger.
|
|
||||||
}
|
|
||||||
// We are logging it, ensure trailing newline
|
|
||||||
if len(msg) == 0 || msg[len(msg)-1] != '\n' {
|
|
||||||
msg += "\n" // Ensure trailing newline
|
|
||||||
}
|
|
||||||
switch level {
|
|
||||||
case LogFatal:
|
|
||||||
defaultLogger.Fatal(msg)
|
|
||||||
case LogPanic:
|
|
||||||
defaultLogger.Panic(msg)
|
|
||||||
case LogError, LogWarning, LogInfo:
|
|
||||||
defaultLogger.Print(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultLogger = func() *log.Logger {
|
|
||||||
l, _ := syslog.NewLogger(syslog.LOG_USER|syslog.LOG_WARNING, log.LstdFlags)
|
|
||||||
return l
|
|
||||||
}()
|
|
61
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_windows.go
generated
vendored
61
vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_windows.go
generated
vendored
@ -1,61 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// forceLog should rarely be used. It forceable logs an entry to the
|
|
||||||
// Windows Event Log (on Windows) or to the SysLog (on Linux)
|
|
||||||
func forceLog(level LogLevel, msg string) {
|
|
||||||
var el eventType
|
|
||||||
switch level {
|
|
||||||
case LogError, LogFatal, LogPanic:
|
|
||||||
el = elError
|
|
||||||
case LogWarning:
|
|
||||||
el = elWarning
|
|
||||||
case LogInfo:
|
|
||||||
el = elInfo
|
|
||||||
}
|
|
||||||
// We are logging it, ensure trailing newline
|
|
||||||
if len(msg) == 0 || msg[len(msg)-1] != '\n' {
|
|
||||||
msg += "\n" // Ensure trailing newline
|
|
||||||
}
|
|
||||||
reportEvent(el, 0, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
type eventType int16
|
|
||||||
|
|
||||||
const (
|
|
||||||
elSuccess eventType = 0
|
|
||||||
elError eventType = 1
|
|
||||||
elWarning eventType = 2
|
|
||||||
elInfo eventType = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
var reportEvent = func() func(eventType eventType, eventID int32, msg string) {
|
|
||||||
advAPI32 := syscall.MustLoadDLL("advapi32.dll") // lower case to tie in with Go's sysdll registration
|
|
||||||
registerEventSource := advAPI32.MustFindProc("RegisterEventSourceW")
|
|
||||||
|
|
||||||
sourceName, _ := os.Executable()
|
|
||||||
sourceNameUTF16, _ := syscall.UTF16PtrFromString(sourceName)
|
|
||||||
handle, _, lastErr := registerEventSource.Call(uintptr(0), uintptr(unsafe.Pointer(sourceNameUTF16)))
|
|
||||||
if lastErr == nil { // On error, logging is a no-op
|
|
||||||
return func(eventType eventType, eventID int32, msg string) {}
|
|
||||||
}
|
|
||||||
reportEvent := advAPI32.MustFindProc("ReportEventW")
|
|
||||||
return func(eventType eventType, eventID int32, msg string) {
|
|
||||||
s, _ := syscall.UTF16PtrFromString(msg)
|
|
||||||
_, _, _ = reportEvent.Call(
|
|
||||||
uintptr(handle), // HANDLE hEventLog
|
|
||||||
uintptr(eventType), // WORD wType
|
|
||||||
uintptr(0), // WORD wCategory
|
|
||||||
uintptr(eventID), // DWORD dwEventID
|
|
||||||
uintptr(0), // PSID lpUserSid
|
|
||||||
uintptr(1), // WORD wNumStrings
|
|
||||||
uintptr(0), // DWORD dwDataSize
|
|
||||||
uintptr(unsafe.Pointer(&s)), // LPCTSTR *lpStrings
|
|
||||||
uintptr(0)) // LPVOID lpRawData
|
|
||||||
}
|
|
||||||
}()
|
|
161
vendor/github.com/Azure/azure-pipeline-go/pipeline/doc.go
generated
vendored
161
vendor/github.com/Azure/azure-pipeline-go/pipeline/doc.go
generated
vendored
@ -1,161 +0,0 @@
|
|||||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
|
||||||
// Use of this source code is governed by an MIT
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package pipeline implements an HTTP request/response middleware pipeline whose
|
|
||||||
policy objects mutate an HTTP request's URL, query parameters, and/or headers before
|
|
||||||
the request is sent over the wire.
|
|
||||||
|
|
||||||
Not all policy objects mutate an HTTP request; some policy objects simply impact the
|
|
||||||
flow of requests/responses by performing operations such as logging, retry policies,
|
|
||||||
timeouts, failure injection, and deserialization of response payloads.
|
|
||||||
|
|
||||||
Implementing the Policy Interface
|
|
||||||
|
|
||||||
To implement a policy, define a struct that implements the pipeline.Policy interface's Do method. Your Do
|
|
||||||
method is called when an HTTP request wants to be sent over the network. Your Do method can perform any
|
|
||||||
operation(s) it desires. For example, it can log the outgoing request, mutate the URL, headers, and/or query
|
|
||||||
parameters, inject a failure, etc. Your Do method must then forward the HTTP request to next Policy object
|
|
||||||
in a linked-list ensuring that the remaining Policy objects perform their work. Ultimately, the last Policy
|
|
||||||
object sends the HTTP request over the network (by calling the HTTPSender's Do method).
|
|
||||||
|
|
||||||
When an HTTP response comes back, each Policy object in the linked-list gets a chance to process the response
|
|
||||||
(in reverse order). The Policy object can log the response, retry the operation if due to a transient failure
|
|
||||||
or timeout, deserialize the response body, etc. Ultimately, the last Policy object returns the HTTP response
|
|
||||||
to the code that initiated the original HTTP request.
|
|
||||||
|
|
||||||
Here is a template for how to define a pipeline.Policy object:
|
|
||||||
|
|
||||||
type myPolicy struct {
|
|
||||||
node PolicyNode
|
|
||||||
// TODO: Add configuration/setting fields here (if desired)...
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *myPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
// TODO: Mutate/process the HTTP request here...
|
|
||||||
response, err := p.node.Do(ctx, request) // Forward HTTP request to next Policy & get HTTP response
|
|
||||||
// TODO: Mutate/process the HTTP response here...
|
|
||||||
return response, err // Return response/error to previous Policy
|
|
||||||
}
|
|
||||||
|
|
||||||
Implementing the Factory Interface
|
|
||||||
|
|
||||||
Each Policy struct definition requires a factory struct definition that implements the pipeline.Factory interface's New
|
|
||||||
method. The New method is called when application code wants to initiate a new HTTP request. Factory's New method is
|
|
||||||
passed a pipeline.PolicyNode object which contains a reference to the owning pipeline.Pipeline object (discussed later) and
|
|
||||||
a reference to the next Policy object in the linked list. The New method should create its corresponding Policy object
|
|
||||||
passing it the PolicyNode and any other configuration/settings fields appropriate for the specific Policy object.
|
|
||||||
|
|
||||||
Here is a template for how to define a pipeline.Policy object:
|
|
||||||
|
|
||||||
// NOTE: Once created & initialized, Factory objects should be goroutine-safe (ex: immutable);
|
|
||||||
// this allows reuse (efficient use of memory) and makes these objects usable by multiple goroutines concurrently.
|
|
||||||
type myPolicyFactory struct {
|
|
||||||
// TODO: Add any configuration/setting fields if desired...
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *myPolicyFactory) New(node pipeline.PolicyNode) Policy {
|
|
||||||
return &myPolicy{node: node} // TODO: Also initialize any configuration/setting fields here (if desired)...
|
|
||||||
}
|
|
||||||
|
|
||||||
Using your Factory and Policy objects via a Pipeline
|
|
||||||
|
|
||||||
To use the Factory and Policy objects, an application constructs a slice of Factory objects and passes
|
|
||||||
this slice to the pipeline.NewPipeline function.
|
|
||||||
|
|
||||||
func NewPipeline(factories []pipeline.Factory, sender pipeline.HTTPSender) Pipeline
|
|
||||||
|
|
||||||
This function also requires an object implementing the HTTPSender interface. For simple scenarios,
|
|
||||||
passing nil for HTTPSender causes a standard Go http.Client object to be created and used to actually
|
|
||||||
send the HTTP response over the network. For more advanced scenarios, you can pass your own HTTPSender
|
|
||||||
object in. This allows sharing of http.Client objects or the use of custom-configured http.Client objects
|
|
||||||
or other objects that can simulate the network requests for testing purposes.
|
|
||||||
|
|
||||||
Now that you have a pipeline.Pipeline object, you can create a pipeline.Request object (which is a simple
|
|
||||||
wrapper around Go's standard http.Request object) and pass it to Pipeline's Do method along with passing a
|
|
||||||
context.Context for cancelling the HTTP request (if desired).
|
|
||||||
|
|
||||||
type Pipeline interface {
|
|
||||||
Do(ctx context.Context, methodFactory pipeline.Factory, request pipeline.Request) (pipeline.Response, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
Do iterates over the slice of Factory objects and tells each one to create its corresponding
|
|
||||||
Policy object. After the linked-list of Policy objects have been created, Do calls the first
|
|
||||||
Policy object passing it the Context & HTTP request parameters. These parameters now flow through
|
|
||||||
all the Policy objects giving each object a chance to look at and/or mutate the HTTP request.
|
|
||||||
The last Policy object sends the message over the network.
|
|
||||||
|
|
||||||
When the network operation completes, the HTTP response and error return values pass
|
|
||||||
back through the same Policy objects in reverse order. Most Policy objects ignore the
|
|
||||||
response/error but some log the result, retry the operation (depending on the exact
|
|
||||||
reason the operation failed), or deserialize the response's body. Your own Policy
|
|
||||||
objects can do whatever they like when processing outgoing requests or incoming responses.
|
|
||||||
|
|
||||||
Note that after an I/O request runs to completion, the Policy objects for that request
|
|
||||||
are garbage collected. However, Pipeline object (like Factory objects) are goroutine-safe allowing
|
|
||||||
them to be created once and reused over many I/O operations. This allows for efficient use of
|
|
||||||
memory and also makes them safely usable by multiple goroutines concurrently.
|
|
||||||
|
|
||||||
Inserting a Method-Specific Factory into the Linked-List of Policy Objects
|
|
||||||
|
|
||||||
While Pipeline and Factory objects can be reused over many different operations, it is
|
|
||||||
common to have special behavior for a specific operation/method. For example, a method
|
|
||||||
may need to deserialize the response's body to an instance of a specific data type.
|
|
||||||
To accommodate this, the Pipeline's Do method takes an additional method-specific
|
|
||||||
Factory object. The Do method tells this Factory to create a Policy object and
|
|
||||||
injects this method-specific Policy object into the linked-list of Policy objects.
|
|
||||||
|
|
||||||
When creating a Pipeline object, the slice of Factory objects passed must have 1
|
|
||||||
(and only 1) entry marking where the method-specific Factory should be injected.
|
|
||||||
The Factory marker is obtained by calling the pipeline.MethodFactoryMarker() function:
|
|
||||||
|
|
||||||
func MethodFactoryMarker() pipeline.Factory
|
|
||||||
|
|
||||||
Creating an HTTP Request Object
|
|
||||||
|
|
||||||
The HTTP request object passed to Pipeline's Do method is not Go's http.Request struct.
|
|
||||||
Instead, it is a pipeline.Request struct which is a simple wrapper around Go's standard
|
|
||||||
http.Request. You create a pipeline.Request object by calling the pipeline.NewRequest function:
|
|
||||||
|
|
||||||
func NewRequest(method string, url url.URL, options pipeline.RequestOptions) (request pipeline.Request, err error)
|
|
||||||
|
|
||||||
To this function, you must pass a pipeline.RequestOptions that looks like this:
|
|
||||||
|
|
||||||
type RequestOptions struct {
|
|
||||||
// The readable and seekable stream to be sent to the server as the request's body.
|
|
||||||
Body io.ReadSeeker
|
|
||||||
|
|
||||||
// The callback method (if not nil) to be invoked to report progress as the stream is uploaded in the HTTP request.
|
|
||||||
Progress ProgressReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
The method and struct ensure that the request's body stream is a read/seekable stream.
|
|
||||||
A seekable stream is required so that upon retry, the final Policy object can seek
|
|
||||||
the stream back to the beginning before retrying the network request and re-uploading the
|
|
||||||
body. In addition, you can associate a ProgressReceiver callback function which will be
|
|
||||||
invoked periodically to report progress while bytes are being read from the body stream
|
|
||||||
and sent over the network.
|
|
||||||
|
|
||||||
Processing the HTTP Response
|
|
||||||
|
|
||||||
When an HTTP response comes in from the network, a reference to Go's http.Response struct is
|
|
||||||
embedded in a struct that implements the pipeline.Response interface:
|
|
||||||
|
|
||||||
type Response interface {
|
|
||||||
Response() *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
This interface is returned through all the Policy objects. Each Policy object can call the Response
|
|
||||||
interface's Response method to examine (or mutate) the embedded http.Response object.
|
|
||||||
|
|
||||||
A Policy object can internally define another struct (implementing the pipeline.Response interface)
|
|
||||||
that embeds an http.Response and adds additional fields and return this structure to other Policy
|
|
||||||
objects. This allows a Policy object to deserialize the body to some other struct and return the
|
|
||||||
original http.Response and the additional struct back through the Policy chain. Other Policy objects
|
|
||||||
can see the Response but cannot see the additional struct with the deserialized body. After all the
|
|
||||||
Policy objects have returned, the pipeline.Response interface is returned by Pipeline's Do method.
|
|
||||||
The caller of this method can perform a type assertion attempting to get back to the struct type
|
|
||||||
really returned by the Policy object. If the type assertion is successful, the caller now has
|
|
||||||
access to both the http.Response and the deserialized struct object.*/
|
|
||||||
package pipeline
|
|
181
vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go
generated
vendored
181
vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go
generated
vendored
@ -1,181 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
type causer interface {
|
|
||||||
Cause() error
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorWithPC(msg string, pc uintptr) string {
|
|
||||||
s := ""
|
|
||||||
if fn := runtime.FuncForPC(pc); fn != nil {
|
|
||||||
file, line := fn.FileLine(pc)
|
|
||||||
s = fmt.Sprintf("-> %v, %v:%v\n", fn.Name(), file, line)
|
|
||||||
}
|
|
||||||
s += msg + "\n\n"
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPC(callersToSkip int) uintptr {
|
|
||||||
// Get the PC of Initialize method's caller.
|
|
||||||
pc := [1]uintptr{}
|
|
||||||
_ = runtime.Callers(callersToSkip, pc[:])
|
|
||||||
return pc[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorNode can be an embedded field in a private error object. This field
|
|
||||||
// adds Program Counter support and a 'cause' (reference to a preceding error).
|
|
||||||
// When initializing a error type with this embedded field, initialize the
|
|
||||||
// ErrorNode field by calling ErrorNode{}.Initialize(cause).
|
|
||||||
type ErrorNode struct {
|
|
||||||
pc uintptr // Represents a Program Counter that you can get symbols for.
|
|
||||||
cause error // Refers to the preceding error (or nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns a string with the PC's symbols or "" if the PC is invalid.
|
|
||||||
// When defining a new error type, have its Error method call this one passing
|
|
||||||
// it the string representation of the error.
|
|
||||||
func (e *ErrorNode) Error(msg string) string {
|
|
||||||
s := errorWithPC(msg, e.pc)
|
|
||||||
if e.cause != nil {
|
|
||||||
s += e.cause.Error() + "\n"
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cause returns the error that preceded this error.
|
|
||||||
func (e *ErrorNode) Cause() error { return e.cause }
|
|
||||||
|
|
||||||
// Temporary returns true if the error occurred due to a temporary condition.
|
|
||||||
func (e ErrorNode) Temporary() bool {
|
|
||||||
type temporary interface {
|
|
||||||
Temporary() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
for err := e.cause; err != nil; {
|
|
||||||
if t, ok := err.(temporary); ok {
|
|
||||||
return t.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
if cause, ok := err.(causer); ok {
|
|
||||||
err = cause.Cause()
|
|
||||||
} else {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeout returns true if the error occurred due to time expiring.
|
|
||||||
func (e ErrorNode) Timeout() bool {
|
|
||||||
type timeout interface {
|
|
||||||
Timeout() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
for err := e.cause; err != nil; {
|
|
||||||
if t, ok := err.(timeout); ok {
|
|
||||||
return t.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
if cause, ok := err.(causer); ok {
|
|
||||||
err = cause.Cause()
|
|
||||||
} else {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize is used to initialize an embedded ErrorNode field.
|
|
||||||
// It captures the caller's program counter and saves the cause (preceding error).
|
|
||||||
// To initialize the field, use "ErrorNode{}.Initialize(cause, 3)". A callersToSkip
|
|
||||||
// value of 3 is very common; but, depending on your code nesting, you may need
|
|
||||||
// a different value.
|
|
||||||
func (ErrorNode) Initialize(cause error, callersToSkip int) ErrorNode {
|
|
||||||
pc := getPC(callersToSkip)
|
|
||||||
return ErrorNode{pc: pc, cause: cause}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cause walks all the preceding errors and return the originating error.
|
|
||||||
func Cause(err error) error {
|
|
||||||
for err != nil {
|
|
||||||
cause, ok := err.(causer)
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
err = cause.Cause()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorNodeNoCause can be an embedded field in a private error object. This field
|
|
||||||
// adds Program Counter support.
|
|
||||||
// When initializing a error type with this embedded field, initialize the
|
|
||||||
// ErrorNodeNoCause field by calling ErrorNodeNoCause{}.Initialize().
|
|
||||||
type ErrorNodeNoCause struct {
|
|
||||||
pc uintptr // Represents a Program Counter that you can get symbols for.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns a string with the PC's symbols or "" if the PC is invalid.
|
|
||||||
// When defining a new error type, have its Error method call this one passing
|
|
||||||
// it the string representation of the error.
|
|
||||||
func (e *ErrorNodeNoCause) Error(msg string) string {
|
|
||||||
return errorWithPC(msg, e.pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary returns true if the error occurred due to a temporary condition.
|
|
||||||
func (e ErrorNodeNoCause) Temporary() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeout returns true if the error occurred due to time expiring.
|
|
||||||
func (e ErrorNodeNoCause) Timeout() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize is used to initialize an embedded ErrorNode field.
|
|
||||||
// It captures the caller's program counter.
|
|
||||||
// To initialize the field, use "ErrorNodeNoCause{}.Initialize(3)". A callersToSkip
|
|
||||||
// value of 3 is very common; but, depending on your code nesting, you may need
|
|
||||||
// a different value.
|
|
||||||
func (ErrorNodeNoCause) Initialize(callersToSkip int) ErrorNodeNoCause {
|
|
||||||
pc := getPC(callersToSkip)
|
|
||||||
return ErrorNodeNoCause{pc: pc}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewError creates a simple string error (like Error.New). But, this
|
|
||||||
// error also captures the caller's Program Counter and the preceding error (if provided).
|
|
||||||
func NewError(cause error, msg string) error {
|
|
||||||
if cause != nil {
|
|
||||||
return &pcError{
|
|
||||||
ErrorNode: ErrorNode{}.Initialize(cause, 3),
|
|
||||||
msg: msg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &pcErrorNoCause{
|
|
||||||
ErrorNodeNoCause: ErrorNodeNoCause{}.Initialize(3),
|
|
||||||
msg: msg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pcError is a simple string error (like error.New) with an ErrorNode (PC & cause).
|
|
||||||
type pcError struct {
|
|
||||||
ErrorNode
|
|
||||||
msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error satisfies the error interface. It shows the error with Program Counter
|
|
||||||
// symbols and calls Error on the preceding error so you can see the full error chain.
|
|
||||||
func (e *pcError) Error() string { return e.ErrorNode.Error(e.msg) }
|
|
||||||
|
|
||||||
// pcErrorNoCause is a simple string error (like error.New) with an ErrorNode (PC).
|
|
||||||
type pcErrorNoCause struct {
|
|
||||||
ErrorNodeNoCause
|
|
||||||
msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error satisfies the error interface. It shows the error with Program Counter symbols.
|
|
||||||
func (e *pcErrorNoCause) Error() string { return e.ErrorNodeNoCause.Error(e.msg) }
|
|
82
vendor/github.com/Azure/azure-pipeline-go/pipeline/progress.go
generated
vendored
82
vendor/github.com/Azure/azure-pipeline-go/pipeline/progress.go
generated
vendored
@ -1,82 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// ********** The following is common between the request body AND the response body.
|
|
||||||
|
|
||||||
// ProgressReceiver defines the signature of a callback function invoked as progress is reported.
|
|
||||||
type ProgressReceiver func(bytesTransferred int64)
|
|
||||||
|
|
||||||
// ********** The following are specific to the request body (a ReadSeekCloser)
|
|
||||||
|
|
||||||
// This struct is used when sending a body to the network
|
|
||||||
type requestBodyProgress struct {
|
|
||||||
requestBody io.ReadSeeker // Seeking is required to support retries
|
|
||||||
pr ProgressReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRequestBodyProgress adds progress reporting to an HTTP request's body stream.
|
|
||||||
func NewRequestBodyProgress(requestBody io.ReadSeeker, pr ProgressReceiver) io.ReadSeeker {
|
|
||||||
if pr == nil {
|
|
||||||
panic("pr must not be nil")
|
|
||||||
}
|
|
||||||
return &requestBodyProgress{requestBody: requestBody, pr: pr}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read reads a block of data from an inner stream and reports progress
|
|
||||||
func (rbp *requestBodyProgress) Read(p []byte) (n int, err error) {
|
|
||||||
n, err = rbp.requestBody.Read(p)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Invokes the user's callback method to report progress
|
|
||||||
position, err := rbp.requestBody.Seek(0, io.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
rbp.pr(position)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rbp *requestBodyProgress) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
|
|
||||||
return rbp.requestBody.Seek(offset, whence)
|
|
||||||
}
|
|
||||||
|
|
||||||
// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it.
|
|
||||||
func (rbp *requestBodyProgress) Close() error {
|
|
||||||
if c, ok := rbp.requestBody.(io.Closer); ok {
|
|
||||||
return c.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ********** The following are specific to the response body (a ReadCloser)
|
|
||||||
|
|
||||||
// This struct is used when sending a body to the network
|
|
||||||
type responseBodyProgress struct {
|
|
||||||
responseBody io.ReadCloser
|
|
||||||
pr ProgressReceiver
|
|
||||||
offset int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResponseBodyProgress adds progress reporting to an HTTP response's body stream.
|
|
||||||
func NewResponseBodyProgress(responseBody io.ReadCloser, pr ProgressReceiver) io.ReadCloser {
|
|
||||||
if pr == nil {
|
|
||||||
panic("pr must not be nil")
|
|
||||||
}
|
|
||||||
return &responseBodyProgress{responseBody: responseBody, pr: pr, offset: 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read reads a block of data from an inner stream and reports progress
|
|
||||||
func (rbp *responseBodyProgress) Read(p []byte) (n int, err error) {
|
|
||||||
n, err = rbp.responseBody.Read(p)
|
|
||||||
rbp.offset += int64(n)
|
|
||||||
|
|
||||||
// Invokes the user's callback method to report progress
|
|
||||||
rbp.pr(rbp.offset)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rbp *responseBodyProgress) Close() error {
|
|
||||||
return rbp.responseBody.Close()
|
|
||||||
}
|
|
147
vendor/github.com/Azure/azure-pipeline-go/pipeline/request.go
generated
vendored
147
vendor/github.com/Azure/azure-pipeline-go/pipeline/request.go
generated
vendored
@ -1,147 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Request is a thin wrapper over an http.Request. The wrapper provides several helper methods.
|
|
||||||
type Request struct {
|
|
||||||
*http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRequest initializes a new HTTP request object with any desired options.
|
|
||||||
func NewRequest(method string, url url.URL, body io.ReadSeeker) (request Request, err error) {
|
|
||||||
// Note: the url is passed by value so that any pipeline operations that modify it do so on a copy.
|
|
||||||
|
|
||||||
// This code to construct an http.Request is copied from http.NewRequest(); we intentionally omitted removeEmptyPort for now.
|
|
||||||
request.Request = &http.Request{
|
|
||||||
Method: method,
|
|
||||||
URL: &url,
|
|
||||||
Proto: "HTTP/1.1",
|
|
||||||
ProtoMajor: 1,
|
|
||||||
ProtoMinor: 1,
|
|
||||||
Header: make(http.Header),
|
|
||||||
Host: url.Host,
|
|
||||||
}
|
|
||||||
|
|
||||||
if body != nil {
|
|
||||||
err = request.SetBody(body)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBody sets the body and content length, assumes body is not nil.
|
|
||||||
func (r Request) SetBody(body io.ReadSeeker) error {
|
|
||||||
size, err := body.Seek(0, io.SeekEnd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
body.Seek(0, io.SeekStart)
|
|
||||||
r.ContentLength = size
|
|
||||||
r.Header["Content-Length"] = []string{strconv.FormatInt(size, 10)}
|
|
||||||
|
|
||||||
if size != 0 {
|
|
||||||
r.Body = &retryableRequestBody{body: body}
|
|
||||||
r.GetBody = func() (io.ReadCloser, error) {
|
|
||||||
_, err := body.Seek(0, io.SeekStart)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return r.Body, nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// in case the body is an empty stream, we need to use http.NoBody to explicitly provide no content
|
|
||||||
r.Body = http.NoBody
|
|
||||||
r.GetBody = func() (io.ReadCloser, error) {
|
|
||||||
return http.NoBody, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the user-provided empty body
|
|
||||||
if c, ok := body.(io.Closer); ok {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy makes a copy of an http.Request. Specifically, it makes a deep copy
|
|
||||||
// of its Method, URL, Host, Proto(Major/Minor), Header. ContentLength, Close,
|
|
||||||
// RemoteAddr, RequestURI. Copy makes a shallow copy of the Body, GetBody, TLS,
|
|
||||||
// Cancel, Response, and ctx fields. Copy panics if any of these fields are
|
|
||||||
// not nil: TransferEncoding, Form, PostForm, MultipartForm, or Trailer.
|
|
||||||
func (r Request) Copy() Request {
|
|
||||||
if r.TransferEncoding != nil || r.Form != nil || r.PostForm != nil || r.MultipartForm != nil || r.Trailer != nil {
|
|
||||||
panic("Can't make a deep copy of the http.Request because at least one of the following is not nil:" +
|
|
||||||
"TransferEncoding, Form, PostForm, MultipartForm, or Trailer.")
|
|
||||||
}
|
|
||||||
copy := *r.Request // Copy the request
|
|
||||||
urlCopy := *(r.Request.URL) // Copy the URL
|
|
||||||
copy.URL = &urlCopy
|
|
||||||
copy.Header = http.Header{} // Copy the header
|
|
||||||
for k, vs := range r.Header {
|
|
||||||
for _, value := range vs {
|
|
||||||
copy.Header.Add(k, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Request{Request: ©} // Return the copy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Request) close() error {
|
|
||||||
if r.Body != nil && r.Body != http.NoBody {
|
|
||||||
c, ok := r.Body.(*retryableRequestBody)
|
|
||||||
if !ok {
|
|
||||||
panic("unexpected request body type (should be *retryableReadSeekerCloser)")
|
|
||||||
}
|
|
||||||
return c.realClose()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RewindBody seeks the request's Body stream back to the beginning so it can be resent when retrying an operation.
|
|
||||||
func (r Request) RewindBody() error {
|
|
||||||
if r.Body != nil && r.Body != http.NoBody {
|
|
||||||
s, ok := r.Body.(io.Seeker)
|
|
||||||
if !ok {
|
|
||||||
panic("unexpected request body type (should be io.Seeker)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the stream back to the beginning
|
|
||||||
_, err := s.Seek(0, io.SeekStart)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ********** The following type/methods implement the retryableRequestBody (a ReadSeekCloser)
|
|
||||||
|
|
||||||
// This struct is used when sending a body to the network
|
|
||||||
type retryableRequestBody struct {
|
|
||||||
body io.ReadSeeker // Seeking is required to support retries
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read reads a block of data from an inner stream and reports progress
|
|
||||||
func (b *retryableRequestBody) Read(p []byte) (n int, err error) {
|
|
||||||
return b.body.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *retryableRequestBody) Seek(offset int64, whence int) (offsetFromStart int64, err error) {
|
|
||||||
return b.body.Seek(offset, whence)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *retryableRequestBody) Close() error {
|
|
||||||
// We don't want the underlying transport to close the request body on transient failures so this is a nop.
|
|
||||||
// The pipeline closes the request body upon success.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *retryableRequestBody) realClose() error {
|
|
||||||
if c, ok := b.body.(io.Closer); ok {
|
|
||||||
return c.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
74
vendor/github.com/Azure/azure-pipeline-go/pipeline/response.go
generated
vendored
74
vendor/github.com/Azure/azure-pipeline-go/pipeline/response.go
generated
vendored
@ -1,74 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The Response interface exposes an http.Response object as it returns through the pipeline of Policy objects.
|
|
||||||
// This ensures that Policy objects have access to the HTTP response. However, the object this interface encapsulates
|
|
||||||
// might be a struct with additional fields that is created by a Policy object (typically a method-specific Factory).
|
|
||||||
// The method that injected the method-specific Factory gets this returned Response and performs a type assertion
|
|
||||||
// to the expected struct and returns the struct to its caller.
|
|
||||||
type Response interface {
|
|
||||||
Response() *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the default struct that has the http.Response.
|
|
||||||
// A method can replace this struct with its own struct containing an http.Response
|
|
||||||
// field and any other additional fields.
|
|
||||||
type httpResponse struct {
|
|
||||||
response *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHTTPResponse is typically called by a Policy object to return a Response object.
|
|
||||||
func NewHTTPResponse(response *http.Response) Response {
|
|
||||||
return &httpResponse{response: response}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method satisfies the public Response interface's Response method
|
|
||||||
func (r httpResponse) Response() *http.Response {
|
|
||||||
return r.response
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are
|
|
||||||
// not nil, then these are also written into the Buffer.
|
|
||||||
func WriteRequestWithResponse(b *bytes.Buffer, request *http.Request, response *http.Response, err error) {
|
|
||||||
// Write the request into the buffer.
|
|
||||||
fmt.Fprint(b, " "+request.Method+" "+request.URL.String()+"\n")
|
|
||||||
writeHeader(b, request.Header)
|
|
||||||
if response != nil {
|
|
||||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
|
||||||
fmt.Fprint(b, " RESPONSE Status: "+response.Status+"\n")
|
|
||||||
writeHeader(b, response.Header)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(b, " --------------------------------------------------------------------------------")
|
|
||||||
fmt.Fprint(b, " ERROR:\n"+err.Error()+"\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatHeaders appends an HTTP request's or response's header into a Buffer.
|
|
||||||
func writeHeader(b *bytes.Buffer, header map[string][]string) {
|
|
||||||
if len(header) == 0 {
|
|
||||||
b.WriteString(" (no headers)\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keys := make([]string, 0, len(header))
|
|
||||||
// Alphabetize the headers
|
|
||||||
for k := range header {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
// Redact the value of any Authorization header to prevent security information from persisting in logs
|
|
||||||
value := interface{}("REDACTED")
|
|
||||||
if !strings.EqualFold(k, "Authorization") {
|
|
||||||
value = header[k]
|
|
||||||
}
|
|
||||||
fmt.Fprintf(b, " %s: %+v\n", k, value)
|
|
||||||
}
|
|
||||||
}
|
|
9
vendor/github.com/Azure/azure-pipeline-go/pipeline/version.go
generated
vendored
9
vendor/github.com/Azure/azure-pipeline-go/pipeline/version.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
const (
|
|
||||||
// UserAgent is the string to be used in the user agent string when making requests.
|
|
||||||
UserAgent = "azure-pipeline-go/" + Version
|
|
||||||
|
|
||||||
// Version is the semantic version (see http://semver.org) of the pipeline package.
|
|
||||||
Version = "0.2.1"
|
|
||||||
)
|
|
21
vendor/github.com/Azure/azure-storage-blob-go/LICENSE
generated
vendored
21
vendor/github.com/Azure/azure-storage-blob-go/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE
|
|
65
vendor/github.com/Azure/azure-storage-blob-go/azblob/access_conditions.go
generated
vendored
65
vendor/github.com/Azure/azure-storage-blob-go/azblob/access_conditions.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ModifiedAccessConditions identifies standard HTTP access conditions which you optionally set.
|
|
||||||
type ModifiedAccessConditions struct {
|
|
||||||
IfModifiedSince time.Time
|
|
||||||
IfUnmodifiedSince time.Time
|
|
||||||
IfMatch ETag
|
|
||||||
IfNoneMatch ETag
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointers is for internal infrastructure. It returns the fields as pointers.
|
|
||||||
func (ac ModifiedAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *ETag, inme *ETag) {
|
|
||||||
if !ac.IfModifiedSince.IsZero() {
|
|
||||||
ims = &ac.IfModifiedSince
|
|
||||||
}
|
|
||||||
if !ac.IfUnmodifiedSince.IsZero() {
|
|
||||||
ius = &ac.IfUnmodifiedSince
|
|
||||||
}
|
|
||||||
if ac.IfMatch != ETagNone {
|
|
||||||
ime = &ac.IfMatch
|
|
||||||
}
|
|
||||||
if ac.IfNoneMatch != ETagNone {
|
|
||||||
inme = &ac.IfNoneMatch
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerAccessConditions identifies container-specific access conditions which you optionally set.
|
|
||||||
type ContainerAccessConditions struct {
|
|
||||||
ModifiedAccessConditions
|
|
||||||
LeaseAccessConditions
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobAccessConditions identifies blob-specific access conditions which you optionally set.
|
|
||||||
type BlobAccessConditions struct {
|
|
||||||
ModifiedAccessConditions
|
|
||||||
LeaseAccessConditions
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaseAccessConditions identifies lease access conditions for a container or blob which you optionally set.
|
|
||||||
type LeaseAccessConditions struct {
|
|
||||||
LeaseID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointers is for internal infrastructure. It returns the fields as pointers.
|
|
||||||
func (ac LeaseAccessConditions) pointers() (leaseID *string) {
|
|
||||||
if ac.LeaseID != "" {
|
|
||||||
leaseID = &ac.LeaseID
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// getInt32 is for internal infrastructure. It is used with access condition values where
|
|
||||||
// 0 (the default setting) is meaningful. The library interprets 0 as do not send the header
|
|
||||||
// and the privately-storage field in the access condition object is stored as +1 higher than desired.
|
|
||||||
// THis method returns true, if the value is > 0 (explicitly set) and the stored value - 1 (the set desired value).
|
|
||||||
func getInt32(value int32) (bool, int32) {
|
|
||||||
return value > 0, value - 1
|
|
||||||
}
|
|
||||||
*/
|
|
8009
vendor/github.com/Azure/azure-storage-blob-go/azblob/blob.json
generated
vendored
8009
vendor/github.com/Azure/azure-storage-blob-go/azblob/blob.json
generated
vendored
File diff suppressed because it is too large
Load Diff
238
vendor/github.com/Azure/azure-storage-blob-go/azblob/chunkwriting.go
generated
vendored
238
vendor/github.com/Azure/azure-storage-blob-go/azblob/chunkwriting.go
generated
vendored
@ -1,238 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
guuid "github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// blockWriter provides methods to upload blocks that represent a file to a server and commit them.
|
|
||||||
// This allows us to provide a local implementation that fakes the server for hermetic testing.
|
|
||||||
type blockWriter interface {
|
|
||||||
StageBlock(context.Context, string, io.ReadSeeker, LeaseAccessConditions, []byte) (*BlockBlobStageBlockResponse, error)
|
|
||||||
CommitBlockList(context.Context, []string, BlobHTTPHeaders, Metadata, BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyFromReader copies a source io.Reader to blob storage using concurrent uploads.
|
|
||||||
// TODO(someone): The existing model provides a buffer size and buffer limit as limiting factors. The buffer size is probably
|
|
||||||
// useless other than needing to be above some number, as the network stack is going to hack up the buffer over some size. The
|
|
||||||
// max buffers is providing a cap on how much memory we use (by multiplying it times the buffer size) and how many go routines can upload
|
|
||||||
// at a time. I think having a single max memory dial would be more efficient. We can choose an internal buffer size that works
|
|
||||||
// well, 4 MiB or 8 MiB, and autoscale to as many goroutines within the memory limit. This gives a single dial to tweak and we can
|
|
||||||
// choose a max value for the memory setting based on internal transfers within Azure (which will give us the maximum throughput model).
|
|
||||||
// We can even provide a utility to dial this number in for customer networks to optimize their copies.
|
|
||||||
func copyFromReader(ctx context.Context, from io.Reader, to blockWriter, o UploadStreamToBlockBlobOptions) (*BlockBlobCommitBlockListResponse, error) {
|
|
||||||
o.defaults()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
cp := &copier{
|
|
||||||
ctx: ctx,
|
|
||||||
cancel: cancel,
|
|
||||||
reader: from,
|
|
||||||
to: to,
|
|
||||||
id: newID(),
|
|
||||||
o: o,
|
|
||||||
ch: make(chan copierChunk, 1),
|
|
||||||
errCh: make(chan error, 1),
|
|
||||||
buffers: sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return make([]byte, o.BufferSize)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts the pools of concurrent writers.
|
|
||||||
cp.wg.Add(o.MaxBuffers)
|
|
||||||
for i := 0; i < o.MaxBuffers; i++ {
|
|
||||||
go cp.writer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all our chunks until we get an error.
|
|
||||||
var err error
|
|
||||||
for {
|
|
||||||
if err = cp.sendChunk(); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the error is not EOF, then we have a problem.
|
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close out our upload.
|
|
||||||
if err := cp.close(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cp.result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// copier streams a file via chunks in parallel from a reader representing a file.
|
|
||||||
// Do not use directly, instead use copyFromReader().
|
|
||||||
type copier struct {
|
|
||||||
// ctx holds the context of a copier. This is normally a faux pas to store a Context in a struct. In this case,
|
|
||||||
// the copier has the lifetime of a function call, so its fine.
|
|
||||||
ctx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
|
|
||||||
// reader is the source to be written to storage.
|
|
||||||
reader io.Reader
|
|
||||||
// to is the location we are writing our chunks to.
|
|
||||||
to blockWriter
|
|
||||||
|
|
||||||
id *id
|
|
||||||
o UploadStreamToBlockBlobOptions
|
|
||||||
|
|
||||||
// num is the current chunk we are on.
|
|
||||||
num int32
|
|
||||||
// ch is used to pass the next chunk of data from our reader to one of the writers.
|
|
||||||
ch chan copierChunk
|
|
||||||
// errCh is used to hold the first error from our concurrent writers.
|
|
||||||
errCh chan error
|
|
||||||
// wg provides a count of how many writers we are waiting to finish.
|
|
||||||
wg sync.WaitGroup
|
|
||||||
// buffers provides a pool of chunks that can be reused.
|
|
||||||
buffers sync.Pool
|
|
||||||
|
|
||||||
// result holds the final result from blob storage after we have submitted all chunks.
|
|
||||||
result *BlockBlobCommitBlockListResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
type copierChunk struct {
|
|
||||||
buffer []byte
|
|
||||||
id string
|
|
||||||
}
|
|
||||||
|
|
||||||
// getErr returns an error by priority. First, if a function set an error, it returns that error. Next, if the Context has an error
|
|
||||||
// it returns that error. Otherwise it is nil. getErr supports only returning an error once per copier.
|
|
||||||
func (c *copier) getErr() error {
|
|
||||||
select {
|
|
||||||
case err := <-c.errCh:
|
|
||||||
return err
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return c.ctx.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendChunk reads data from out internal reader, creates a chunk, and sends it to be written via a channel.
|
|
||||||
// sendChunk returns io.EOF when the reader returns an io.EOF or io.ErrUnexpectedEOF.
|
|
||||||
func (c *copier) sendChunk() error {
|
|
||||||
if err := c.getErr(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer := c.buffers.Get().([]byte)
|
|
||||||
n, err := io.ReadFull(c.reader, buffer)
|
|
||||||
switch {
|
|
||||||
case err == nil && n == 0:
|
|
||||||
return nil
|
|
||||||
case err == nil:
|
|
||||||
c.ch <- copierChunk{
|
|
||||||
buffer: buffer[0:n],
|
|
||||||
id: c.id.next(),
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
case err != nil && (err == io.EOF || err == io.ErrUnexpectedEOF) && n == 0:
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
|
||||||
c.ch <- copierChunk{
|
|
||||||
buffer: buffer[0:n],
|
|
||||||
id: c.id.next(),
|
|
||||||
}
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
if err := c.getErr(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// writer writes chunks sent on a channel.
|
|
||||||
func (c *copier) writer() {
|
|
||||||
defer c.wg.Done()
|
|
||||||
|
|
||||||
for chunk := range c.ch {
|
|
||||||
if err := c.write(chunk); err != nil {
|
|
||||||
if !errors.Is(err, context.Canceled) {
|
|
||||||
select {
|
|
||||||
case c.errCh <- err:
|
|
||||||
c.cancel()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write uploads a chunk to blob storage.
|
|
||||||
func (c *copier) write(chunk copierChunk) error {
|
|
||||||
defer c.buffers.Put(chunk.buffer)
|
|
||||||
|
|
||||||
if err := c.ctx.Err(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := c.to.StageBlock(c.ctx, chunk.id, bytes.NewReader(chunk.buffer), LeaseAccessConditions{}, nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("write error: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// close commits our blocks to blob storage and closes our writer.
|
|
||||||
func (c *copier) close() error {
|
|
||||||
close(c.ch)
|
|
||||||
c.wg.Wait()
|
|
||||||
|
|
||||||
if err := c.getErr(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
c.result, err = c.to.CommitBlockList(c.ctx, c.id.issued(), c.o.BlobHTTPHeaders, c.o.Metadata, c.o.AccessConditions)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// id allows the creation of unique IDs based on UUID4 + an int32. This autoincrements.
|
|
||||||
type id struct {
|
|
||||||
u [64]byte
|
|
||||||
num uint32
|
|
||||||
all []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newID constructs a new id.
|
|
||||||
func newID() *id {
|
|
||||||
uu := guuid.New()
|
|
||||||
u := [64]byte{}
|
|
||||||
copy(u[:], uu[:])
|
|
||||||
return &id{u: u}
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns the next ID. This is not thread-safe.
|
|
||||||
func (id *id) next() string {
|
|
||||||
defer func() { id.num++ }()
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32((id.u[len(guuid.UUID{}):]), id.num)
|
|
||||||
str := base64.StdEncoding.EncodeToString(id.u[:])
|
|
||||||
id.all = append(id.all, str)
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// issued returns all ids that have been issued. This returned value shares the internal slice so it is not safe to modify the return.
|
|
||||||
// The value is only valid until the next time next() is called.
|
|
||||||
func (id *id) issued() []string {
|
|
||||||
return id.all
|
|
||||||
}
|
|
396
vendor/github.com/Azure/azure-storage-blob-go/azblob/highlevel.go
generated
vendored
396
vendor/github.com/Azure/azure-storage-blob-go/azblob/highlevel.go
generated
vendored
@ -1,396 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CommonResponse returns the headers common to all blob REST API responses.
|
|
||||||
type CommonResponse interface {
|
|
||||||
// ETag returns the value for header ETag.
|
|
||||||
ETag() ETag
|
|
||||||
|
|
||||||
// LastModified returns the value for header Last-Modified.
|
|
||||||
LastModified() time.Time
|
|
||||||
|
|
||||||
// RequestID returns the value for header x-ms-request-id.
|
|
||||||
RequestID() string
|
|
||||||
|
|
||||||
// Date returns the value for header Date.
|
|
||||||
Date() time.Time
|
|
||||||
|
|
||||||
// Version returns the value for header x-ms-version.
|
|
||||||
Version() string
|
|
||||||
|
|
||||||
// Response returns the raw HTTP response object.
|
|
||||||
Response() *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadToBlockBlobOptions identifies options used by the UploadBufferToBlockBlob and UploadFileToBlockBlob functions.
|
|
||||||
type UploadToBlockBlobOptions struct {
|
|
||||||
// BlockSize specifies the block size to use; the default (and maximum size) is BlockBlobMaxStageBlockBytes.
|
|
||||||
BlockSize int64
|
|
||||||
|
|
||||||
// Progress is a function that is invoked periodically as bytes are sent to the BlockBlobURL.
|
|
||||||
// Note that the progress reporting is not always increasing; it can go down when retrying a request.
|
|
||||||
Progress pipeline.ProgressReceiver
|
|
||||||
|
|
||||||
// BlobHTTPHeaders indicates the HTTP headers to be associated with the blob.
|
|
||||||
BlobHTTPHeaders BlobHTTPHeaders
|
|
||||||
|
|
||||||
// Metadata indicates the metadata to be associated with the blob when PutBlockList is called.
|
|
||||||
Metadata Metadata
|
|
||||||
|
|
||||||
// AccessConditions indicates the access conditions for the block blob.
|
|
||||||
AccessConditions BlobAccessConditions
|
|
||||||
|
|
||||||
// Parallelism indicates the maximum number of blocks to upload in parallel (0=default)
|
|
||||||
Parallelism uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadBufferToBlockBlob uploads a buffer in blocks to a block blob.
|
|
||||||
func UploadBufferToBlockBlob(ctx context.Context, b []byte,
|
|
||||||
blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) {
|
|
||||||
bufferSize := int64(len(b))
|
|
||||||
if o.BlockSize == 0 {
|
|
||||||
// If bufferSize > (BlockBlobMaxStageBlockBytes * BlockBlobMaxBlocks), then error
|
|
||||||
if bufferSize > BlockBlobMaxStageBlockBytes*BlockBlobMaxBlocks {
|
|
||||||
return nil, errors.New("buffer is too large to upload to a block blob")
|
|
||||||
}
|
|
||||||
// If bufferSize <= BlockBlobMaxUploadBlobBytes, then Upload should be used with just 1 I/O request
|
|
||||||
if bufferSize <= BlockBlobMaxUploadBlobBytes {
|
|
||||||
o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified
|
|
||||||
} else {
|
|
||||||
o.BlockSize = bufferSize / BlockBlobMaxBlocks // buffer / max blocks = block size to use all 50,000 blocks
|
|
||||||
if o.BlockSize < BlobDefaultDownloadBlockSize { // If the block size is smaller than 4MB, round up to 4MB
|
|
||||||
o.BlockSize = BlobDefaultDownloadBlockSize
|
|
||||||
}
|
|
||||||
// StageBlock will be called with blockSize blocks and a Parallelism of (BufferSize / BlockSize).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bufferSize <= BlockBlobMaxUploadBlobBytes {
|
|
||||||
// If the size can fit in 1 Upload call, do it this way
|
|
||||||
var body io.ReadSeeker = bytes.NewReader(b)
|
|
||||||
if o.Progress != nil {
|
|
||||||
body = pipeline.NewRequestBodyProgress(body, o.Progress)
|
|
||||||
}
|
|
||||||
return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions)
|
|
||||||
}
|
|
||||||
|
|
||||||
var numBlocks = uint16(((bufferSize - 1) / o.BlockSize) + 1)
|
|
||||||
|
|
||||||
blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs
|
|
||||||
progress := int64(0)
|
|
||||||
progressLock := &sync.Mutex{}
|
|
||||||
|
|
||||||
err := DoBatchTransfer(ctx, BatchTransferOptions{
|
|
||||||
OperationName: "UploadBufferToBlockBlob",
|
|
||||||
TransferSize: bufferSize,
|
|
||||||
ChunkSize: o.BlockSize,
|
|
||||||
Parallelism: o.Parallelism,
|
|
||||||
Operation: func(offset int64, count int64, ctx context.Context) error {
|
|
||||||
// This function is called once per block.
|
|
||||||
// It is passed this block's offset within the buffer and its count of bytes
|
|
||||||
// Prepare to read the proper block/section of the buffer
|
|
||||||
var body io.ReadSeeker = bytes.NewReader(b[offset : offset+count])
|
|
||||||
blockNum := offset / o.BlockSize
|
|
||||||
if o.Progress != nil {
|
|
||||||
blockProgress := int64(0)
|
|
||||||
body = pipeline.NewRequestBodyProgress(body,
|
|
||||||
func(bytesTransferred int64) {
|
|
||||||
diff := bytesTransferred - blockProgress
|
|
||||||
blockProgress = bytesTransferred
|
|
||||||
progressLock.Lock() // 1 goroutine at a time gets a progress report
|
|
||||||
progress += diff
|
|
||||||
o.Progress(progress)
|
|
||||||
progressLock.Unlock()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block IDs are unique values to avoid issue if 2+ clients are uploading blocks
|
|
||||||
// at the same time causing PutBlockList to get a mix of blocks from all the clients.
|
|
||||||
blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes())
|
|
||||||
_, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions, nil)
|
|
||||||
return err
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// All put blocks were successful, call Put Block List to finalize the blob
|
|
||||||
return blockBlobURL.CommitBlockList(ctx, blockIDList, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadFileToBlockBlob uploads a file in blocks to a block blob.
|
|
||||||
func UploadFileToBlockBlob(ctx context.Context, file *os.File,
|
|
||||||
blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) {
|
|
||||||
|
|
||||||
stat, err := file.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m := mmf{} // Default to an empty slice; used for 0-size file
|
|
||||||
if stat.Size() != 0 {
|
|
||||||
m, err = newMMF(file, false, 0, int(stat.Size()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer m.unmap()
|
|
||||||
}
|
|
||||||
return UploadBufferToBlockBlob(ctx, m, blockBlobURL, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const BlobDefaultDownloadBlockSize = int64(4 * 1024 * 1024) // 4MB
|
|
||||||
|
|
||||||
// DownloadFromBlobOptions identifies options used by the DownloadBlobToBuffer and DownloadBlobToFile functions.
|
|
||||||
type DownloadFromBlobOptions struct {
|
|
||||||
// BlockSize specifies the block size to use for each parallel download; the default size is BlobDefaultDownloadBlockSize.
|
|
||||||
BlockSize int64
|
|
||||||
|
|
||||||
// Progress is a function that is invoked periodically as bytes are received.
|
|
||||||
Progress pipeline.ProgressReceiver
|
|
||||||
|
|
||||||
// AccessConditions indicates the access conditions used when making HTTP GET requests against the blob.
|
|
||||||
AccessConditions BlobAccessConditions
|
|
||||||
|
|
||||||
// Parallelism indicates the maximum number of blocks to download in parallel (0=default)
|
|
||||||
Parallelism uint16
|
|
||||||
|
|
||||||
// RetryReaderOptionsPerBlock is used when downloading each block.
|
|
||||||
RetryReaderOptionsPerBlock RetryReaderOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// downloadBlobToBuffer downloads an Azure blob to a buffer with parallel.
|
|
||||||
func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64,
|
|
||||||
b []byte, o DownloadFromBlobOptions, initialDownloadResponse *DownloadResponse) error {
|
|
||||||
if o.BlockSize == 0 {
|
|
||||||
o.BlockSize = BlobDefaultDownloadBlockSize
|
|
||||||
}
|
|
||||||
|
|
||||||
if count == CountToEnd { // If size not specified, calculate it
|
|
||||||
if initialDownloadResponse != nil {
|
|
||||||
count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it
|
|
||||||
} else {
|
|
||||||
// If we don't have the length at all, get it
|
|
||||||
dr, err := blobURL.Download(ctx, 0, CountToEnd, o.AccessConditions, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
count = dr.ContentLength() - offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare and do parallel download.
|
|
||||||
progress := int64(0)
|
|
||||||
progressLock := &sync.Mutex{}
|
|
||||||
|
|
||||||
err := DoBatchTransfer(ctx, BatchTransferOptions{
|
|
||||||
OperationName: "downloadBlobToBuffer",
|
|
||||||
TransferSize: count,
|
|
||||||
ChunkSize: o.BlockSize,
|
|
||||||
Parallelism: o.Parallelism,
|
|
||||||
Operation: func(chunkStart int64, count int64, ctx context.Context) error {
|
|
||||||
dr, err := blobURL.Download(ctx, chunkStart+offset, count, o.AccessConditions, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
body := dr.Body(o.RetryReaderOptionsPerBlock)
|
|
||||||
if o.Progress != nil {
|
|
||||||
rangeProgress := int64(0)
|
|
||||||
body = pipeline.NewResponseBodyProgress(
|
|
||||||
body,
|
|
||||||
func(bytesTransferred int64) {
|
|
||||||
diff := bytesTransferred - rangeProgress
|
|
||||||
rangeProgress = bytesTransferred
|
|
||||||
progressLock.Lock()
|
|
||||||
progress += diff
|
|
||||||
o.Progress(progress)
|
|
||||||
progressLock.Unlock()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_, err = io.ReadFull(body, b[chunkStart:chunkStart+count])
|
|
||||||
body.Close()
|
|
||||||
return err
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DownloadBlobToBuffer downloads an Azure blob to a buffer with parallel.
|
|
||||||
// Offset and count are optional, pass 0 for both to download the entire blob.
|
|
||||||
func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64,
|
|
||||||
b []byte, o DownloadFromBlobOptions) error {
|
|
||||||
return downloadBlobToBuffer(ctx, blobURL, offset, count, b, o, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DownloadBlobToFile downloads an Azure blob to a local file.
|
|
||||||
// The file would be truncated if the size doesn't match.
|
|
||||||
// Offset and count are optional, pass 0 for both to download the entire blob.
|
|
||||||
func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, count int64,
|
|
||||||
file *os.File, o DownloadFromBlobOptions) error {
|
|
||||||
// 1. Calculate the size of the destination file
|
|
||||||
var size int64
|
|
||||||
|
|
||||||
if count == CountToEnd {
|
|
||||||
// Try to get Azure blob's size
|
|
||||||
props, err := blobURL.GetProperties(ctx, o.AccessConditions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
size = props.ContentLength() - offset
|
|
||||||
} else {
|
|
||||||
size = count
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Compare and try to resize local file's size if it doesn't match Azure blob's size.
|
|
||||||
stat, err := file.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if stat.Size() != size {
|
|
||||||
if err = file.Truncate(size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if size > 0 {
|
|
||||||
// 3. Set mmap and call downloadBlobToBuffer.
|
|
||||||
m, err := newMMF(file, true, 0, int(size))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer m.unmap()
|
|
||||||
return downloadBlobToBuffer(ctx, blobURL, offset, size, m, o, nil)
|
|
||||||
} else { // if the blob's size is 0, there is no need in downloading it
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// BatchTransferOptions identifies options used by DoBatchTransfer.
|
|
||||||
type BatchTransferOptions struct {
|
|
||||||
TransferSize int64
|
|
||||||
ChunkSize int64
|
|
||||||
Parallelism uint16
|
|
||||||
Operation func(offset int64, chunkSize int64, ctx context.Context) error
|
|
||||||
OperationName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoBatchTransfer helps to execute operations in a batch manner.
|
|
||||||
// Can be used by users to customize batch works (for other scenarios that the SDK does not provide)
|
|
||||||
func DoBatchTransfer(ctx context.Context, o BatchTransferOptions) error {
|
|
||||||
if o.ChunkSize == 0 {
|
|
||||||
return errors.New("ChunkSize cannot be 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.Parallelism == 0 {
|
|
||||||
o.Parallelism = 5 // default Parallelism
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare and do parallel operations.
|
|
||||||
numChunks := uint16(((o.TransferSize - 1) / o.ChunkSize) + 1)
|
|
||||||
operationChannel := make(chan func() error, o.Parallelism) // Create the channel that release 'Parallelism' goroutines concurrently
|
|
||||||
operationResponseChannel := make(chan error, numChunks) // Holds each response
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// Create the goroutines that process each operation (in parallel).
|
|
||||||
for g := uint16(0); g < o.Parallelism; g++ {
|
|
||||||
//grIndex := g
|
|
||||||
go func() {
|
|
||||||
for f := range operationChannel {
|
|
||||||
err := f()
|
|
||||||
operationResponseChannel <- err
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add each chunk's operation to the channel.
|
|
||||||
for chunkNum := uint16(0); chunkNum < numChunks; chunkNum++ {
|
|
||||||
curChunkSize := o.ChunkSize
|
|
||||||
|
|
||||||
if chunkNum == numChunks-1 { // Last chunk
|
|
||||||
curChunkSize = o.TransferSize - (int64(chunkNum) * o.ChunkSize) // Remove size of all transferred chunks from total
|
|
||||||
}
|
|
||||||
offset := int64(chunkNum) * o.ChunkSize
|
|
||||||
|
|
||||||
operationChannel <- func() error {
|
|
||||||
return o.Operation(offset, curChunkSize, ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(operationChannel)
|
|
||||||
|
|
||||||
// Wait for the operations to complete.
|
|
||||||
var firstErr error = nil
|
|
||||||
for chunkNum := uint16(0); chunkNum < numChunks; chunkNum++ {
|
|
||||||
responseError := <-operationResponseChannel
|
|
||||||
// record the first error (the original error which should cause the other chunks to fail with canceled context)
|
|
||||||
if responseError != nil && firstErr == nil {
|
|
||||||
cancel() // As soon as any operation fails, cancel all remaining operation calls
|
|
||||||
firstErr = responseError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return firstErr
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const _1MiB = 1024 * 1024
|
|
||||||
|
|
||||||
type UploadStreamToBlockBlobOptions struct {
|
|
||||||
// BufferSize sizes the buffer used to read data from source. If < 1 MiB, defaults to 1 MiB.
|
|
||||||
BufferSize int
|
|
||||||
// MaxBuffers defines the number of simultaneous uploads will be performed to upload the file.
|
|
||||||
MaxBuffers int
|
|
||||||
BlobHTTPHeaders BlobHTTPHeaders
|
|
||||||
Metadata Metadata
|
|
||||||
AccessConditions BlobAccessConditions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UploadStreamToBlockBlobOptions) defaults() {
|
|
||||||
if u.MaxBuffers == 0 {
|
|
||||||
u.MaxBuffers = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.BufferSize < _1MiB {
|
|
||||||
u.BufferSize = _1MiB
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadStreamToBlockBlob copies the file held in io.Reader to the Blob at blockBlobURL.
|
|
||||||
// A Context deadline or cancellation will cause this to error.
|
|
||||||
func UploadStreamToBlockBlob(ctx context.Context, reader io.Reader, blockBlobURL BlockBlobURL,
|
|
||||||
o UploadStreamToBlockBlobOptions) (CommonResponse, error) {
|
|
||||||
o.defaults()
|
|
||||||
|
|
||||||
result, err := copyFromReader(ctx, reader, blockBlobURL, o)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadStreamOptions (defunct) was used internally. This will be removed or made private in a future version.
|
|
||||||
type UploadStreamOptions struct {
|
|
||||||
BufferSize int
|
|
||||||
MaxBuffers int
|
|
||||||
}
|
|
153
vendor/github.com/Azure/azure-storage-blob-go/azblob/parsing_urls.go
generated
vendored
153
vendor/github.com/Azure/azure-storage-blob-go/azblob/parsing_urls.go
generated
vendored
@ -1,153 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
snapshot = "snapshot"
|
|
||||||
SnapshotTimeFormat = "2006-01-02T15:04:05.0000000Z07:00"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You parse an
|
|
||||||
// existing URL into its parts by calling NewBlobURLParts(). You construct a URL from parts by calling URL().
|
|
||||||
// NOTE: Changing any SAS-related field requires computing a new SAS signature.
|
|
||||||
type BlobURLParts struct {
|
|
||||||
Scheme string // Ex: "https://"
|
|
||||||
Host string // Ex: "account.blob.core.windows.net", "10.132.141.33", "10.132.141.33:80"
|
|
||||||
IPEndpointStyleInfo IPEndpointStyleInfo
|
|
||||||
ContainerName string // "" if no container
|
|
||||||
BlobName string // "" if no blob
|
|
||||||
Snapshot string // "" if not a snapshot
|
|
||||||
SAS SASQueryParameters
|
|
||||||
UnparsedParams string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator.
|
|
||||||
// Ex: "https://10.132.141.33/accountname/containername"
|
|
||||||
type IPEndpointStyleInfo struct {
|
|
||||||
AccountName string // "" if not using IP endpoint style
|
|
||||||
}
|
|
||||||
|
|
||||||
// isIPEndpointStyle checkes if URL's host is IP, in this case the storage account endpoint will be composed as:
|
|
||||||
// http(s)://IP(:port)/storageaccount/container/...
|
|
||||||
// As url's Host property, host could be both host or host:port
|
|
||||||
func isIPEndpointStyle(host string) bool {
|
|
||||||
if host == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if h, _, err := net.SplitHostPort(host); err == nil {
|
|
||||||
host = h
|
|
||||||
}
|
|
||||||
// For IPv6, there could be case where SplitHostPort fails for cannot finding port.
|
|
||||||
// In this case, eliminate the '[' and ']' in the URL.
|
|
||||||
// For details about IPv6 URL, please refer to https://tools.ietf.org/html/rfc2732
|
|
||||||
if host[0] == '[' && host[len(host)-1] == ']' {
|
|
||||||
host = host[1 : len(host)-1]
|
|
||||||
}
|
|
||||||
return net.ParseIP(host) != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlobURLParts parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other
|
|
||||||
// query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object.
|
|
||||||
func NewBlobURLParts(u url.URL) BlobURLParts {
|
|
||||||
up := BlobURLParts{
|
|
||||||
Scheme: u.Scheme,
|
|
||||||
Host: u.Host,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the container & blob names (if any)
|
|
||||||
if u.Path != "" {
|
|
||||||
path := u.Path
|
|
||||||
if path[0] == '/' {
|
|
||||||
path = path[1:] // If path starts with a slash, remove it
|
|
||||||
}
|
|
||||||
if isIPEndpointStyle(up.Host) {
|
|
||||||
if accountEndIndex := strings.Index(path, "/"); accountEndIndex == -1 { // Slash not found; path has account name & no container name or blob
|
|
||||||
up.IPEndpointStyleInfo.AccountName = path
|
|
||||||
} else {
|
|
||||||
up.IPEndpointStyleInfo.AccountName = path[:accountEndIndex] // The account name is the part between the slashes
|
|
||||||
path = path[accountEndIndex+1:] // path refers to portion after the account name now (container & blob names)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
containerEndIndex := strings.Index(path, "/") // Find the next slash (if it exists)
|
|
||||||
if containerEndIndex == -1 { // Slash not found; path has container name & no blob name
|
|
||||||
up.ContainerName = path
|
|
||||||
} else {
|
|
||||||
up.ContainerName = path[:containerEndIndex] // The container name is the part between the slashes
|
|
||||||
up.BlobName = path[containerEndIndex+1:] // The blob name is after the container slash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the query parameters to a case-sensitive map & trim whitespace
|
|
||||||
paramsMap := u.Query()
|
|
||||||
|
|
||||||
up.Snapshot = "" // Assume no snapshot
|
|
||||||
if snapshotStr, ok := caseInsensitiveValues(paramsMap).Get(snapshot); ok {
|
|
||||||
up.Snapshot = snapshotStr[0]
|
|
||||||
// If we recognized the query parameter, remove it from the map
|
|
||||||
delete(paramsMap, snapshot)
|
|
||||||
}
|
|
||||||
up.SAS = newSASQueryParameters(paramsMap, true)
|
|
||||||
up.UnparsedParams = paramsMap.Encode()
|
|
||||||
return up
|
|
||||||
}
|
|
||||||
|
|
||||||
type caseInsensitiveValues url.Values // map[string][]string
|
|
||||||
func (values caseInsensitiveValues) Get(key string) ([]string, bool) {
|
|
||||||
key = strings.ToLower(key)
|
|
||||||
for k, v := range values {
|
|
||||||
if strings.ToLower(k) == key {
|
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []string{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL returns a URL object whose fields are initialized from the BlobURLParts fields. The URL's RawQuery
|
|
||||||
// field contains the SAS, snapshot, and unparsed query parameters.
|
|
||||||
func (up BlobURLParts) URL() url.URL {
|
|
||||||
path := ""
|
|
||||||
if isIPEndpointStyle(up.Host) && up.IPEndpointStyleInfo.AccountName != "" {
|
|
||||||
path += "/" + up.IPEndpointStyleInfo.AccountName
|
|
||||||
}
|
|
||||||
// Concatenate container & blob names (if they exist)
|
|
||||||
if up.ContainerName != "" {
|
|
||||||
path += "/" + up.ContainerName
|
|
||||||
if up.BlobName != "" {
|
|
||||||
path += "/" + up.BlobName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rawQuery := up.UnparsedParams
|
|
||||||
|
|
||||||
//If no snapshot is initially provided, fill it in from the SAS query properties to help the user
|
|
||||||
if up.Snapshot == "" && !up.SAS.snapshotTime.IsZero() {
|
|
||||||
up.Snapshot = up.SAS.snapshotTime.Format(SnapshotTimeFormat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concatenate blob snapshot query parameter (if it exists)
|
|
||||||
if up.Snapshot != "" {
|
|
||||||
if len(rawQuery) > 0 {
|
|
||||||
rawQuery += "&"
|
|
||||||
}
|
|
||||||
rawQuery += snapshot + "=" + up.Snapshot
|
|
||||||
}
|
|
||||||
sas := up.SAS.Encode()
|
|
||||||
if sas != "" {
|
|
||||||
if len(rawQuery) > 0 {
|
|
||||||
rawQuery += "&"
|
|
||||||
}
|
|
||||||
rawQuery += sas
|
|
||||||
}
|
|
||||||
u := url.URL{
|
|
||||||
Scheme: up.Scheme,
|
|
||||||
Host: up.Host,
|
|
||||||
Path: path,
|
|
||||||
RawQuery: rawQuery,
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
256
vendor/github.com/Azure/azure-storage-blob-go/azblob/sas_service.go
generated
vendored
256
vendor/github.com/Azure/azure-storage-blob-go/azblob/sas_service.go
generated
vendored
@ -1,256 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-a-service-sas
|
|
||||||
type BlobSASSignatureValues struct {
|
|
||||||
Version string `param:"sv"` // If not specified, this defaults to SASVersion
|
|
||||||
Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants
|
|
||||||
StartTime time.Time `param:"st"` // Not specified if IsZero
|
|
||||||
ExpiryTime time.Time `param:"se"` // Not specified if IsZero
|
|
||||||
SnapshotTime time.Time
|
|
||||||
Permissions string `param:"sp"` // Create by initializing a ContainerSASPermissions or BlobSASPermissions and then call String()
|
|
||||||
IPRange IPRange `param:"sip"`
|
|
||||||
Identifier string `param:"si"`
|
|
||||||
ContainerName string
|
|
||||||
BlobName string // Use "" to create a Container SAS
|
|
||||||
CacheControl string // rscc
|
|
||||||
ContentDisposition string // rscd
|
|
||||||
ContentEncoding string // rsce
|
|
||||||
ContentLanguage string // rscl
|
|
||||||
ContentType string // rsct
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSASQueryParameters uses an account's StorageAccountCredential to sign this signature values to produce
|
|
||||||
// the proper SAS query parameters.
|
|
||||||
// See: StorageAccountCredential. Compatible with both UserDelegationCredential and SharedKeyCredential
|
|
||||||
func (v BlobSASSignatureValues) NewSASQueryParameters(credential StorageAccountCredential) (SASQueryParameters, error) {
|
|
||||||
resource := "c"
|
|
||||||
if credential == nil {
|
|
||||||
return SASQueryParameters{}, fmt.Errorf("cannot sign SAS query without StorageAccountCredential")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.SnapshotTime.IsZero() {
|
|
||||||
resource = "bs"
|
|
||||||
//Make sure the permission characters are in the correct order
|
|
||||||
perms := &BlobSASPermissions{}
|
|
||||||
if err := perms.Parse(v.Permissions); err != nil {
|
|
||||||
return SASQueryParameters{}, err
|
|
||||||
}
|
|
||||||
v.Permissions = perms.String()
|
|
||||||
} else if v.BlobName == "" {
|
|
||||||
// Make sure the permission characters are in the correct order
|
|
||||||
perms := &ContainerSASPermissions{}
|
|
||||||
if err := perms.Parse(v.Permissions); err != nil {
|
|
||||||
return SASQueryParameters{}, err
|
|
||||||
}
|
|
||||||
v.Permissions = perms.String()
|
|
||||||
} else {
|
|
||||||
resource = "b"
|
|
||||||
// Make sure the permission characters are in the correct order
|
|
||||||
perms := &BlobSASPermissions{}
|
|
||||||
if err := perms.Parse(v.Permissions); err != nil {
|
|
||||||
return SASQueryParameters{}, err
|
|
||||||
}
|
|
||||||
v.Permissions = perms.String()
|
|
||||||
}
|
|
||||||
if v.Version == "" {
|
|
||||||
v.Version = SASVersion
|
|
||||||
}
|
|
||||||
startTime, expiryTime, snapshotTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime, v.SnapshotTime)
|
|
||||||
|
|
||||||
signedIdentifier := v.Identifier
|
|
||||||
|
|
||||||
udk := credential.getUDKParams()
|
|
||||||
|
|
||||||
if udk != nil {
|
|
||||||
udkStart, udkExpiry, _ := FormatTimesForSASSigning(udk.SignedStart, udk.SignedExpiry, time.Time{})
|
|
||||||
//I don't like this answer to combining the functions
|
|
||||||
//But because signedIdentifier and the user delegation key strings share a place, this is an _OK_ way to do it.
|
|
||||||
signedIdentifier = strings.Join([]string{
|
|
||||||
udk.SignedOid,
|
|
||||||
udk.SignedTid,
|
|
||||||
udkStart,
|
|
||||||
udkExpiry,
|
|
||||||
udk.SignedService,
|
|
||||||
udk.SignedVersion,
|
|
||||||
}, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// String to sign: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
|
|
||||||
stringToSign := strings.Join([]string{
|
|
||||||
v.Permissions,
|
|
||||||
startTime,
|
|
||||||
expiryTime,
|
|
||||||
getCanonicalName(credential.AccountName(), v.ContainerName, v.BlobName),
|
|
||||||
signedIdentifier,
|
|
||||||
v.IPRange.String(),
|
|
||||||
string(v.Protocol),
|
|
||||||
v.Version,
|
|
||||||
resource,
|
|
||||||
snapshotTime, // signed timestamp
|
|
||||||
v.CacheControl, // rscc
|
|
||||||
v.ContentDisposition, // rscd
|
|
||||||
v.ContentEncoding, // rsce
|
|
||||||
v.ContentLanguage, // rscl
|
|
||||||
v.ContentType}, // rsct
|
|
||||||
"\n")
|
|
||||||
|
|
||||||
signature := ""
|
|
||||||
signature = credential.ComputeHMACSHA256(stringToSign)
|
|
||||||
|
|
||||||
p := SASQueryParameters{
|
|
||||||
// Common SAS parameters
|
|
||||||
version: v.Version,
|
|
||||||
protocol: v.Protocol,
|
|
||||||
startTime: v.StartTime,
|
|
||||||
expiryTime: v.ExpiryTime,
|
|
||||||
permissions: v.Permissions,
|
|
||||||
ipRange: v.IPRange,
|
|
||||||
|
|
||||||
// Container/Blob-specific SAS parameters
|
|
||||||
resource: resource,
|
|
||||||
identifier: v.Identifier,
|
|
||||||
cacheControl: v.CacheControl,
|
|
||||||
contentDisposition: v.ContentDisposition,
|
|
||||||
contentEncoding: v.ContentEncoding,
|
|
||||||
contentLanguage: v.ContentLanguage,
|
|
||||||
contentType: v.ContentType,
|
|
||||||
snapshotTime: v.SnapshotTime,
|
|
||||||
|
|
||||||
// Calculated SAS signature
|
|
||||||
signature: signature,
|
|
||||||
}
|
|
||||||
|
|
||||||
//User delegation SAS specific parameters
|
|
||||||
if udk != nil {
|
|
||||||
p.signedOid = udk.SignedOid
|
|
||||||
p.signedTid = udk.SignedTid
|
|
||||||
p.signedStart = udk.SignedStart
|
|
||||||
p.signedExpiry = udk.SignedExpiry
|
|
||||||
p.signedService = udk.SignedService
|
|
||||||
p.signedVersion = udk.SignedVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCanonicalName computes the canonical name for a container or blob resource for SAS signing.
|
|
||||||
func getCanonicalName(account string, containerName string, blobName string) string {
|
|
||||||
// Container: "/blob/account/containername"
|
|
||||||
// Blob: "/blob/account/containername/blobname"
|
|
||||||
elements := []string{"/blob/", account, "/", containerName}
|
|
||||||
if blobName != "" {
|
|
||||||
elements = append(elements, "/", strings.Replace(blobName, "\\", "/", -1))
|
|
||||||
}
|
|
||||||
return strings.Join(elements, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS.
|
|
||||||
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
|
|
||||||
type ContainerSASPermissions struct {
|
|
||||||
Read, Add, Create, Write, Delete, List bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String produces the SAS permissions string for an Azure Storage container.
|
|
||||||
// Call this method to set BlobSASSignatureValues's Permissions field.
|
|
||||||
func (p ContainerSASPermissions) String() string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
if p.Read {
|
|
||||||
b.WriteRune('r')
|
|
||||||
}
|
|
||||||
if p.Add {
|
|
||||||
b.WriteRune('a')
|
|
||||||
}
|
|
||||||
if p.Create {
|
|
||||||
b.WriteRune('c')
|
|
||||||
}
|
|
||||||
if p.Write {
|
|
||||||
b.WriteRune('w')
|
|
||||||
}
|
|
||||||
if p.Delete {
|
|
||||||
b.WriteRune('d')
|
|
||||||
}
|
|
||||||
if p.List {
|
|
||||||
b.WriteRune('l')
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the ContainerSASPermissions's fields from a string.
|
|
||||||
func (p *ContainerSASPermissions) Parse(s string) error {
|
|
||||||
*p = ContainerSASPermissions{} // Clear the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 'r':
|
|
||||||
p.Read = true
|
|
||||||
case 'a':
|
|
||||||
p.Add = true
|
|
||||||
case 'c':
|
|
||||||
p.Create = true
|
|
||||||
case 'w':
|
|
||||||
p.Write = true
|
|
||||||
case 'd':
|
|
||||||
p.Delete = true
|
|
||||||
case 'l':
|
|
||||||
p.List = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid permission: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS.
|
|
||||||
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
|
|
||||||
type BlobSASPermissions struct{ Read, Add, Create, Write, Delete bool }
|
|
||||||
|
|
||||||
// String produces the SAS permissions string for an Azure Storage blob.
|
|
||||||
// Call this method to set BlobSASSignatureValues's Permissions field.
|
|
||||||
func (p BlobSASPermissions) String() string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
if p.Read {
|
|
||||||
b.WriteRune('r')
|
|
||||||
}
|
|
||||||
if p.Add {
|
|
||||||
b.WriteRune('a')
|
|
||||||
}
|
|
||||||
if p.Create {
|
|
||||||
b.WriteRune('c')
|
|
||||||
}
|
|
||||||
if p.Write {
|
|
||||||
b.WriteRune('w')
|
|
||||||
}
|
|
||||||
if p.Delete {
|
|
||||||
b.WriteRune('d')
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the BlobSASPermissions's fields from a string.
|
|
||||||
func (p *BlobSASPermissions) Parse(s string) error {
|
|
||||||
*p = BlobSASPermissions{} // Clear the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 'r':
|
|
||||||
p.Read = true
|
|
||||||
case 'a':
|
|
||||||
p.Add = true
|
|
||||||
case 'c':
|
|
||||||
p.Create = true
|
|
||||||
case 'w':
|
|
||||||
p.Write = true
|
|
||||||
case 'd':
|
|
||||||
p.Delete = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid permission: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
195
vendor/github.com/Azure/azure-storage-blob-go/azblob/service_codes_blob.go
generated
vendored
195
vendor/github.com/Azure/azure-storage-blob-go/azblob/service_codes_blob.go
generated
vendored
@ -1,195 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/blob-service-error-codes
|
|
||||||
|
|
||||||
// ServiceCode values indicate a service failure.
|
|
||||||
const (
|
|
||||||
// ServiceCodeAppendPositionConditionNotMet means the append position condition specified was not met.
|
|
||||||
ServiceCodeAppendPositionConditionNotMet ServiceCodeType = "AppendPositionConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeBlobAlreadyExists means the specified blob already exists.
|
|
||||||
ServiceCodeBlobAlreadyExists ServiceCodeType = "BlobAlreadyExists"
|
|
||||||
|
|
||||||
// ServiceCodeBlobNotFound means the specified blob does not exist.
|
|
||||||
ServiceCodeBlobNotFound ServiceCodeType = "BlobNotFound"
|
|
||||||
|
|
||||||
// ServiceCodeBlobOverwritten means the blob has been recreated since the previous snapshot was taken.
|
|
||||||
ServiceCodeBlobOverwritten ServiceCodeType = "BlobOverwritten"
|
|
||||||
|
|
||||||
// ServiceCodeBlobTierInadequateForContentLength means the specified blob tier size limit cannot be less than content length.
|
|
||||||
ServiceCodeBlobTierInadequateForContentLength ServiceCodeType = "BlobTierInadequateForContentLength"
|
|
||||||
|
|
||||||
// ServiceCodeBlockCountExceedsLimit means the committed block count cannot exceed the maximum limit of 50,000 blocks
|
|
||||||
// or that the uncommitted block count cannot exceed the maximum limit of 100,000 blocks.
|
|
||||||
ServiceCodeBlockCountExceedsLimit ServiceCodeType = "BlockCountExceedsLimit"
|
|
||||||
|
|
||||||
// ServiceCodeBlockListTooLong means the block list may not contain more than 50,000 blocks.
|
|
||||||
ServiceCodeBlockListTooLong ServiceCodeType = "BlockListTooLong"
|
|
||||||
|
|
||||||
// ServiceCodeCannotChangeToLowerTier means that a higher blob tier has already been explicitly set.
|
|
||||||
ServiceCodeCannotChangeToLowerTier ServiceCodeType = "CannotChangeToLowerTier"
|
|
||||||
|
|
||||||
// ServiceCodeCannotVerifyCopySource means that the service could not verify the copy source within the specified time.
|
|
||||||
// Examine the HTTP status code and message for more information about the failure.
|
|
||||||
ServiceCodeCannotVerifyCopySource ServiceCodeType = "CannotVerifyCopySource"
|
|
||||||
|
|
||||||
// ServiceCodeContainerAlreadyExists means the specified container already exists.
|
|
||||||
ServiceCodeContainerAlreadyExists ServiceCodeType = "ContainerAlreadyExists"
|
|
||||||
|
|
||||||
// ServiceCodeContainerBeingDeleted means the specified container is being deleted.
|
|
||||||
ServiceCodeContainerBeingDeleted ServiceCodeType = "ContainerBeingDeleted"
|
|
||||||
|
|
||||||
// ServiceCodeContainerDisabled means the specified container has been disabled by the administrator.
|
|
||||||
ServiceCodeContainerDisabled ServiceCodeType = "ContainerDisabled"
|
|
||||||
|
|
||||||
// ServiceCodeContainerNotFound means the specified container does not exist.
|
|
||||||
ServiceCodeContainerNotFound ServiceCodeType = "ContainerNotFound"
|
|
||||||
|
|
||||||
// ServiceCodeContentLengthLargerThanTierLimit means the blob's content length cannot exceed its tier limit.
|
|
||||||
ServiceCodeContentLengthLargerThanTierLimit ServiceCodeType = "ContentLengthLargerThanTierLimit"
|
|
||||||
|
|
||||||
// ServiceCodeCopyAcrossAccountsNotSupported means the copy source account and destination account must be the same.
|
|
||||||
ServiceCodeCopyAcrossAccountsNotSupported ServiceCodeType = "CopyAcrossAccountsNotSupported"
|
|
||||||
|
|
||||||
// ServiceCodeCopyIDMismatch means the specified copy ID did not match the copy ID for the pending copy operation.
|
|
||||||
ServiceCodeCopyIDMismatch ServiceCodeType = "CopyIdMismatch"
|
|
||||||
|
|
||||||
// ServiceCodeFeatureVersionMismatch means the type of blob in the container is unrecognized by this version or
|
|
||||||
// that the operation for AppendBlob requires at least version 2015-02-21.
|
|
||||||
ServiceCodeFeatureVersionMismatch ServiceCodeType = "FeatureVersionMismatch"
|
|
||||||
|
|
||||||
// ServiceCodeIncrementalCopyBlobMismatch means the specified source blob is different than the copy source of the existing incremental copy blob.
|
|
||||||
ServiceCodeIncrementalCopyBlobMismatch ServiceCodeType = "IncrementalCopyBlobMismatch"
|
|
||||||
|
|
||||||
// ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed means the specified snapshot is earlier than the last snapshot copied into the incremental copy blob.
|
|
||||||
ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed ServiceCodeType = "IncrementalCopyOfEralierVersionSnapshotNotAllowed"
|
|
||||||
|
|
||||||
// ServiceCodeIncrementalCopySourceMustBeSnapshot means the source for incremental copy request must be a snapshot.
|
|
||||||
ServiceCodeIncrementalCopySourceMustBeSnapshot ServiceCodeType = "IncrementalCopySourceMustBeSnapshot"
|
|
||||||
|
|
||||||
// ServiceCodeInfiniteLeaseDurationRequired means the lease ID matched, but the specified lease must be an infinite-duration lease.
|
|
||||||
ServiceCodeInfiniteLeaseDurationRequired ServiceCodeType = "InfiniteLeaseDurationRequired"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidBlobOrBlock means the specified blob or block content is invalid.
|
|
||||||
ServiceCodeInvalidBlobOrBlock ServiceCodeType = "InvalidBlobOrBlock"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidBlobType means the blob type is invalid for this operation.
|
|
||||||
ServiceCodeInvalidBlobType ServiceCodeType = "InvalidBlobType"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidBlockID means the specified block ID is invalid. The block ID must be Base64-encoded.
|
|
||||||
ServiceCodeInvalidBlockID ServiceCodeType = "InvalidBlockId"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidBlockList means the specified block list is invalid.
|
|
||||||
ServiceCodeInvalidBlockList ServiceCodeType = "InvalidBlockList"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidOperation means an invalid operation against a blob snapshot.
|
|
||||||
ServiceCodeInvalidOperation ServiceCodeType = "InvalidOperation"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidPageRange means the page range specified is invalid.
|
|
||||||
ServiceCodeInvalidPageRange ServiceCodeType = "InvalidPageRange"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidSourceBlobType means the copy source blob type is invalid for this operation.
|
|
||||||
ServiceCodeInvalidSourceBlobType ServiceCodeType = "InvalidSourceBlobType"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidSourceBlobURL means the source URL for incremental copy request must be valid Azure Storage blob URL.
|
|
||||||
ServiceCodeInvalidSourceBlobURL ServiceCodeType = "InvalidSourceBlobUrl"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidVersionForPageBlobOperation means that all operations on page blobs require at least version 2009-09-19.
|
|
||||||
ServiceCodeInvalidVersionForPageBlobOperation ServiceCodeType = "InvalidVersionForPageBlobOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseAlreadyPresent means there is already a lease present.
|
|
||||||
ServiceCodeLeaseAlreadyPresent ServiceCodeType = "LeaseAlreadyPresent"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseAlreadyBroken means the lease has already been broken and cannot be broken again.
|
|
||||||
ServiceCodeLeaseAlreadyBroken ServiceCodeType = "LeaseAlreadyBroken"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIDMismatchWithBlobOperation means the lease ID specified did not match the lease ID for the blob.
|
|
||||||
ServiceCodeLeaseIDMismatchWithBlobOperation ServiceCodeType = "LeaseIdMismatchWithBlobOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIDMismatchWithContainerOperation means the lease ID specified did not match the lease ID for the container.
|
|
||||||
ServiceCodeLeaseIDMismatchWithContainerOperation ServiceCodeType = "LeaseIdMismatchWithContainerOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIDMismatchWithLeaseOperation means the lease ID specified did not match the lease ID for the blob/container.
|
|
||||||
ServiceCodeLeaseIDMismatchWithLeaseOperation ServiceCodeType = "LeaseIdMismatchWithLeaseOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIDMissing means there is currently a lease on the blob/container and no lease ID was specified in the request.
|
|
||||||
ServiceCodeLeaseIDMissing ServiceCodeType = "LeaseIdMissing"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIsBreakingAndCannotBeAcquired means the lease ID matched, but the lease is currently in breaking state and cannot be acquired until it is broken.
|
|
||||||
ServiceCodeLeaseIsBreakingAndCannotBeAcquired ServiceCodeType = "LeaseIsBreakingAndCannotBeAcquired"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIsBreakingAndCannotBeChanged means the lease ID matched, but the lease is currently in breaking state and cannot be changed.
|
|
||||||
ServiceCodeLeaseIsBreakingAndCannotBeChanged ServiceCodeType = "LeaseIsBreakingAndCannotBeChanged"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseIsBrokenAndCannotBeRenewed means the lease ID matched, but the lease has been broken explicitly and cannot be renewed.
|
|
||||||
ServiceCodeLeaseIsBrokenAndCannotBeRenewed ServiceCodeType = "LeaseIsBrokenAndCannotBeRenewed"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseLost means a lease ID was specified, but the lease for the blob/container has expired.
|
|
||||||
ServiceCodeLeaseLost ServiceCodeType = "LeaseLost"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseNotPresentWithBlobOperation means there is currently no lease on the blob.
|
|
||||||
ServiceCodeLeaseNotPresentWithBlobOperation ServiceCodeType = "LeaseNotPresentWithBlobOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseNotPresentWithContainerOperation means there is currently no lease on the container.
|
|
||||||
ServiceCodeLeaseNotPresentWithContainerOperation ServiceCodeType = "LeaseNotPresentWithContainerOperation"
|
|
||||||
|
|
||||||
// ServiceCodeLeaseNotPresentWithLeaseOperation means there is currently no lease on the blob/container.
|
|
||||||
ServiceCodeLeaseNotPresentWithLeaseOperation ServiceCodeType = "LeaseNotPresentWithLeaseOperation"
|
|
||||||
|
|
||||||
// ServiceCodeMaxBlobSizeConditionNotMet means the max blob size condition specified was not met.
|
|
||||||
ServiceCodeMaxBlobSizeConditionNotMet ServiceCodeType = "MaxBlobSizeConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeNoPendingCopyOperation means there is currently no pending copy operation.
|
|
||||||
ServiceCodeNoPendingCopyOperation ServiceCodeType = "NoPendingCopyOperation"
|
|
||||||
|
|
||||||
// ServiceCodeOperationNotAllowedOnIncrementalCopyBlob means the specified operation is not allowed on an incremental copy blob.
|
|
||||||
ServiceCodeOperationNotAllowedOnIncrementalCopyBlob ServiceCodeType = "OperationNotAllowedOnIncrementalCopyBlob"
|
|
||||||
|
|
||||||
// ServiceCodePendingCopyOperation means there is currently a pending copy operation.
|
|
||||||
ServiceCodePendingCopyOperation ServiceCodeType = "PendingCopyOperation"
|
|
||||||
|
|
||||||
// ServiceCodePreviousSnapshotCannotBeNewer means the prevsnapshot query parameter value cannot be newer than snapshot query parameter value.
|
|
||||||
ServiceCodePreviousSnapshotCannotBeNewer ServiceCodeType = "PreviousSnapshotCannotBeNewer"
|
|
||||||
|
|
||||||
// ServiceCodePreviousSnapshotNotFound means the previous snapshot is not found.
|
|
||||||
ServiceCodePreviousSnapshotNotFound ServiceCodeType = "PreviousSnapshotNotFound"
|
|
||||||
|
|
||||||
// ServiceCodePreviousSnapshotOperationNotSupported means that differential Get Page Ranges is not supported on the previous snapshot.
|
|
||||||
ServiceCodePreviousSnapshotOperationNotSupported ServiceCodeType = "PreviousSnapshotOperationNotSupported"
|
|
||||||
|
|
||||||
// ServiceCodeSequenceNumberConditionNotMet means the sequence number condition specified was not met.
|
|
||||||
ServiceCodeSequenceNumberConditionNotMet ServiceCodeType = "SequenceNumberConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeSequenceNumberIncrementTooLarge means the sequence number increment cannot be performed because it would result in overflow of the sequence number.
|
|
||||||
ServiceCodeSequenceNumberIncrementTooLarge ServiceCodeType = "SequenceNumberIncrementTooLarge"
|
|
||||||
|
|
||||||
// ServiceCodeSnapshotCountExceeded means the snapshot count against this blob has been exceeded.
|
|
||||||
ServiceCodeSnapshotCountExceeded ServiceCodeType = "SnapshotCountExceeded"
|
|
||||||
|
|
||||||
// ServiceCodeSnaphotOperationRateExceeded means the rate of snapshot operations against this blob has been exceeded.
|
|
||||||
ServiceCodeSnaphotOperationRateExceeded ServiceCodeType = "SnaphotOperationRateExceeded"
|
|
||||||
|
|
||||||
// ServiceCodeSnapshotsPresent means this operation is not permitted while the blob has snapshots.
|
|
||||||
ServiceCodeSnapshotsPresent ServiceCodeType = "SnapshotsPresent"
|
|
||||||
|
|
||||||
// ServiceCodeSourceConditionNotMet means the source condition specified using HTTP conditional header(s) is not met.
|
|
||||||
ServiceCodeSourceConditionNotMet ServiceCodeType = "SourceConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeSystemInUse means this blob is in use by the system.
|
|
||||||
ServiceCodeSystemInUse ServiceCodeType = "SystemInUse"
|
|
||||||
|
|
||||||
// ServiceCodeTargetConditionNotMet means the target condition specified using HTTP conditional header(s) is not met.
|
|
||||||
ServiceCodeTargetConditionNotMet ServiceCodeType = "TargetConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeUnauthorizedBlobOverwrite means this request is not authorized to perform blob overwrites.
|
|
||||||
ServiceCodeUnauthorizedBlobOverwrite ServiceCodeType = "UnauthorizedBlobOverwrite"
|
|
||||||
|
|
||||||
// ServiceCodeBlobBeingRehydrated means this operation is not permitted because the blob is being rehydrated.
|
|
||||||
ServiceCodeBlobBeingRehydrated ServiceCodeType = "BlobBeingRehydrated"
|
|
||||||
|
|
||||||
// ServiceCodeBlobArchived means this operation is not permitted on an archived blob.
|
|
||||||
ServiceCodeBlobArchived ServiceCodeType = "BlobArchived"
|
|
||||||
|
|
||||||
// ServiceCodeBlobNotArchived means this blob is currently not in the archived state.
|
|
||||||
ServiceCodeBlobNotArchived ServiceCodeType = "BlobNotArchived"
|
|
||||||
)
|
|
8
vendor/github.com/Azure/azure-storage-blob-go/azblob/storage_account_credential.go
generated
vendored
8
vendor/github.com/Azure/azure-storage-blob-go/azblob/storage_account_credential.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// StorageAccountCredential is a wrapper interface for SharedKeyCredential and UserDelegationCredential
|
|
||||||
type StorageAccountCredential interface {
|
|
||||||
AccountName() string
|
|
||||||
ComputeHMACSHA256(message string) (base64String string)
|
|
||||||
getUDKParams() *UserDelegationKey
|
|
||||||
}
|
|
138
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_append_blob.go
generated
vendored
138
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_append_blob.go
generated
vendored
@ -1,138 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// AppendBlobMaxAppendBlockBytes indicates the maximum number of bytes that can be sent in a call to AppendBlock.
|
|
||||||
AppendBlobMaxAppendBlockBytes = 4 * 1024 * 1024 // 4MB
|
|
||||||
|
|
||||||
// AppendBlobMaxBlocks indicates the maximum number of blocks allowed in an append blob.
|
|
||||||
AppendBlobMaxBlocks = 50000
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppendBlobURL defines a set of operations applicable to append blobs.
|
|
||||||
type AppendBlobURL struct {
|
|
||||||
BlobURL
|
|
||||||
abClient appendBlobClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAppendBlobURL creates an AppendBlobURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewAppendBlobURL(url url.URL, p pipeline.Pipeline) AppendBlobURL {
|
|
||||||
blobClient := newBlobClient(url, p)
|
|
||||||
abClient := newAppendBlobClient(url, p)
|
|
||||||
return AppendBlobURL{BlobURL: BlobURL{blobClient: blobClient}, abClient: abClient}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new AppendBlobURL object identical to the source but with the specific request policy pipeline.
|
|
||||||
func (ab AppendBlobURL) WithPipeline(p pipeline.Pipeline) AppendBlobURL {
|
|
||||||
return NewAppendBlobURL(ab.blobClient.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSnapshot creates a new AppendBlobURL object identical to the source but with the specified snapshot timestamp.
|
|
||||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
|
||||||
func (ab AppendBlobURL) WithSnapshot(snapshot string) AppendBlobURL {
|
|
||||||
p := NewBlobURLParts(ab.URL())
|
|
||||||
p.Snapshot = snapshot
|
|
||||||
return NewAppendBlobURL(p.URL(), ab.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ab AppendBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
|
|
||||||
return ab.blobClient.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates a 0-length append blob. Call AppendBlock to append data to an append blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
|
|
||||||
func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*AppendBlobCreateResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return ab.abClient.Create(ctx, 0, nil,
|
|
||||||
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
|
|
||||||
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendBlock writes a stream to a new block of data to the end of the existing append blob.
|
|
||||||
// This method panics if the stream is not at position 0.
|
|
||||||
// Note that the http client closes the body stream after the request is sent to the service.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block.
|
|
||||||
func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac AppendBlobAccessConditions, transactionalMD5 []byte) (*AppendBlobAppendBlockResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendPositionAccessConditions.pointers()
|
|
||||||
count, err := validateSeekableStreamAt0AndGetCount(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ab.abClient.AppendBlock(ctx, body, count, nil,
|
|
||||||
transactionalMD5,
|
|
||||||
nil, // CRC
|
|
||||||
ac.LeaseAccessConditions.pointers(),
|
|
||||||
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendBlockFromURL copies a new block of data from source URL to the end of the existing append blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block-from-url.
|
|
||||||
func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.URL, offset int64, count int64, destinationAccessConditions AppendBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, transactionalMD5 []byte) (*AppendBlobAppendBlockFromURLResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
|
|
||||||
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
|
|
||||||
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := destinationAccessConditions.AppendPositionAccessConditions.pointers()
|
|
||||||
return ab.abClient.AppendBlockFromURL(ctx, sourceURL.String(), 0, httpRange{offset: offset, count: count}.pointers(),
|
|
||||||
transactionalMD5, nil, nil, nil,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
destinationAccessConditions.LeaseAccessConditions.pointers(),
|
|
||||||
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppendBlobAccessConditions struct {
|
|
||||||
ModifiedAccessConditions
|
|
||||||
LeaseAccessConditions
|
|
||||||
AppendPositionAccessConditions
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendPositionAccessConditions identifies append blob-specific access conditions which you optionally set.
|
|
||||||
type AppendPositionAccessConditions struct {
|
|
||||||
// IfAppendPositionEqual ensures that the AppendBlock operation succeeds
|
|
||||||
// only if the append position is equal to a value.
|
|
||||||
// IfAppendPositionEqual=0 means no 'IfAppendPositionEqual' header specified.
|
|
||||||
// IfAppendPositionEqual>0 means 'IfAppendPositionEqual' header specified with its value
|
|
||||||
// IfAppendPositionEqual==-1 means IfAppendPositionEqual' header specified with a value of 0
|
|
||||||
IfAppendPositionEqual int64
|
|
||||||
|
|
||||||
// IfMaxSizeLessThanOrEqual ensures that the AppendBlock operation succeeds
|
|
||||||
// only if the append blob's size is less than or equal to a value.
|
|
||||||
// IfMaxSizeLessThanOrEqual=0 means no 'IfMaxSizeLessThanOrEqual' header specified.
|
|
||||||
// IfMaxSizeLessThanOrEqual>0 means 'IfMaxSizeLessThanOrEqual' header specified with its value
|
|
||||||
// IfMaxSizeLessThanOrEqual==-1 means 'IfMaxSizeLessThanOrEqual' header specified with a value of 0
|
|
||||||
IfMaxSizeLessThanOrEqual int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointers is for internal infrastructure. It returns the fields as pointers.
|
|
||||||
func (ac AppendPositionAccessConditions) pointers() (iape *int64, imsltoe *int64) {
|
|
||||||
var zero int64 // defaults to 0
|
|
||||||
switch ac.IfAppendPositionEqual {
|
|
||||||
case -1:
|
|
||||||
iape = &zero
|
|
||||||
case 0:
|
|
||||||
iape = nil
|
|
||||||
default:
|
|
||||||
iape = &ac.IfAppendPositionEqual
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ac.IfMaxSizeLessThanOrEqual {
|
|
||||||
case -1:
|
|
||||||
imsltoe = &zero
|
|
||||||
case 0:
|
|
||||||
imsltoe = nil
|
|
||||||
default:
|
|
||||||
imsltoe = &ac.IfMaxSizeLessThanOrEqual
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
225
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_blob.go
generated
vendored
225
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_blob.go
generated
vendored
@ -1,225 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A BlobURL represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob.
|
|
||||||
type BlobURL struct {
|
|
||||||
blobClient blobClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL {
|
|
||||||
blobClient := newBlobClient(url, p)
|
|
||||||
return BlobURL{blobClient: blobClient}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL returns the URL endpoint used by the BlobURL object.
|
|
||||||
func (b BlobURL) URL() url.URL {
|
|
||||||
return b.blobClient.URL()
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the URL as a string.
|
|
||||||
func (b BlobURL) String() string {
|
|
||||||
u := b.URL()
|
|
||||||
return u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b BlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
|
|
||||||
return b.blobClient.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline.
|
|
||||||
func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL {
|
|
||||||
return NewBlobURL(b.blobClient.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSnapshot creates a new BlobURL object identical to the source but with the specified snapshot timestamp.
|
|
||||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
|
||||||
func (b BlobURL) WithSnapshot(snapshot string) BlobURL {
|
|
||||||
p := NewBlobURLParts(b.URL())
|
|
||||||
p.Snapshot = snapshot
|
|
||||||
return NewBlobURL(p.URL(), b.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToAppendBlobURL creates an AppendBlobURL using the source's URL and pipeline.
|
|
||||||
func (b BlobURL) ToAppendBlobURL() AppendBlobURL {
|
|
||||||
return NewAppendBlobURL(b.URL(), b.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToBlockBlobURL creates a BlockBlobURL using the source's URL and pipeline.
|
|
||||||
func (b BlobURL) ToBlockBlobURL() BlockBlobURL {
|
|
||||||
return NewBlockBlobURL(b.URL(), b.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToPageBlobURL creates a PageBlobURL using the source's URL and pipeline.
|
|
||||||
func (b BlobURL) ToPageBlobURL() PageBlobURL {
|
|
||||||
return NewPageBlobURL(b.URL(), b.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// DownloadBlob reads a range of bytes from a blob. The response also includes the blob's properties and metadata.
|
|
||||||
// Passing azblob.CountToEnd (0) for count will download the blob from the offset to the end.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob.
|
|
||||||
func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool) (*DownloadResponse, error) {
|
|
||||||
var xRangeGetContentMD5 *bool
|
|
||||||
if rangeGetContentMD5 {
|
|
||||||
xRangeGetContentMD5 = &rangeGetContentMD5
|
|
||||||
}
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
dr, err := b.blobClient.Download(ctx, nil, nil,
|
|
||||||
httpRange{offset: offset, count: count}.pointers(),
|
|
||||||
ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5, nil,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &DownloadResponse{
|
|
||||||
b: b,
|
|
||||||
r: dr,
|
|
||||||
ctx: ctx,
|
|
||||||
getInfo: HTTPGetterInfo{Offset: offset, Count: count, ETag: dr.ETag()},
|
|
||||||
}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteBlob marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection.
|
|
||||||
// Note that deleting a blob also deletes all its snapshots.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob.
|
|
||||||
func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return b.blobClient.Delete(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/undelete-blob.
|
|
||||||
func (b BlobURL) Undelete(ctx context.Context) (*BlobUndeleteResponse, error) {
|
|
||||||
return b.blobClient.Undelete(ctx, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTier operation sets the tier on a blob. The operation is allowed on a page
|
|
||||||
// blob in a premium storage account and on a block blob in a blob storage account (locally
|
|
||||||
// redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and
|
|
||||||
// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation
|
|
||||||
// does not update the blob's ETag.
|
|
||||||
// For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers.
|
|
||||||
func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType, lac LeaseAccessConditions) (*BlobSetTierResponse, error) {
|
|
||||||
return b.blobClient.SetTier(ctx, tier, nil, RehydratePriorityNone, nil, lac.pointers())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlobProperties returns the blob's properties.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties.
|
|
||||||
func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*BlobGetPropertiesResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return b.blobClient.GetProperties(ctx, nil, nil, ac.LeaseAccessConditions.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBlobHTTPHeaders changes a blob's HTTP headers.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
|
|
||||||
func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return b.blobClient.SetHTTPHeaders(ctx, nil,
|
|
||||||
&h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage,
|
|
||||||
ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
|
|
||||||
&h.ContentDisposition, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBlobMetadata changes a blob's metadata.
|
|
||||||
// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata.
|
|
||||||
func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobSetMetadataResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateSnapshot creates a read-only snapshot of a blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob.
|
|
||||||
func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobCreateSnapshotResponse, error) {
|
|
||||||
// CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter
|
|
||||||
// because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this
|
|
||||||
// performance hit.
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return b.blobClient.CreateSnapshot(ctx, nil, metadata,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between
|
|
||||||
// 15 to 60 seconds, or infinite (-1).
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
|
|
||||||
func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*BlobAcquireLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
|
|
||||||
return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewLease renews the blob's previously-acquired lease.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
|
|
||||||
func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobRenewLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
|
|
||||||
return b.blobClient.RenewLease(ctx, leaseID, nil,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReleaseLease releases the blob's previously-acquired lease.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
|
|
||||||
func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobReleaseLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
|
|
||||||
return b.blobClient.ReleaseLease(ctx, leaseID, nil,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1)
|
|
||||||
// constant to break a fixed-duration lease when it expires or an infinite lease immediately.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
|
|
||||||
func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac ModifiedAccessConditions) (*BlobBreakLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
|
|
||||||
return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds),
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeLease changes the blob's lease ID.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
|
|
||||||
func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*BlobChangeLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
|
|
||||||
return b.blobClient.ChangeLease(ctx, leaseID, proposedID,
|
|
||||||
nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaseBreakNaturally tells ContainerURL's or BlobURL's BreakLease method to break the lease using service semantics.
|
|
||||||
const LeaseBreakNaturally = -1
|
|
||||||
|
|
||||||
func leasePeriodPointer(period int32) (p *int32) {
|
|
||||||
if period != LeaseBreakNaturally {
|
|
||||||
p = &period
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartCopyFromURL copies the data at the source URL to a blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob.
|
|
||||||
func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions) (*BlobStartCopyFromURLResponse, error) {
|
|
||||||
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
|
|
||||||
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
|
|
||||||
dstLeaseID := dstac.LeaseAccessConditions.pointers()
|
|
||||||
|
|
||||||
return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata,
|
|
||||||
AccessTierNone, RehydratePriorityNone, srcIfModifiedSince, srcIfUnmodifiedSince,
|
|
||||||
srcIfMatchETag, srcIfNoneMatchETag,
|
|
||||||
dstIfModifiedSince, dstIfUnmodifiedSince,
|
|
||||||
dstIfMatchETag, dstIfNoneMatchETag,
|
|
||||||
dstLeaseID, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/abort-copy-blob.
|
|
||||||
func (b BlobURL) AbortCopyFromURL(ctx context.Context, copyID string, ac LeaseAccessConditions) (*BlobAbortCopyFromURLResponse, error) {
|
|
||||||
return b.blobClient.AbortCopyFromURL(ctx, copyID, nil, ac.pointers(), nil)
|
|
||||||
}
|
|
134
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_block_blob.go
generated
vendored
134
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_block_blob.go
generated
vendored
@ -1,134 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// BlockBlobMaxUploadBlobBytes indicates the maximum number of bytes that can be sent in a call to Upload.
|
|
||||||
BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB
|
|
||||||
|
|
||||||
// BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock.
|
|
||||||
BlockBlobMaxStageBlockBytes = 100 * 1024 * 1024 // 100MB
|
|
||||||
|
|
||||||
// BlockBlobMaxBlocks indicates the maximum number of blocks allowed in a block blob.
|
|
||||||
BlockBlobMaxBlocks = 50000
|
|
||||||
)
|
|
||||||
|
|
||||||
// BlockBlobURL defines a set of operations applicable to block blobs.
|
|
||||||
type BlockBlobURL struct {
|
|
||||||
BlobURL
|
|
||||||
bbClient blockBlobClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlockBlobURL creates a BlockBlobURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewBlockBlobURL(url url.URL, p pipeline.Pipeline) BlockBlobURL {
|
|
||||||
blobClient := newBlobClient(url, p)
|
|
||||||
bbClient := newBlockBlobClient(url, p)
|
|
||||||
return BlockBlobURL{BlobURL: BlobURL{blobClient: blobClient}, bbClient: bbClient}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new BlockBlobURL object identical to the source but with the specific request policy pipeline.
|
|
||||||
func (bb BlockBlobURL) WithPipeline(p pipeline.Pipeline) BlockBlobURL {
|
|
||||||
return NewBlockBlobURL(bb.blobClient.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSnapshot creates a new BlockBlobURL object identical to the source but with the specified snapshot timestamp.
|
|
||||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
|
||||||
func (bb BlockBlobURL) WithSnapshot(snapshot string) BlockBlobURL {
|
|
||||||
p := NewBlobURLParts(bb.URL())
|
|
||||||
p.Snapshot = snapshot
|
|
||||||
return NewBlockBlobURL(p.URL(), bb.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bb BlockBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
|
|
||||||
return bb.blobClient.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload creates a new block blob or overwrites an existing block blob.
|
|
||||||
// Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not
|
|
||||||
// supported with Upload; the content of the existing blob is overwritten with the new content. To
|
|
||||||
// perform a partial update of a block blob, use StageBlock and CommitBlockList.
|
|
||||||
// This method panics if the stream is not at position 0.
|
|
||||||
// Note that the http client closes the body stream after the request is sent to the service.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
|
|
||||||
func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*BlockBlobUploadResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
count, err := validateSeekableStreamAt0AndGetCount(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return bb.bbClient.Upload(ctx, body, count, nil, nil,
|
|
||||||
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
|
|
||||||
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
AccessTierNone, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
|
|
||||||
nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList.
|
|
||||||
// Note that the http client closes the body stream after the request is sent to the service.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block.
|
|
||||||
func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions, transactionalMD5 []byte) (*BlockBlobStageBlockResponse, error) {
|
|
||||||
count, err := validateSeekableStreamAt0AndGetCount(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return bb.bbClient.StageBlock(ctx, base64BlockID, count, body, transactionalMD5, nil, nil, ac.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList.
|
|
||||||
// If count is CountToEnd (0), then data is read from specified offset to the end.
|
|
||||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url.
|
|
||||||
func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, destinationAccessConditions LeaseAccessConditions, sourceAccessConditions ModifiedAccessConditions) (*BlockBlobStageBlockFromURLResponse, error) {
|
|
||||||
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
|
|
||||||
return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, sourceURL.String(), httpRange{offset: offset, count: count}.pointers(), nil, nil, nil,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
destinationAccessConditions.pointers(), sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob.
|
|
||||||
// In order to be written as part of a blob, a block must have been successfully written
|
|
||||||
// to the server in a prior PutBlock operation. You can call PutBlockList to update a blob
|
|
||||||
// by uploading only those blocks that have changed, then committing the new and existing
|
|
||||||
// blocks together. Any blocks not specified in the block list and permanently deleted.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list.
|
|
||||||
func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders,
|
|
||||||
metadata Metadata, ac BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil,
|
|
||||||
&h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, nil, nil,
|
|
||||||
metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
AccessTierNone,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlockList returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-block-list.
|
|
||||||
func (bb BlockBlobURL) GetBlockList(ctx context.Context, listType BlockListType, ac LeaseAccessConditions) (*BlockList, error) {
|
|
||||||
return bb.bbClient.GetBlockList(ctx, listType, nil, nil, ac.pointers(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
|
|
||||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
|
|
||||||
func (bb BlockBlobURL) CopyFromURL(ctx context.Context, source url.URL, metadata Metadata,
|
|
||||||
srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte) (*BlobCopyFromURLResponse, error) {
|
|
||||||
|
|
||||||
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
|
|
||||||
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
|
|
||||||
dstLeaseID := dstac.LeaseAccessConditions.pointers()
|
|
||||||
|
|
||||||
return bb.blobClient.CopyFromURL(ctx, source.String(), nil, metadata, AccessTierNone,
|
|
||||||
srcIfModifiedSince, srcIfUnmodifiedSince,
|
|
||||||
srcIfMatchETag, srcIfNoneMatchETag,
|
|
||||||
dstIfModifiedSince, dstIfUnmodifiedSince,
|
|
||||||
dstIfMatchETag, dstIfNoneMatchETag,
|
|
||||||
dstLeaseID, nil, srcContentMD5)
|
|
||||||
}
|
|
299
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_container.go
generated
vendored
299
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_container.go
generated
vendored
@ -1,299 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A ContainerURL represents a URL to the Azure Storage container allowing you to manipulate its blobs.
|
|
||||||
type ContainerURL struct {
|
|
||||||
client containerClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContainerURL creates a ContainerURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewContainerURL(url url.URL, p pipeline.Pipeline) ContainerURL {
|
|
||||||
client := newContainerClient(url, p)
|
|
||||||
return ContainerURL{client: client}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL returns the URL endpoint used by the ContainerURL object.
|
|
||||||
func (c ContainerURL) URL() url.URL {
|
|
||||||
return c.client.URL()
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the URL as a string.
|
|
||||||
func (c ContainerURL) String() string {
|
|
||||||
u := c.URL()
|
|
||||||
return u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ContainerURL) GetAccountInfo(ctx context.Context) (*ContainerGetAccountInfoResponse, error) {
|
|
||||||
return c.client.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new ContainerURL object identical to the source but with the specified request policy pipeline.
|
|
||||||
func (c ContainerURL) WithPipeline(p pipeline.Pipeline) ContainerURL {
|
|
||||||
return NewContainerURL(c.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlobURL creates a new BlobURL object by concatenating blobName to the end of
|
|
||||||
// ContainerURL's URL. The new BlobURL uses the same request policy pipeline as the ContainerURL.
|
|
||||||
// To change the pipeline, create the BlobURL and then call its WithPipeline method passing in the
|
|
||||||
// desired pipeline object. Or, call this package's NewBlobURL instead of calling this object's
|
|
||||||
// NewBlobURL method.
|
|
||||||
func (c ContainerURL) NewBlobURL(blobName string) BlobURL {
|
|
||||||
blobURL := appendToURLPath(c.URL(), blobName)
|
|
||||||
return NewBlobURL(blobURL, c.client.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAppendBlobURL creates a new AppendBlobURL object by concatenating blobName to the end of
|
|
||||||
// ContainerURL's URL. The new AppendBlobURL uses the same request policy pipeline as the ContainerURL.
|
|
||||||
// To change the pipeline, create the AppendBlobURL and then call its WithPipeline method passing in the
|
|
||||||
// desired pipeline object. Or, call this package's NewAppendBlobURL instead of calling this object's
|
|
||||||
// NewAppendBlobURL method.
|
|
||||||
func (c ContainerURL) NewAppendBlobURL(blobName string) AppendBlobURL {
|
|
||||||
blobURL := appendToURLPath(c.URL(), blobName)
|
|
||||||
return NewAppendBlobURL(blobURL, c.client.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlockBlobURL creates a new BlockBlobURL object by concatenating blobName to the end of
|
|
||||||
// ContainerURL's URL. The new BlockBlobURL uses the same request policy pipeline as the ContainerURL.
|
|
||||||
// To change the pipeline, create the BlockBlobURL and then call its WithPipeline method passing in the
|
|
||||||
// desired pipeline object. Or, call this package's NewBlockBlobURL instead of calling this object's
|
|
||||||
// NewBlockBlobURL method.
|
|
||||||
func (c ContainerURL) NewBlockBlobURL(blobName string) BlockBlobURL {
|
|
||||||
blobURL := appendToURLPath(c.URL(), blobName)
|
|
||||||
return NewBlockBlobURL(blobURL, c.client.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPageBlobURL creates a new PageBlobURL object by concatenating blobName to the end of
|
|
||||||
// ContainerURL's URL. The new PageBlobURL uses the same request policy pipeline as the ContainerURL.
|
|
||||||
// To change the pipeline, create the PageBlobURL and then call its WithPipeline method passing in the
|
|
||||||
// desired pipeline object. Or, call this package's NewPageBlobURL instead of calling this object's
|
|
||||||
// NewPageBlobURL method.
|
|
||||||
func (c ContainerURL) NewPageBlobURL(blobName string) PageBlobURL {
|
|
||||||
blobURL := appendToURLPath(c.URL(), blobName)
|
|
||||||
return NewPageBlobURL(blobURL, c.client.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates a new container within a storage account. If a container with the same name already exists, the operation fails.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/create-container.
|
|
||||||
func (c ContainerURL) Create(ctx context.Context, metadata Metadata, publicAccessType PublicAccessType) (*ContainerCreateResponse, error) {
|
|
||||||
return c.client.Create(ctx, nil, metadata, publicAccessType, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-container.
|
|
||||||
func (c ContainerURL) Delete(ctx context.Context, ac ContainerAccessConditions) (*ContainerDeleteResponse, error) {
|
|
||||||
if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
|
|
||||||
return nil, errors.New("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service")
|
|
||||||
}
|
|
||||||
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return c.client.Delete(ctx, nil, ac.LeaseAccessConditions.pointers(),
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProperties returns the container's properties.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-container-metadata.
|
|
||||||
func (c ContainerURL) GetProperties(ctx context.Context, ac LeaseAccessConditions) (*ContainerGetPropertiesResponse, error) {
|
|
||||||
// NOTE: GetMetadata actually calls GetProperties internally because GetProperties returns the metadata AND the properties.
|
|
||||||
// This allows us to not expose a GetProperties method at all simplifying the API.
|
|
||||||
return c.client.GetProperties(ctx, nil, ac.pointers(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMetadata sets the container's metadata.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-metadata.
|
|
||||||
func (c ContainerURL) SetMetadata(ctx context.Context, metadata Metadata, ac ContainerAccessConditions) (*ContainerSetMetadataResponse, error) {
|
|
||||||
if !ac.IfUnmodifiedSince.IsZero() || ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
|
|
||||||
return nil, errors.New("the IfUnmodifiedSince, IfMatch, and IfNoneMatch must have their default values because they are ignored by the blob service")
|
|
||||||
}
|
|
||||||
ifModifiedSince, _, _, _ := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return c.client.SetMetadata(ctx, nil, ac.LeaseAccessConditions.pointers(), metadata, ifModifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccessPolicy returns the container's access policy. The access policy indicates whether container's blobs may be accessed publicly.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-container-acl.
|
|
||||||
func (c ContainerURL) GetAccessPolicy(ctx context.Context, ac LeaseAccessConditions) (*SignedIdentifiers, error) {
|
|
||||||
return c.client.GetAccessPolicy(ctx, nil, ac.pointers(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The AccessPolicyPermission type simplifies creating the permissions string for a container's access policy.
|
|
||||||
// Initialize an instance of this type and then call its String method to set AccessPolicy's Permission field.
|
|
||||||
type AccessPolicyPermission struct {
|
|
||||||
Read, Add, Create, Write, Delete, List bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String produces the access policy permission string for an Azure Storage container.
|
|
||||||
// Call this method to set AccessPolicy's Permission field.
|
|
||||||
func (p AccessPolicyPermission) String() string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
if p.Read {
|
|
||||||
b.WriteRune('r')
|
|
||||||
}
|
|
||||||
if p.Add {
|
|
||||||
b.WriteRune('a')
|
|
||||||
}
|
|
||||||
if p.Create {
|
|
||||||
b.WriteRune('c')
|
|
||||||
}
|
|
||||||
if p.Write {
|
|
||||||
b.WriteRune('w')
|
|
||||||
}
|
|
||||||
if p.Delete {
|
|
||||||
b.WriteRune('d')
|
|
||||||
}
|
|
||||||
if p.List {
|
|
||||||
b.WriteRune('l')
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the AccessPolicyPermission's fields from a string.
|
|
||||||
func (p *AccessPolicyPermission) Parse(s string) error {
|
|
||||||
*p = AccessPolicyPermission{} // Clear the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 'r':
|
|
||||||
p.Read = true
|
|
||||||
case 'a':
|
|
||||||
p.Add = true
|
|
||||||
case 'c':
|
|
||||||
p.Create = true
|
|
||||||
case 'w':
|
|
||||||
p.Write = true
|
|
||||||
case 'd':
|
|
||||||
p.Delete = true
|
|
||||||
case 'l':
|
|
||||||
p.List = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid permission: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAccessPolicy sets the container's permissions. The access policy indicates whether blobs in a container may be accessed publicly.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-acl.
|
|
||||||
func (c ContainerURL) SetAccessPolicy(ctx context.Context, accessType PublicAccessType, si []SignedIdentifier,
|
|
||||||
ac ContainerAccessConditions) (*ContainerSetAccessPolicyResponse, error) {
|
|
||||||
if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
|
|
||||||
return nil, errors.New("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service")
|
|
||||||
}
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return c.client.SetAccessPolicy(ctx, si, nil, ac.LeaseAccessConditions.pointers(),
|
|
||||||
accessType, ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcquireLease acquires a lease on the container for delete operations. The lease duration must be between 15 to 60 seconds, or infinite (-1).
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
|
|
||||||
func (c ContainerURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*ContainerAcquireLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
|
|
||||||
return c.client.AcquireLease(ctx, nil, &duration, &proposedID,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewLease renews the container's previously-acquired lease.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
|
|
||||||
func (c ContainerURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*ContainerRenewLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
|
|
||||||
return c.client.RenewLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReleaseLease releases the container's previously-acquired lease.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
|
|
||||||
func (c ContainerURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*ContainerReleaseLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
|
|
||||||
return c.client.ReleaseLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakLease breaks the container's previously-acquired lease (if it exists).
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
|
|
||||||
func (c ContainerURL) BreakLease(ctx context.Context, period int32, ac ModifiedAccessConditions) (*ContainerBreakLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
|
|
||||||
return c.client.BreakLease(ctx, nil, leasePeriodPointer(period), ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeLease changes the container's lease ID.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
|
|
||||||
func (c ContainerURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*ContainerChangeLeaseResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
|
|
||||||
return c.client.ChangeLease(ctx, leaseID, proposedID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBlobsFlatSegment returns a single segment of blobs starting from the specified Marker. Use an empty
|
|
||||||
// Marker to start enumeration from the beginning. Blob names are returned in lexicographic order.
|
|
||||||
// After getting a segment, process it, and then call ListBlobsFlatSegment again (passing the the
|
|
||||||
// previously-returned Marker) to get the next segment.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs.
|
|
||||||
func (c ContainerURL) ListBlobsFlatSegment(ctx context.Context, marker Marker, o ListBlobsSegmentOptions) (*ListBlobsFlatSegmentResponse, error) {
|
|
||||||
prefix, include, maxResults := o.pointers()
|
|
||||||
return c.client.ListBlobFlatSegment(ctx, prefix, marker.Val, maxResults, include, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBlobsHierarchySegment returns a single segment of blobs starting from the specified Marker. Use an empty
|
|
||||||
// Marker to start enumeration from the beginning. Blob names are returned in lexicographic order.
|
|
||||||
// After getting a segment, process it, and then call ListBlobsHierarchicalSegment again (passing the the
|
|
||||||
// previously-returned Marker) to get the next segment.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs.
|
|
||||||
func (c ContainerURL) ListBlobsHierarchySegment(ctx context.Context, marker Marker, delimiter string, o ListBlobsSegmentOptions) (*ListBlobsHierarchySegmentResponse, error) {
|
|
||||||
if o.Details.Snapshots {
|
|
||||||
return nil, errors.New("snapshots are not supported in this listing operation")
|
|
||||||
}
|
|
||||||
prefix, include, maxResults := o.pointers()
|
|
||||||
return c.client.ListBlobHierarchySegment(ctx, delimiter, prefix, marker.Val, maxResults, include, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBlobsSegmentOptions defines options available when calling ListBlobs.
|
|
||||||
type ListBlobsSegmentOptions struct {
|
|
||||||
Details BlobListingDetails // No IncludeType header is produced if ""
|
|
||||||
Prefix string // No Prefix header is produced if ""
|
|
||||||
|
|
||||||
// SetMaxResults sets the maximum desired results you want the service to return. Note, the
|
|
||||||
// service may return fewer results than requested.
|
|
||||||
// MaxResults=0 means no 'MaxResults' header specified.
|
|
||||||
MaxResults int32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ListBlobsSegmentOptions) pointers() (prefix *string, include []ListBlobsIncludeItemType, maxResults *int32) {
|
|
||||||
if o.Prefix != "" {
|
|
||||||
prefix = &o.Prefix
|
|
||||||
}
|
|
||||||
include = o.Details.slice()
|
|
||||||
if o.MaxResults != 0 {
|
|
||||||
maxResults = &o.MaxResults
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobListingDetails indicates what additional information the service should return with each blob.
|
|
||||||
type BlobListingDetails struct {
|
|
||||||
Copy, Metadata, Snapshots, UncommittedBlobs, Deleted bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// string produces the Include query parameter's value.
|
|
||||||
func (d *BlobListingDetails) slice() []ListBlobsIncludeItemType {
|
|
||||||
items := []ListBlobsIncludeItemType{}
|
|
||||||
// NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails!
|
|
||||||
if d.Copy {
|
|
||||||
items = append(items, ListBlobsIncludeItemCopy)
|
|
||||||
}
|
|
||||||
if d.Deleted {
|
|
||||||
items = append(items, ListBlobsIncludeItemDeleted)
|
|
||||||
}
|
|
||||||
if d.Metadata {
|
|
||||||
items = append(items, ListBlobsIncludeItemMetadata)
|
|
||||||
}
|
|
||||||
if d.Snapshots {
|
|
||||||
items = append(items, ListBlobsIncludeItemSnapshots)
|
|
||||||
}
|
|
||||||
if d.UncommittedBlobs {
|
|
||||||
items = append(items, ListBlobsIncludeItemUncommittedblobs)
|
|
||||||
}
|
|
||||||
return items
|
|
||||||
}
|
|
233
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_page_blob.go
generated
vendored
233
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_page_blob.go
generated
vendored
@ -1,233 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// PageBlobPageBytes indicates the number of bytes in a page (512).
|
|
||||||
PageBlobPageBytes = 512
|
|
||||||
|
|
||||||
// PageBlobMaxPutPagesBytes indicates the maximum number of bytes that can be sent in a call to PutPage.
|
|
||||||
PageBlobMaxUploadPagesBytes = 4 * 1024 * 1024 // 4MB
|
|
||||||
)
|
|
||||||
|
|
||||||
// PageBlobURL defines a set of operations applicable to page blobs.
|
|
||||||
type PageBlobURL struct {
|
|
||||||
BlobURL
|
|
||||||
pbClient pageBlobClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPageBlobURL creates a PageBlobURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewPageBlobURL(url url.URL, p pipeline.Pipeline) PageBlobURL {
|
|
||||||
blobClient := newBlobClient(url, p)
|
|
||||||
pbClient := newPageBlobClient(url, p)
|
|
||||||
return PageBlobURL{BlobURL: BlobURL{blobClient: blobClient}, pbClient: pbClient}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new PageBlobURL object identical to the source but with the specific request policy pipeline.
|
|
||||||
func (pb PageBlobURL) WithPipeline(p pipeline.Pipeline) PageBlobURL {
|
|
||||||
return NewPageBlobURL(pb.blobClient.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSnapshot creates a new PageBlobURL object identical to the source but with the specified snapshot timestamp.
|
|
||||||
// Pass "" to remove the snapshot returning a URL to the base blob.
|
|
||||||
func (pb PageBlobURL) WithSnapshot(snapshot string) PageBlobURL {
|
|
||||||
p := NewBlobURLParts(pb.URL())
|
|
||||||
p.Snapshot = snapshot
|
|
||||||
return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pb PageBlobURL) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
|
|
||||||
return pb.blobClient.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates a page blob of the specified length. Call PutPage to upload data data to a page blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
|
|
||||||
func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*PageBlobCreateResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return pb.pbClient.Create(ctx, 0, size, nil, PremiumPageBlobAccessTierNone,
|
|
||||||
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl,
|
|
||||||
metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &sequenceNumber, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes.
|
|
||||||
// This method panics if the stream is not at position 0.
|
|
||||||
// Note that the http client closes the body stream after the request is sent to the service.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
|
|
||||||
func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac PageBlobAccessConditions, transactionalMD5 []byte) (*PageBlobUploadPagesResponse, error) {
|
|
||||||
count, err := validateSeekableStreamAt0AndGetCount(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
|
|
||||||
return pb.pbClient.UploadPages(ctx, body, count, transactionalMD5, nil, nil,
|
|
||||||
PageRange{Start: offset, End: offset + count - 1}.pointers(),
|
|
||||||
ac.LeaseAccessConditions.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadPagesFromURL copies 1 or more pages from a source URL to the page blob.
|
|
||||||
// The sourceOffset specifies the start offset of source data to copy from.
|
|
||||||
// The destOffset specifies the start offset of data in page blob will be written to.
|
|
||||||
// The count must be a multiple of 512 bytes.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page-from-url.
|
|
||||||
func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL, sourceOffset int64, destOffset int64, count int64, transactionalMD5 []byte, destinationAccessConditions PageBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions) (*PageBlobUploadPagesFromURLResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
|
|
||||||
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := destinationAccessConditions.SequenceNumberAccessConditions.pointers()
|
|
||||||
return pb.pbClient.UploadPagesFromURL(ctx, sourceURL.String(), *PageRange{Start: sourceOffset, End: sourceOffset + count - 1}.pointers(), 0,
|
|
||||||
*PageRange{Start: destOffset, End: destOffset + count - 1}.pointers(), transactionalMD5, nil, nil,
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
destinationAccessConditions.LeaseAccessConditions.pointers(),
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearPages frees the specified pages from the page blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
|
|
||||||
func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac PageBlobAccessConditions) (*PageBlobClearPagesResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
|
|
||||||
return pb.pbClient.ClearPages(ctx, 0, nil,
|
|
||||||
PageRange{Start: offset, End: offset + count - 1}.pointers(),
|
|
||||||
ac.LeaseAccessConditions.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan,
|
|
||||||
ifSequenceNumberEqual, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPageRanges returns the list of valid page ranges for a page blob or snapshot of a page blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges.
|
|
||||||
func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageList, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return pb.pbClient.GetPageRanges(ctx, nil, nil,
|
|
||||||
httpRange{offset: offset, count: count}.pointers(),
|
|
||||||
ac.LeaseAccessConditions.pointers(),
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges.
|
|
||||||
func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot,
|
|
||||||
httpRange{offset: offset, count: count}.pointers(),
|
|
||||||
ac.LeaseAccessConditions.pointers(),
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
|
|
||||||
nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize resizes the page blob to the specified size (which must be a multiple of 512).
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
|
|
||||||
func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions) (*PageBlobResizeResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(),
|
|
||||||
nil, nil, EncryptionAlgorithmNone, // CPK
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSequenceNumber sets the page blob's sequence number.
|
|
||||||
func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64,
|
|
||||||
ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) {
|
|
||||||
sn := &sequenceNumber
|
|
||||||
if action == SequenceNumberActionIncrement {
|
|
||||||
sn = nil
|
|
||||||
}
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers()
|
|
||||||
return pb.pbClient.UpdateSequenceNumber(ctx, action, nil,
|
|
||||||
ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch,
|
|
||||||
sn, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartIncrementalCopy begins an operation to start an incremental copy from one page blob's snapshot to this page blob.
|
|
||||||
// The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination.
|
|
||||||
// The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and
|
|
||||||
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots.
|
|
||||||
func (pb PageBlobURL) StartCopyIncremental(ctx context.Context, source url.URL, snapshot string, ac BlobAccessConditions) (*PageBlobCopyIncrementalResponse, error) {
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
|
|
||||||
qp := source.Query()
|
|
||||||
qp.Set("snapshot", snapshot)
|
|
||||||
source.RawQuery = qp.Encode()
|
|
||||||
return pb.pbClient.CopyIncremental(ctx, source.String(), nil,
|
|
||||||
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pr PageRange) pointers() *string {
|
|
||||||
endOffset := strconv.FormatInt(int64(pr.End), 10)
|
|
||||||
asString := fmt.Sprintf("bytes=%v-%s", pr.Start, endOffset)
|
|
||||||
return &asString
|
|
||||||
}
|
|
||||||
|
|
||||||
type PageBlobAccessConditions struct {
|
|
||||||
ModifiedAccessConditions
|
|
||||||
LeaseAccessConditions
|
|
||||||
SequenceNumberAccessConditions
|
|
||||||
}
|
|
||||||
|
|
||||||
// SequenceNumberAccessConditions identifies page blob-specific access conditions which you optionally set.
|
|
||||||
type SequenceNumberAccessConditions struct {
|
|
||||||
// IfSequenceNumberLessThan ensures that the page blob operation succeeds
|
|
||||||
// only if the blob's sequence number is less than a value.
|
|
||||||
// IfSequenceNumberLessThan=0 means no 'IfSequenceNumberLessThan' header specified.
|
|
||||||
// IfSequenceNumberLessThan>0 means 'IfSequenceNumberLessThan' header specified with its value
|
|
||||||
// IfSequenceNumberLessThan==-1 means 'IfSequenceNumberLessThan' header specified with a value of 0
|
|
||||||
IfSequenceNumberLessThan int64
|
|
||||||
|
|
||||||
// IfSequenceNumberLessThanOrEqual ensures that the page blob operation succeeds
|
|
||||||
// only if the blob's sequence number is less than or equal to a value.
|
|
||||||
// IfSequenceNumberLessThanOrEqual=0 means no 'IfSequenceNumberLessThanOrEqual' header specified.
|
|
||||||
// IfSequenceNumberLessThanOrEqual>0 means 'IfSequenceNumberLessThanOrEqual' header specified with its value
|
|
||||||
// IfSequenceNumberLessThanOrEqual=-1 means 'IfSequenceNumberLessThanOrEqual' header specified with a value of 0
|
|
||||||
IfSequenceNumberLessThanOrEqual int64
|
|
||||||
|
|
||||||
// IfSequenceNumberEqual ensures that the page blob operation succeeds
|
|
||||||
// only if the blob's sequence number is equal to a value.
|
|
||||||
// IfSequenceNumberEqual=0 means no 'IfSequenceNumberEqual' header specified.
|
|
||||||
// IfSequenceNumberEqual>0 means 'IfSequenceNumberEqual' header specified with its value
|
|
||||||
// IfSequenceNumberEqual=-1 means 'IfSequenceNumberEqual' header specified with a value of 0
|
|
||||||
IfSequenceNumberEqual int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointers is for internal infrastructure. It returns the fields as pointers.
|
|
||||||
func (ac SequenceNumberAccessConditions) pointers() (snltoe *int64, snlt *int64, sne *int64) {
|
|
||||||
var zero int64 // Defaults to 0
|
|
||||||
switch ac.IfSequenceNumberLessThan {
|
|
||||||
case -1:
|
|
||||||
snlt = &zero
|
|
||||||
case 0:
|
|
||||||
snlt = nil
|
|
||||||
default:
|
|
||||||
snlt = &ac.IfSequenceNumberLessThan
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ac.IfSequenceNumberLessThanOrEqual {
|
|
||||||
case -1:
|
|
||||||
snltoe = &zero
|
|
||||||
case 0:
|
|
||||||
snltoe = nil
|
|
||||||
default:
|
|
||||||
snltoe = &ac.IfSequenceNumberLessThanOrEqual
|
|
||||||
}
|
|
||||||
switch ac.IfSequenceNumberEqual {
|
|
||||||
case -1:
|
|
||||||
sne = &zero
|
|
||||||
case 0:
|
|
||||||
sne = nil
|
|
||||||
default:
|
|
||||||
sne = &ac.IfSequenceNumberEqual
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
159
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_service.go
generated
vendored
159
vendor/github.com/Azure/azure-storage-blob-go/azblob/url_service.go
generated
vendored
@ -1,159 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ContainerNameRoot is the special Azure Storage name used to identify a storage account's root container.
|
|
||||||
ContainerNameRoot = "$root"
|
|
||||||
|
|
||||||
// ContainerNameLogs is the special Azure Storage name used to identify a storage account's logs container.
|
|
||||||
ContainerNameLogs = "$logs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A ServiceURL represents a URL to the Azure Storage Blob service allowing you to manipulate blob containers.
|
|
||||||
type ServiceURL struct {
|
|
||||||
client serviceClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServiceURL creates a ServiceURL object using the specified URL and request policy pipeline.
|
|
||||||
func NewServiceURL(primaryURL url.URL, p pipeline.Pipeline) ServiceURL {
|
|
||||||
client := newServiceClient(primaryURL, p)
|
|
||||||
return ServiceURL{client: client}
|
|
||||||
}
|
|
||||||
|
|
||||||
//GetUserDelegationCredential obtains a UserDelegationKey object using the base ServiceURL object.
|
|
||||||
//OAuth is required for this call, as well as any role that can delegate access to the storage account.
|
|
||||||
func (s ServiceURL) GetUserDelegationCredential(ctx context.Context, info KeyInfo, timeout *int32, requestID *string) (UserDelegationCredential, error) {
|
|
||||||
sc := newServiceClient(s.client.url, s.client.p)
|
|
||||||
udk, err := sc.GetUserDelegationKey(ctx, info, timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return UserDelegationCredential{}, err
|
|
||||||
}
|
|
||||||
return NewUserDelegationCredential(strings.Split(s.client.url.Host, ".")[0], *udk), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO this was supposed to be generated
|
|
||||||
//NewKeyInfo creates a new KeyInfo struct with the correct time formatting & conversion
|
|
||||||
func NewKeyInfo(Start, Expiry time.Time) KeyInfo {
|
|
||||||
return KeyInfo{
|
|
||||||
Start: Start.UTC().Format(SASTimeFormat),
|
|
||||||
Expiry: Expiry.UTC().Format(SASTimeFormat),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s ServiceURL) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) {
|
|
||||||
return s.client.GetAccountInfo(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL returns the URL endpoint used by the ServiceURL object.
|
|
||||||
func (s ServiceURL) URL() url.URL {
|
|
||||||
return s.client.URL()
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the URL as a string.
|
|
||||||
func (s ServiceURL) String() string {
|
|
||||||
u := s.URL()
|
|
||||||
return u.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPipeline creates a new ServiceURL object identical to the source but with the specified request policy pipeline.
|
|
||||||
func (s ServiceURL) WithPipeline(p pipeline.Pipeline) ServiceURL {
|
|
||||||
return NewServiceURL(s.URL(), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContainerURL creates a new ContainerURL object by concatenating containerName to the end of
|
|
||||||
// ServiceURL's URL. The new ContainerURL uses the same request policy pipeline as the ServiceURL.
|
|
||||||
// To change the pipeline, create the ContainerURL and then call its WithPipeline method passing in the
|
|
||||||
// desired pipeline object. Or, call this package's NewContainerURL instead of calling this object's
|
|
||||||
// NewContainerURL method.
|
|
||||||
func (s ServiceURL) NewContainerURL(containerName string) ContainerURL {
|
|
||||||
containerURL := appendToURLPath(s.URL(), containerName)
|
|
||||||
return NewContainerURL(containerURL, s.client.Pipeline())
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendToURLPath appends a string to the end of a URL's path (prefixing the string with a '/' if required)
|
|
||||||
func appendToURLPath(u url.URL, name string) url.URL {
|
|
||||||
// e.g. "https://ms.com/a/b/?k1=v1&k2=v2#f"
|
|
||||||
// When you call url.Parse() this is what you'll get:
|
|
||||||
// Scheme: "https"
|
|
||||||
// Opaque: ""
|
|
||||||
// User: nil
|
|
||||||
// Host: "ms.com"
|
|
||||||
// Path: "/a/b/" This should start with a / and it might or might not have a trailing slash
|
|
||||||
// RawPath: ""
|
|
||||||
// ForceQuery: false
|
|
||||||
// RawQuery: "k1=v1&k2=v2"
|
|
||||||
// Fragment: "f"
|
|
||||||
if len(u.Path) == 0 || u.Path[len(u.Path)-1] != '/' {
|
|
||||||
u.Path += "/" // Append "/" to end before appending name
|
|
||||||
}
|
|
||||||
u.Path += name
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListContainersFlatSegment returns a single segment of containers starting from the specified Marker. Use an empty
|
|
||||||
// Marker to start enumeration from the beginning. Container names are returned in lexicographic order.
|
|
||||||
// After getting a segment, process it, and then call ListContainersFlatSegment again (passing the the
|
|
||||||
// previously-returned Marker) to get the next segment. For more information, see
|
|
||||||
// https://docs.microsoft.com/rest/api/storageservices/list-containers2.
|
|
||||||
func (s ServiceURL) ListContainersSegment(ctx context.Context, marker Marker, o ListContainersSegmentOptions) (*ListContainersSegmentResponse, error) {
|
|
||||||
prefix, include, maxResults := o.pointers()
|
|
||||||
return s.client.ListContainersSegment(ctx, prefix, marker.Val, maxResults, include, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListContainersOptions defines options available when calling ListContainers.
|
|
||||||
type ListContainersSegmentOptions struct {
|
|
||||||
Detail ListContainersDetail // No IncludeType header is produced if ""
|
|
||||||
Prefix string // No Prefix header is produced if ""
|
|
||||||
MaxResults int32 // 0 means unspecified
|
|
||||||
// TODO: update swagger to generate this type?
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ListContainersSegmentOptions) pointers() (prefix *string, include ListContainersIncludeType, maxResults *int32) {
|
|
||||||
if o.Prefix != "" {
|
|
||||||
prefix = &o.Prefix
|
|
||||||
}
|
|
||||||
if o.MaxResults != 0 {
|
|
||||||
maxResults = &o.MaxResults
|
|
||||||
}
|
|
||||||
include = ListContainersIncludeType(o.Detail.string())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListContainersFlatDetail indicates what additional information the service should return with each container.
|
|
||||||
type ListContainersDetail struct {
|
|
||||||
// Tells the service whether to return metadata for each container.
|
|
||||||
Metadata bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// string produces the Include query parameter's value.
|
|
||||||
func (d *ListContainersDetail) string() string {
|
|
||||||
items := make([]string, 0, 1)
|
|
||||||
// NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails!
|
|
||||||
if d.Metadata {
|
|
||||||
items = append(items, string(ListContainersIncludeMetadata))
|
|
||||||
}
|
|
||||||
if len(items) > 0 {
|
|
||||||
return strings.Join(items, ",")
|
|
||||||
}
|
|
||||||
return string(ListContainersIncludeNone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bsu ServiceURL) GetProperties(ctx context.Context) (*StorageServiceProperties, error) {
|
|
||||||
return bsu.client.GetProperties(ctx, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bsu ServiceURL) SetProperties(ctx context.Context, properties StorageServiceProperties) (*ServiceSetPropertiesResponse, error) {
|
|
||||||
return bsu.client.SetProperties(ctx, properties, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bsu ServiceURL) GetStatistics(ctx context.Context) (*StorageServiceStats, error) {
|
|
||||||
return bsu.client.GetStatistics(ctx, nil, nil)
|
|
||||||
}
|
|
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/user_delegation_credential.go
generated
vendored
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/user_delegation_credential.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewUserDelegationCredential creates a new UserDelegationCredential using a Storage account's name and a user delegation key from it
|
|
||||||
func NewUserDelegationCredential(accountName string, key UserDelegationKey) UserDelegationCredential {
|
|
||||||
return UserDelegationCredential{
|
|
||||||
accountName: accountName,
|
|
||||||
accountKey: key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserDelegationCredential struct {
|
|
||||||
accountName string
|
|
||||||
accountKey UserDelegationKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountName returns the Storage account's name
|
|
||||||
func (f UserDelegationCredential) AccountName() string {
|
|
||||||
return f.accountName
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputeHMAC
|
|
||||||
func (f UserDelegationCredential) ComputeHMACSHA256(message string) (base64String string) {
|
|
||||||
bytes, _ := base64.StdEncoding.DecodeString(f.accountKey.Value)
|
|
||||||
h := hmac.New(sha256.New, bytes)
|
|
||||||
h.Write([]byte(message))
|
|
||||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private method to return important parameters for NewSASQueryParameters
|
|
||||||
func (f UserDelegationCredential) getUDKParams() *UserDelegationKey {
|
|
||||||
return &f.accountKey
|
|
||||||
}
|
|
3
vendor/github.com/Azure/azure-storage-blob-go/azblob/version.go
generated
vendored
3
vendor/github.com/Azure/azure-storage-blob-go/azblob/version.go
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
const serviceLibVersion = "0.10"
|
|
55
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_anonymous.go
generated
vendored
55
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_anonymous.go
generated
vendored
@ -1,55 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Credential represent any credential type; it is used to create a credential policy Factory.
|
|
||||||
type Credential interface {
|
|
||||||
pipeline.Factory
|
|
||||||
credentialMarker()
|
|
||||||
}
|
|
||||||
|
|
||||||
type credentialFunc pipeline.FactoryFunc
|
|
||||||
|
|
||||||
func (f credentialFunc) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return f(next, po)
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialMarker is a package-internal method that exists just to satisfy the Credential interface.
|
|
||||||
func (credentialFunc) credentialMarker() {}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
|
|
||||||
// NewAnonymousCredential creates an anonymous credential for use with HTTP(S) requests that read public resource
|
|
||||||
// or for use with Shared Access Signatures (SAS).
|
|
||||||
func NewAnonymousCredential() Credential {
|
|
||||||
return anonymousCredentialFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
var anonymousCredentialFactory Credential = &anonymousCredentialPolicyFactory{} // Singleton
|
|
||||||
|
|
||||||
// anonymousCredentialPolicyFactory is the credential's policy factory.
|
|
||||||
type anonymousCredentialPolicyFactory struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a credential policy object.
|
|
||||||
func (f *anonymousCredentialPolicyFactory) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return &anonymousCredentialPolicy{next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialMarker is a package-internal method that exists just to satisfy the Credential interface.
|
|
||||||
func (*anonymousCredentialPolicyFactory) credentialMarker() {}
|
|
||||||
|
|
||||||
// anonymousCredentialPolicy is the credential's policy object.
|
|
||||||
type anonymousCredentialPolicy struct {
|
|
||||||
next pipeline.Policy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do implements the credential's policy interface.
|
|
||||||
func (p anonymousCredentialPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
// For anonymous credentials, this is effectively a no-op
|
|
||||||
return p.next.Do(ctx, request)
|
|
||||||
}
|
|
205
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_shared_key.go
generated
vendored
205
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_shared_key.go
generated
vendored
@ -1,205 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
|
|
||||||
// storage account's name and either its primary or secondary key.
|
|
||||||
func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) {
|
|
||||||
bytes, err := base64.StdEncoding.DecodeString(accountKey)
|
|
||||||
if err != nil {
|
|
||||||
return &SharedKeyCredential{}, err
|
|
||||||
}
|
|
||||||
return &SharedKeyCredential{accountName: accountName, accountKey: bytes}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SharedKeyCredential contains an account's name and its primary or secondary key.
|
|
||||||
// It is immutable making it shareable and goroutine-safe.
|
|
||||||
type SharedKeyCredential struct {
|
|
||||||
// Only the NewSharedKeyCredential method should set these; all other methods should treat them as read-only
|
|
||||||
accountName string
|
|
||||||
accountKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountName returns the Storage account's name.
|
|
||||||
func (f SharedKeyCredential) AccountName() string {
|
|
||||||
return f.accountName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f SharedKeyCredential) getAccountKey() []byte {
|
|
||||||
return f.accountKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// noop function to satisfy StorageAccountCredential interface
|
|
||||||
func (f SharedKeyCredential) getUDKParams() *UserDelegationKey {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a credential policy object.
|
|
||||||
func (f *SharedKeyCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
// Add a x-ms-date header if it doesn't already exist
|
|
||||||
if d := request.Header.Get(headerXmsDate); d == "" {
|
|
||||||
request.Header[headerXmsDate] = []string{time.Now().UTC().Format(http.TimeFormat)}
|
|
||||||
}
|
|
||||||
stringToSign, err := f.buildStringToSign(request)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signature := f.ComputeHMACSHA256(stringToSign)
|
|
||||||
authHeader := strings.Join([]string{"SharedKey ", f.accountName, ":", signature}, "")
|
|
||||||
request.Header[headerAuthorization] = []string{authHeader}
|
|
||||||
|
|
||||||
response, err := next.Do(ctx, request)
|
|
||||||
if err != nil && response != nil && response.Response() != nil && response.Response().StatusCode == http.StatusForbidden {
|
|
||||||
// Service failed to authenticate request, log it
|
|
||||||
po.Log(pipeline.LogError, "===== HTTP Forbidden status, String-to-Sign:\n"+stringToSign+"\n===============================\n")
|
|
||||||
}
|
|
||||||
return response, err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialMarker is a package-internal method that exists just to satisfy the Credential interface.
|
|
||||||
func (*SharedKeyCredential) credentialMarker() {}
|
|
||||||
|
|
||||||
// Constants ensuring that header names are correctly spelled and consistently cased.
|
|
||||||
const (
|
|
||||||
headerAuthorization = "Authorization"
|
|
||||||
headerCacheControl = "Cache-Control"
|
|
||||||
headerContentEncoding = "Content-Encoding"
|
|
||||||
headerContentDisposition = "Content-Disposition"
|
|
||||||
headerContentLanguage = "Content-Language"
|
|
||||||
headerContentLength = "Content-Length"
|
|
||||||
headerContentMD5 = "Content-MD5"
|
|
||||||
headerContentType = "Content-Type"
|
|
||||||
headerDate = "Date"
|
|
||||||
headerIfMatch = "If-Match"
|
|
||||||
headerIfModifiedSince = "If-Modified-Since"
|
|
||||||
headerIfNoneMatch = "If-None-Match"
|
|
||||||
headerIfUnmodifiedSince = "If-Unmodified-Since"
|
|
||||||
headerRange = "Range"
|
|
||||||
headerUserAgent = "User-Agent"
|
|
||||||
headerXmsDate = "x-ms-date"
|
|
||||||
headerXmsVersion = "x-ms-version"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ComputeHMACSHA256 generates a hash signature for an HTTP request or for a SAS.
|
|
||||||
func (f SharedKeyCredential) ComputeHMACSHA256(message string) (base64String string) {
|
|
||||||
h := hmac.New(sha256.New, f.accountKey)
|
|
||||||
h.Write([]byte(message))
|
|
||||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) (string, error) {
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
|
|
||||||
headers := request.Header
|
|
||||||
contentLength := headers.Get(headerContentLength)
|
|
||||||
if contentLength == "0" {
|
|
||||||
contentLength = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
canonicalizedResource, err := f.buildCanonicalizedResource(request.URL)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stringToSign := strings.Join([]string{
|
|
||||||
request.Method,
|
|
||||||
headers.Get(headerContentEncoding),
|
|
||||||
headers.Get(headerContentLanguage),
|
|
||||||
contentLength,
|
|
||||||
headers.Get(headerContentMD5),
|
|
||||||
headers.Get(headerContentType),
|
|
||||||
"", // Empty date because x-ms-date is expected (as per web page above)
|
|
||||||
headers.Get(headerIfModifiedSince),
|
|
||||||
headers.Get(headerIfMatch),
|
|
||||||
headers.Get(headerIfNoneMatch),
|
|
||||||
headers.Get(headerIfUnmodifiedSince),
|
|
||||||
headers.Get(headerRange),
|
|
||||||
buildCanonicalizedHeader(headers),
|
|
||||||
canonicalizedResource,
|
|
||||||
}, "\n")
|
|
||||||
return stringToSign, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildCanonicalizedHeader(headers http.Header) string {
|
|
||||||
cm := map[string][]string{}
|
|
||||||
for k, v := range headers {
|
|
||||||
headerName := strings.TrimSpace(strings.ToLower(k))
|
|
||||||
if strings.HasPrefix(headerName, "x-ms-") {
|
|
||||||
cm[headerName] = v // NOTE: the value must not have any whitespace around it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(cm) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
keys := make([]string, 0, len(cm))
|
|
||||||
for key := range cm {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
ch := bytes.NewBufferString("")
|
|
||||||
for i, key := range keys {
|
|
||||||
if i > 0 {
|
|
||||||
ch.WriteRune('\n')
|
|
||||||
}
|
|
||||||
ch.WriteString(key)
|
|
||||||
ch.WriteRune(':')
|
|
||||||
ch.WriteString(strings.Join(cm[key], ","))
|
|
||||||
}
|
|
||||||
return string(ch.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) (string, error) {
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
|
|
||||||
cr := bytes.NewBufferString("/")
|
|
||||||
cr.WriteString(f.accountName)
|
|
||||||
|
|
||||||
if len(u.Path) > 0 {
|
|
||||||
// Any portion of the CanonicalizedResource string that is derived from
|
|
||||||
// the resource's URI should be encoded exactly as it is in the URI.
|
|
||||||
// -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx
|
|
||||||
cr.WriteString(u.EscapedPath())
|
|
||||||
} else {
|
|
||||||
// a slash is required to indicate the root path
|
|
||||||
cr.WriteString("/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// params is a map[string][]string; param name is key; params values is []string
|
|
||||||
params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("parsing query parameters must succeed, otherwise there might be serious problems in the SDK/generated code")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params) > 0 { // There is at least 1 query parameter
|
|
||||||
paramNames := []string{} // We use this to sort the parameter key names
|
|
||||||
for paramName := range params {
|
|
||||||
paramNames = append(paramNames, paramName) // paramNames must be lowercase
|
|
||||||
}
|
|
||||||
sort.Strings(paramNames)
|
|
||||||
|
|
||||||
for _, paramName := range paramNames {
|
|
||||||
paramValues := params[paramName]
|
|
||||||
sort.Strings(paramValues)
|
|
||||||
|
|
||||||
// Join the sorted key values separated by ','
|
|
||||||
// Then prepend "keyName:"; then add this string to the buffer
|
|
||||||
cr.WriteString("\n" + paramName + ":" + strings.Join(paramValues, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(cr.Bytes()), nil
|
|
||||||
}
|
|
137
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_token.go
generated
vendored
137
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_credential_token.go
generated
vendored
@ -1,137 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TokenRefresher represents a callback method that you write; this method is called periodically
|
|
||||||
// so you can refresh the token credential's value.
|
|
||||||
type TokenRefresher func(credential TokenCredential) time.Duration
|
|
||||||
|
|
||||||
// TokenCredential represents a token credential (which is also a pipeline.Factory).
|
|
||||||
type TokenCredential interface {
|
|
||||||
Credential
|
|
||||||
Token() string
|
|
||||||
SetToken(newToken string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTokenCredential creates a token credential for use with role-based access control (RBAC) access to Azure Storage
|
|
||||||
// resources. You initialize the TokenCredential with an initial token value. If you pass a non-nil value for
|
|
||||||
// tokenRefresher, then the function you pass will be called immediately so it can refresh and change the
|
|
||||||
// TokenCredential's token value by calling SetToken. Your tokenRefresher function must return a time.Duration
|
|
||||||
// indicating how long the TokenCredential object should wait before calling your tokenRefresher function again.
|
|
||||||
// If your tokenRefresher callback fails to refresh the token, you can return a duration of 0 to stop your
|
|
||||||
// TokenCredential object from ever invoking tokenRefresher again. Also, oen way to deal with failing to refresh a
|
|
||||||
// token is to cancel a context.Context object used by requests that have the TokenCredential object in their pipeline.
|
|
||||||
func NewTokenCredential(initialToken string, tokenRefresher TokenRefresher) TokenCredential {
|
|
||||||
tc := &tokenCredential{}
|
|
||||||
tc.SetToken(initialToken) // We don't set it above to guarantee atomicity
|
|
||||||
if tokenRefresher == nil {
|
|
||||||
return tc // If no callback specified, return the simple tokenCredential
|
|
||||||
}
|
|
||||||
|
|
||||||
tcwr := &tokenCredentialWithRefresh{token: tc}
|
|
||||||
tcwr.token.startRefresh(tokenRefresher)
|
|
||||||
runtime.SetFinalizer(tcwr, func(deadTC *tokenCredentialWithRefresh) {
|
|
||||||
deadTC.token.stopRefresh()
|
|
||||||
deadTC.token = nil // Sanity (not really required)
|
|
||||||
})
|
|
||||||
return tcwr
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenCredentialWithRefresh is a wrapper over a token credential.
|
|
||||||
// When this wrapper object gets GC'd, it stops the tokenCredential's timer
|
|
||||||
// which allows the tokenCredential object to also be GC'd.
|
|
||||||
type tokenCredentialWithRefresh struct {
|
|
||||||
token *tokenCredential
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialMarker is a package-internal method that exists just to satisfy the Credential interface.
|
|
||||||
func (*tokenCredentialWithRefresh) credentialMarker() {}
|
|
||||||
|
|
||||||
// Token returns the current token value
|
|
||||||
func (f *tokenCredentialWithRefresh) Token() string { return f.token.Token() }
|
|
||||||
|
|
||||||
// SetToken changes the current token value
|
|
||||||
func (f *tokenCredentialWithRefresh) SetToken(token string) { f.token.SetToken(token) }
|
|
||||||
|
|
||||||
// New satisfies pipeline.Factory's New method creating a pipeline policy object.
|
|
||||||
func (f *tokenCredentialWithRefresh) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return f.token.New(next, po)
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// tokenCredential is a pipeline.Factory is the credential's policy factory.
|
|
||||||
type tokenCredential struct {
|
|
||||||
token atomic.Value
|
|
||||||
|
|
||||||
// The members below are only used if the user specified a tokenRefresher callback function.
|
|
||||||
timer *time.Timer
|
|
||||||
tokenRefresher TokenRefresher
|
|
||||||
lock sync.Mutex
|
|
||||||
stopped bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialMarker is a package-internal method that exists just to satisfy the Credential interface.
|
|
||||||
func (*tokenCredential) credentialMarker() {}
|
|
||||||
|
|
||||||
// Token returns the current token value
|
|
||||||
func (f *tokenCredential) Token() string { return f.token.Load().(string) }
|
|
||||||
|
|
||||||
// SetToken changes the current token value
|
|
||||||
func (f *tokenCredential) SetToken(token string) { f.token.Store(token) }
|
|
||||||
|
|
||||||
// startRefresh calls refresh which immediately calls tokenRefresher
|
|
||||||
// and then starts a timer to call tokenRefresher in the future.
|
|
||||||
func (f *tokenCredential) startRefresh(tokenRefresher TokenRefresher) {
|
|
||||||
f.tokenRefresher = tokenRefresher
|
|
||||||
f.stopped = false // In case user calls StartRefresh, StopRefresh, & then StartRefresh again
|
|
||||||
f.refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
// refresh calls the user's tokenRefresher so they can refresh the token (by
|
|
||||||
// calling SetToken) and then starts another time (based on the returned duration)
|
|
||||||
// in order to refresh the token again in the future.
|
|
||||||
func (f *tokenCredential) refresh() {
|
|
||||||
d := f.tokenRefresher(f) // Invoke the user's refresh callback outside of the lock
|
|
||||||
if d > 0 { // If duration is 0 or negative, refresher wants to not be called again
|
|
||||||
f.lock.Lock()
|
|
||||||
if !f.stopped {
|
|
||||||
f.timer = time.AfterFunc(d, f.refresh)
|
|
||||||
}
|
|
||||||
f.lock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stopRefresh stops any pending timer and sets stopped field to true to prevent
|
|
||||||
// any new timer from starting.
|
|
||||||
// NOTE: Stopping the timer allows the GC to destroy the tokenCredential object.
|
|
||||||
func (f *tokenCredential) stopRefresh() {
|
|
||||||
f.lock.Lock()
|
|
||||||
f.stopped = true
|
|
||||||
if f.timer != nil {
|
|
||||||
f.timer.Stop()
|
|
||||||
}
|
|
||||||
f.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// New satisfies pipeline.Factory's New method creating a pipeline policy object.
|
|
||||||
func (f *tokenCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
if request.URL.Scheme != "https" {
|
|
||||||
// HTTPS must be used, otherwise the tokens are at the risk of being exposed
|
|
||||||
return nil, errors.New("token credentials require a URL using the https protocol scheme")
|
|
||||||
}
|
|
||||||
request.Header[headerAuthorization] = []string{"Bearer " + f.Token()}
|
|
||||||
return next.Do(ctx, request)
|
|
||||||
})
|
|
||||||
}
|
|
28
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_mmf_unix.go
generated
vendored
28
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_mmf_unix.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
// +build linux darwin freebsd openbsd netbsd dragonfly solaris
|
|
||||||
|
|
||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mmf []byte
|
|
||||||
|
|
||||||
func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) {
|
|
||||||
prot, flags := unix.PROT_READ, unix.MAP_SHARED // Assume read-only
|
|
||||||
if writable {
|
|
||||||
prot, flags = unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED
|
|
||||||
}
|
|
||||||
addr, err := unix.Mmap(int(file.Fd()), offset, length, prot, flags)
|
|
||||||
return mmf(addr), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mmf) unmap() {
|
|
||||||
err := unix.Munmap(*m)
|
|
||||||
*m = nil
|
|
||||||
if err != nil {
|
|
||||||
panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
|
|
||||||
}
|
|
||||||
}
|
|
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_mmf_windows.go
generated
vendored
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_mmf_windows.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mmf []byte
|
|
||||||
|
|
||||||
func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) {
|
|
||||||
prot, access := uint32(syscall.PAGE_READONLY), uint32(syscall.FILE_MAP_READ) // Assume read-only
|
|
||||||
if writable {
|
|
||||||
prot, access = uint32(syscall.PAGE_READWRITE), uint32(syscall.FILE_MAP_WRITE)
|
|
||||||
}
|
|
||||||
hMMF, errno := syscall.CreateFileMapping(syscall.Handle(file.Fd()), nil, prot, uint32(int64(length)>>32), uint32(int64(length)&0xffffffff), nil)
|
|
||||||
if hMMF == 0 {
|
|
||||||
return nil, os.NewSyscallError("CreateFileMapping", errno)
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(hMMF)
|
|
||||||
addr, errno := syscall.MapViewOfFile(hMMF, access, uint32(offset>>32), uint32(offset&0xffffffff), uintptr(length))
|
|
||||||
m := mmf{}
|
|
||||||
h := (*reflect.SliceHeader)(unsafe.Pointer(&m))
|
|
||||||
h.Data = addr
|
|
||||||
h.Len = length
|
|
||||||
h.Cap = h.Len
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mmf) unmap() {
|
|
||||||
addr := uintptr(unsafe.Pointer(&(([]byte)(*m)[0])))
|
|
||||||
*m = mmf{}
|
|
||||||
err := syscall.UnmapViewOfFile(addr)
|
|
||||||
if err != nil {
|
|
||||||
panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
|
|
||||||
}
|
|
||||||
}
|
|
46
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_pipeline.go
generated
vendored
46
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_pipeline.go
generated
vendored
@ -1,46 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PipelineOptions is used to configure a request policy pipeline's retry policy and logging.
|
|
||||||
type PipelineOptions struct {
|
|
||||||
// Log configures the pipeline's logging infrastructure indicating what information is logged and where.
|
|
||||||
Log pipeline.LogOptions
|
|
||||||
|
|
||||||
// Retry configures the built-in retry policy behavior.
|
|
||||||
Retry RetryOptions
|
|
||||||
|
|
||||||
// RequestLog configures the built-in request logging policy.
|
|
||||||
RequestLog RequestLogOptions
|
|
||||||
|
|
||||||
// Telemetry configures the built-in telemetry policy behavior.
|
|
||||||
Telemetry TelemetryOptions
|
|
||||||
|
|
||||||
// HTTPSender configures the sender of HTTP requests
|
|
||||||
HTTPSender pipeline.Factory
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPipeline creates a Pipeline using the specified credentials and options.
|
|
||||||
func NewPipeline(c Credential, o PipelineOptions) pipeline.Pipeline {
|
|
||||||
// Closest to API goes first; closest to the wire goes last
|
|
||||||
f := []pipeline.Factory{
|
|
||||||
NewTelemetryPolicyFactory(o.Telemetry),
|
|
||||||
NewUniqueRequestIDPolicyFactory(),
|
|
||||||
NewRetryPolicyFactory(o.Retry),
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := c.(*anonymousCredentialPolicyFactory); !ok {
|
|
||||||
// For AnonymousCredential, we optimize out the policy factory since it doesn't do anything
|
|
||||||
// NOTE: The credential's policy factory must appear close to the wire so it can sign any
|
|
||||||
// changes made by other factories (like UniqueRequestIDPolicyFactory)
|
|
||||||
f = append(f, c)
|
|
||||||
}
|
|
||||||
f = append(f,
|
|
||||||
NewRequestLogPolicyFactory(o.RequestLog),
|
|
||||||
pipeline.MethodFactoryMarker()) // indicates at what stage in the pipeline the method factory is invoked
|
|
||||||
|
|
||||||
|
|
||||||
return pipeline.NewPipeline(f, pipeline.Options{HTTPSender: o.HTTPSender, Log: o.Log})
|
|
||||||
}
|
|
182
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_request_log.go
generated
vendored
182
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_request_log.go
generated
vendored
@ -1,182 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RequestLogOptions configures the retry policy's behavior.
|
|
||||||
type RequestLogOptions struct {
|
|
||||||
// LogWarningIfTryOverThreshold logs a warning if a tried operation takes longer than the specified
|
|
||||||
// duration (-1=no logging; 0=default threshold).
|
|
||||||
LogWarningIfTryOverThreshold time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o RequestLogOptions) defaults() RequestLogOptions {
|
|
||||||
if o.LogWarningIfTryOverThreshold == 0 {
|
|
||||||
// It would be good to relate this to https://azure.microsoft.com/en-us/support/legal/sla/storage/v1_2/
|
|
||||||
// But this monitors the time to get the HTTP response; NOT the time to download the response body.
|
|
||||||
o.LogWarningIfTryOverThreshold = 3 * time.Second // Default to 3 seconds
|
|
||||||
}
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRequestLogPolicyFactory creates a RequestLogPolicyFactory object configured using the specified options.
|
|
||||||
func NewRequestLogPolicyFactory(o RequestLogOptions) pipeline.Factory {
|
|
||||||
o = o.defaults() // Force defaults to be calculated
|
|
||||||
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
|
|
||||||
// These variables are per-policy; shared by multiple calls to Do
|
|
||||||
var try int32
|
|
||||||
operationStart := time.Now() // If this is the 1st try, record the operation state time
|
|
||||||
return func(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) {
|
|
||||||
try++ // The first try is #1 (not #0)
|
|
||||||
|
|
||||||
// Log the outgoing request as informational
|
|
||||||
if po.ShouldLog(pipeline.LogInfo) {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
fmt.Fprintf(b, "==> OUTGOING REQUEST (Try=%d)\n", try)
|
|
||||||
pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(request), nil, nil)
|
|
||||||
po.Log(pipeline.LogInfo, b.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the time for this particular retry operation and then Do the operation.
|
|
||||||
tryStart := time.Now()
|
|
||||||
response, err = next.Do(ctx, request) // Make the request
|
|
||||||
tryEnd := time.Now()
|
|
||||||
tryDuration := tryEnd.Sub(tryStart)
|
|
||||||
opDuration := tryEnd.Sub(operationStart)
|
|
||||||
|
|
||||||
logLevel, forceLog := pipeline.LogInfo, false // Default logging information
|
|
||||||
|
|
||||||
// If the response took too long, we'll upgrade to warning.
|
|
||||||
if o.LogWarningIfTryOverThreshold > 0 && tryDuration > o.LogWarningIfTryOverThreshold {
|
|
||||||
// Log a warning if the try duration exceeded the specified threshold
|
|
||||||
logLevel, forceLog = pipeline.LogWarning, true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil { // We got a response from the service
|
|
||||||
sc := response.Response().StatusCode
|
|
||||||
if ((sc >= 400 && sc <= 499) && sc != http.StatusNotFound && sc != http.StatusConflict && sc != http.StatusPreconditionFailed && sc != http.StatusRequestedRangeNotSatisfiable) || (sc >= 500 && sc <= 599) {
|
|
||||||
logLevel, forceLog = pipeline.LogError, true // Promote to Error any 4xx (except those listed is an error) or any 5xx
|
|
||||||
} else {
|
|
||||||
// For other status codes, we leave the level as is.
|
|
||||||
}
|
|
||||||
} else { // This error did not get an HTTP response from the service; upgrade the severity to Error
|
|
||||||
logLevel, forceLog = pipeline.LogError, true
|
|
||||||
}
|
|
||||||
|
|
||||||
if shouldLog := po.ShouldLog(logLevel); forceLog || shouldLog {
|
|
||||||
// We're going to log this; build the string to log
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
slow := ""
|
|
||||||
if o.LogWarningIfTryOverThreshold > 0 && tryDuration > o.LogWarningIfTryOverThreshold {
|
|
||||||
slow = fmt.Sprintf("[SLOW >%v]", o.LogWarningIfTryOverThreshold)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(b, "==> REQUEST/RESPONSE (Try=%d/%v%s, OpTime=%v) -- ", try, tryDuration, slow, opDuration)
|
|
||||||
if err != nil { // This HTTP request did not get a response from the service
|
|
||||||
fmt.Fprint(b, "REQUEST ERROR\n")
|
|
||||||
} else {
|
|
||||||
if logLevel == pipeline.LogError {
|
|
||||||
fmt.Fprint(b, "RESPONSE STATUS CODE ERROR\n")
|
|
||||||
} else {
|
|
||||||
fmt.Fprint(b, "RESPONSE SUCCESSFULLY RECEIVED\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(request), response.Response(), err)
|
|
||||||
if logLevel <= pipeline.LogError {
|
|
||||||
b.Write(stack()) // For errors (or lower levels), we append the stack trace (an expensive operation)
|
|
||||||
}
|
|
||||||
msg := b.String()
|
|
||||||
|
|
||||||
if forceLog {
|
|
||||||
pipeline.ForceLog(logLevel, msg)
|
|
||||||
}
|
|
||||||
if shouldLog {
|
|
||||||
po.Log(logLevel, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response, err
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// RedactSigQueryParam redacts the 'sig' query parameter in URL's raw query to protect secret.
|
|
||||||
func RedactSigQueryParam(rawQuery string) (bool, string) {
|
|
||||||
rawQuery = strings.ToLower(rawQuery) // lowercase the string so we can look for ?sig= and &sig=
|
|
||||||
sigFound := strings.Contains(rawQuery, "?sig=")
|
|
||||||
if !sigFound {
|
|
||||||
sigFound = strings.Contains(rawQuery, "&sig=")
|
|
||||||
if !sigFound {
|
|
||||||
return sigFound, rawQuery // [?|&]sig= not found; return same rawQuery passed in (no memory allocation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// [?|&]sig= found, redact its value
|
|
||||||
values, _ := url.ParseQuery(rawQuery)
|
|
||||||
for name := range values {
|
|
||||||
if strings.EqualFold(name, "sig") {
|
|
||||||
values[name] = []string{"REDACTED"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sigFound, values.Encode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func prepareRequestForLogging(request pipeline.Request) *http.Request {
|
|
||||||
req := request
|
|
||||||
if sigFound, rawQuery := RedactSigQueryParam(req.URL.RawQuery); sigFound {
|
|
||||||
// Make copy so we don't destroy the query parameters we actually need to send in the request
|
|
||||||
req = request.Copy()
|
|
||||||
req.Request.URL.RawQuery = rawQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
return prepareRequestForServiceLogging(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stack() []byte {
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
for {
|
|
||||||
n := runtime.Stack(buf, false)
|
|
||||||
if n < len(buf) {
|
|
||||||
return buf[:n]
|
|
||||||
}
|
|
||||||
buf = make([]byte, 2*len(buf))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Redact phase useful for blob and file service only. For other services,
|
|
||||||
// this method can directly return request.Request.
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
func prepareRequestForServiceLogging(request pipeline.Request) *http.Request {
|
|
||||||
req := request
|
|
||||||
if exist, key := doesHeaderExistCaseInsensitive(req.Header, xMsCopySourceHeader); exist {
|
|
||||||
req = request.Copy()
|
|
||||||
url, err := url.Parse(req.Header.Get(key))
|
|
||||||
if err == nil {
|
|
||||||
if sigFound, rawQuery := RedactSigQueryParam(url.RawQuery); sigFound {
|
|
||||||
url.RawQuery = rawQuery
|
|
||||||
req.Header.Set(xMsCopySourceHeader, url.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return req.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
const xMsCopySourceHeader = "x-ms-copy-source"
|
|
||||||
|
|
||||||
func doesHeaderExistCaseInsensitive(header http.Header, key string) (bool, string) {
|
|
||||||
for keyInHeader := range header {
|
|
||||||
if strings.EqualFold(keyInHeader, key) {
|
|
||||||
return true, keyInHeader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, ""
|
|
||||||
}
|
|
414
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_retry.go
generated
vendored
414
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_retry.go
generated
vendored
@ -1,414 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RetryPolicy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants.
|
|
||||||
type RetryPolicy int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RetryPolicyExponential tells the pipeline to use an exponential back-off retry policy
|
|
||||||
RetryPolicyExponential RetryPolicy = 0
|
|
||||||
|
|
||||||
// RetryPolicyFixed tells the pipeline to use a fixed back-off retry policy
|
|
||||||
RetryPolicyFixed RetryPolicy = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// RetryOptions configures the retry policy's behavior.
|
|
||||||
type RetryOptions struct {
|
|
||||||
// Policy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants.\
|
|
||||||
// A value of zero means that you accept our default policy.
|
|
||||||
Policy RetryPolicy
|
|
||||||
|
|
||||||
// MaxTries specifies the maximum number of attempts an operation will be tried before producing an error (0=default).
|
|
||||||
// A value of zero means that you accept our default policy. A value of 1 means 1 try and no retries.
|
|
||||||
MaxTries int32
|
|
||||||
|
|
||||||
// TryTimeout indicates the maximum time allowed for any single try of an HTTP request.
|
|
||||||
// A value of zero means that you accept our default timeout. NOTE: When transferring large amounts
|
|
||||||
// of data, the default TryTimeout will probably not be sufficient. You should override this value
|
|
||||||
// based on the bandwidth available to the host machine and proximity to the Storage service. A good
|
|
||||||
// starting point may be something like (60 seconds per MB of anticipated-payload-size).
|
|
||||||
TryTimeout time.Duration
|
|
||||||
|
|
||||||
// RetryDelay specifies the amount of delay to use before retrying an operation (0=default).
|
|
||||||
// When RetryPolicy is specified as RetryPolicyExponential, the delay increases exponentially
|
|
||||||
// with each retry up to a maximum specified by MaxRetryDelay.
|
|
||||||
// If you specify 0, then you must also specify 0 for MaxRetryDelay.
|
|
||||||
// If you specify RetryDelay, then you must also specify MaxRetryDelay, and MaxRetryDelay should be
|
|
||||||
// equal to or greater than RetryDelay.
|
|
||||||
RetryDelay time.Duration
|
|
||||||
|
|
||||||
// MaxRetryDelay specifies the maximum delay allowed before retrying an operation (0=default).
|
|
||||||
// If you specify 0, then you must also specify 0 for RetryDelay.
|
|
||||||
MaxRetryDelay time.Duration
|
|
||||||
|
|
||||||
// RetryReadsFromSecondaryHost specifies whether the retry policy should retry a read operation against another host.
|
|
||||||
// If RetryReadsFromSecondaryHost is "" (the default) then operations are not retried against another host.
|
|
||||||
// NOTE: Before setting this field, make sure you understand the issues around reading stale & potentially-inconsistent
|
|
||||||
// data at this webpage: https://docs.microsoft.com/en-us/azure/storage/common/storage-designing-ha-apps-with-ragrs
|
|
||||||
RetryReadsFromSecondaryHost string // Comment this our for non-Blob SDKs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o RetryOptions) retryReadsFromSecondaryHost() string {
|
|
||||||
return o.RetryReadsFromSecondaryHost // This is for the Blob SDK only
|
|
||||||
//return "" // This is for non-blob SDKs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o RetryOptions) defaults() RetryOptions {
|
|
||||||
// We assume the following:
|
|
||||||
// 1. o.Policy should either be RetryPolicyExponential or RetryPolicyFixed
|
|
||||||
// 2. o.MaxTries >= 0
|
|
||||||
// 3. o.TryTimeout, o.RetryDelay, and o.MaxRetryDelay >=0
|
|
||||||
// 4. o.RetryDelay <= o.MaxRetryDelay
|
|
||||||
// 5. Both o.RetryDelay and o.MaxRetryDelay must be 0 or neither can be 0
|
|
||||||
|
|
||||||
IfDefault := func(current *time.Duration, desired time.Duration) {
|
|
||||||
if *current == time.Duration(0) {
|
|
||||||
*current = desired
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set defaults if unspecified
|
|
||||||
if o.MaxTries == 0 {
|
|
||||||
o.MaxTries = 4
|
|
||||||
}
|
|
||||||
switch o.Policy {
|
|
||||||
case RetryPolicyExponential:
|
|
||||||
IfDefault(&o.TryTimeout, 1*time.Minute)
|
|
||||||
IfDefault(&o.RetryDelay, 4*time.Second)
|
|
||||||
IfDefault(&o.MaxRetryDelay, 120*time.Second)
|
|
||||||
|
|
||||||
case RetryPolicyFixed:
|
|
||||||
IfDefault(&o.TryTimeout, 1*time.Minute)
|
|
||||||
IfDefault(&o.RetryDelay, 30*time.Second)
|
|
||||||
IfDefault(&o.MaxRetryDelay, 120*time.Second)
|
|
||||||
}
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o RetryOptions) calcDelay(try int32) time.Duration { // try is >=1; never 0
|
|
||||||
pow := func(number int64, exponent int32) int64 { // pow is nested helper function
|
|
||||||
var result int64 = 1
|
|
||||||
for n := int32(0); n < exponent; n++ {
|
|
||||||
result *= number
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
delay := time.Duration(0)
|
|
||||||
switch o.Policy {
|
|
||||||
case RetryPolicyExponential:
|
|
||||||
delay = time.Duration(pow(2, try-1)-1) * o.RetryDelay
|
|
||||||
|
|
||||||
case RetryPolicyFixed:
|
|
||||||
if try > 1 { // Any try after the 1st uses the fixed delay
|
|
||||||
delay = o.RetryDelay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Introduce some jitter: [0.0, 1.0) / 2 = [0.0, 0.5) + 0.8 = [0.8, 1.3)
|
|
||||||
// For casts and rounding - be careful, as per https://github.com/golang/go/issues/20757
|
|
||||||
delay = time.Duration(float32(delay) * (rand.Float32()/2 + 0.8)) // NOTE: We want math/rand; not crypto/rand
|
|
||||||
if delay > o.MaxRetryDelay {
|
|
||||||
delay = o.MaxRetryDelay
|
|
||||||
}
|
|
||||||
return delay
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRetryPolicyFactory creates a RetryPolicyFactory object configured using the specified options.
|
|
||||||
func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
|
|
||||||
o = o.defaults() // Force defaults to be calculated
|
|
||||||
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
|
|
||||||
return func(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) {
|
|
||||||
// Before each try, we'll select either the primary or secondary URL.
|
|
||||||
primaryTry := int32(0) // This indicates how many tries we've attempted against the primary DC
|
|
||||||
|
|
||||||
// We only consider retrying against a secondary if we have a read request (GET/HEAD) AND this policy has a Secondary URL it can use
|
|
||||||
considerSecondary := (request.Method == http.MethodGet || request.Method == http.MethodHead) && o.retryReadsFromSecondaryHost() != ""
|
|
||||||
|
|
||||||
// Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2)
|
|
||||||
// When to retry: connection failure or temporary/timeout. NOTE: StorageError considers HTTP 500/503 as temporary & is therefore retryable
|
|
||||||
// If using a secondary:
|
|
||||||
// Even tries go against primary; odd tries go against the secondary
|
|
||||||
// For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, 1.2)
|
|
||||||
// If secondary gets a 404, don't fail, retry but future retries are only against the primary
|
|
||||||
// When retrying against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2))
|
|
||||||
for try := int32(1); try <= o.MaxTries; try++ {
|
|
||||||
logf("\n=====> Try=%d\n", try)
|
|
||||||
|
|
||||||
// Determine which endpoint to try. It's primary if there is no secondary or if it is an add # attempt.
|
|
||||||
tryingPrimary := !considerSecondary || (try%2 == 1)
|
|
||||||
// Select the correct host and delay
|
|
||||||
if tryingPrimary {
|
|
||||||
primaryTry++
|
|
||||||
delay := o.calcDelay(primaryTry)
|
|
||||||
logf("Primary try=%d, Delay=%v\n", primaryTry, delay)
|
|
||||||
time.Sleep(delay) // The 1st try returns 0 delay
|
|
||||||
} else {
|
|
||||||
// For casts and rounding - be careful, as per https://github.com/golang/go/issues/20757
|
|
||||||
delay := time.Duration(float32(time.Second) * (rand.Float32()/2 + 0.8))
|
|
||||||
logf("Secondary try=%d, Delay=%v\n", try-primaryTry, delay)
|
|
||||||
time.Sleep(delay) // Delay with some jitter before trying secondary
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone the original request to ensure that each try starts with the original (unmutated) request.
|
|
||||||
requestCopy := request.Copy()
|
|
||||||
|
|
||||||
// For each try, seek to the beginning of the Body stream. We do this even for the 1st try because
|
|
||||||
// the stream may not be at offset 0 when we first get it and we want the same behavior for the
|
|
||||||
// 1st try as for additional tries.
|
|
||||||
err = requestCopy.RewindBody()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("we must be able to seek on the Body Stream, otherwise retries would cause data corruption")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tryingPrimary {
|
|
||||||
requestCopy.URL.Host = o.retryReadsFromSecondaryHost()
|
|
||||||
requestCopy.Host = o.retryReadsFromSecondaryHost()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the server-side timeout query parameter "timeout=[seconds]"
|
|
||||||
timeout := int32(o.TryTimeout.Seconds()) // Max seconds per try
|
|
||||||
if deadline, ok := ctx.Deadline(); ok { // If user's ctx has a deadline, make the timeout the smaller of the two
|
|
||||||
t := int32(deadline.Sub(time.Now()).Seconds()) // Duration from now until user's ctx reaches its deadline
|
|
||||||
logf("MaxTryTimeout=%d secs, TimeTilDeadline=%d sec\n", timeout, t)
|
|
||||||
if t < timeout {
|
|
||||||
timeout = t
|
|
||||||
}
|
|
||||||
if timeout < 0 {
|
|
||||||
timeout = 0 // If timeout ever goes negative, set it to zero; this happen while debugging
|
|
||||||
}
|
|
||||||
logf("TryTimeout adjusted to=%d sec\n", timeout)
|
|
||||||
}
|
|
||||||
q := requestCopy.Request.URL.Query()
|
|
||||||
q.Set("timeout", strconv.Itoa(int(timeout+1))) // Add 1 to "round up"
|
|
||||||
requestCopy.Request.URL.RawQuery = q.Encode()
|
|
||||||
logf("Url=%s\n", requestCopy.Request.URL.String())
|
|
||||||
|
|
||||||
// Set the time for this particular retry operation and then Do the operation.
|
|
||||||
tryCtx, tryCancel := context.WithTimeout(ctx, time.Second*time.Duration(timeout))
|
|
||||||
//requestCopy.Body = &deadlineExceededReadCloser{r: requestCopy.Request.Body}
|
|
||||||
response, err = next.Do(tryCtx, requestCopy) // Make the request
|
|
||||||
/*err = improveDeadlineExceeded(err)
|
|
||||||
if err == nil {
|
|
||||||
response.Response().Body = &deadlineExceededReadCloser{r: response.Response().Body}
|
|
||||||
}*/
|
|
||||||
logf("Err=%v, response=%v\n", err, response)
|
|
||||||
|
|
||||||
action := "" // This MUST get changed within the switch code below
|
|
||||||
switch {
|
|
||||||
case ctx.Err() != nil:
|
|
||||||
action = "NoRetry: Op timeout"
|
|
||||||
case !tryingPrimary && response != nil && response.Response() != nil && response.Response().StatusCode == http.StatusNotFound:
|
|
||||||
// If attempt was against the secondary & it returned a StatusNotFound (404), then
|
|
||||||
// the resource was not found. This may be due to replication delay. So, in this
|
|
||||||
// case, we'll never try the secondary again for this operation.
|
|
||||||
considerSecondary = false
|
|
||||||
action = "Retry: Secondary URL returned 404"
|
|
||||||
case err != nil:
|
|
||||||
// NOTE: Protocol Responder returns non-nil if REST API returns invalid status code for the invoked operation.
|
|
||||||
// Use ServiceCode to verify if the error is related to storage service-side,
|
|
||||||
// ServiceCode is set only when error related to storage service happened.
|
|
||||||
if stErr, ok := err.(StorageError); ok {
|
|
||||||
if stErr.Temporary() {
|
|
||||||
action = "Retry: StorageError with error service code and Temporary()"
|
|
||||||
} else if stErr.Response() != nil && isSuccessStatusCode(stErr.Response()) { // TODO: This is a temporarily work around, remove this after protocol layer fix the issue that net.Error is wrapped as storageError
|
|
||||||
action = "Retry: StorageError with success status code"
|
|
||||||
} else {
|
|
||||||
action = "NoRetry: StorageError not Temporary() and without retriable status code"
|
|
||||||
}
|
|
||||||
} else if netErr, ok := err.(net.Error); ok {
|
|
||||||
// Use non-retriable net.Error list, but not retriable list.
|
|
||||||
// As there are errors without Temporary() implementation,
|
|
||||||
// while need be retried, like 'connection reset by peer', 'transport connection broken' and etc.
|
|
||||||
// So the SDK do retry for most of the case, unless the error should not be retried for sure.
|
|
||||||
if !isNotRetriable(netErr) {
|
|
||||||
action = "Retry: net.Error and not in the non-retriable list"
|
|
||||||
} else {
|
|
||||||
action = "NoRetry: net.Error and in the non-retriable list"
|
|
||||||
}
|
|
||||||
} else if err == io.ErrUnexpectedEOF {
|
|
||||||
action = "Retry: unexpected EOF"
|
|
||||||
} else {
|
|
||||||
action = "NoRetry: unrecognized error"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
action = "NoRetry: successful HTTP request" // no error
|
|
||||||
}
|
|
||||||
|
|
||||||
logf("Action=%s\n", action)
|
|
||||||
// fmt.Println(action + "\n") // This is where we could log the retry operation; action is why we're retrying
|
|
||||||
if action[0] != 'R' { // Retry only if action starts with 'R'
|
|
||||||
if err != nil {
|
|
||||||
tryCancel() // If we're returning an error, cancel this current/last per-retry timeout context
|
|
||||||
} else {
|
|
||||||
// We wrap the last per-try context in a body and overwrite the Response's Body field with our wrapper.
|
|
||||||
// So, when the user closes the Body, the our per-try context gets closed too.
|
|
||||||
// Another option, is that the Last Policy do this wrapping for a per-retry context (not for the user's context)
|
|
||||||
if response == nil || response.Response() == nil {
|
|
||||||
// We do panic in the case response or response.Response() is nil,
|
|
||||||
// as for client, the response should not be nil if request is sent and the operations is executed successfully.
|
|
||||||
// Another option, is that execute the cancel function when response or response.Response() is nil,
|
|
||||||
// as in this case, current per-try has nothing to do in future.
|
|
||||||
return nil, errors.New("invalid state, response should not be nil when the operation is executed successfully")
|
|
||||||
}
|
|
||||||
response.Response().Body = &contextCancelReadCloser{cf: tryCancel, body: response.Response().Body}
|
|
||||||
}
|
|
||||||
break // Don't retry
|
|
||||||
}
|
|
||||||
if response != nil && response.Response() != nil && response.Response().Body != nil {
|
|
||||||
// If we're going to retry and we got a previous response, then flush its body to avoid leaking its TCP connection
|
|
||||||
body := response.Response().Body
|
|
||||||
io.Copy(ioutil.Discard, body)
|
|
||||||
body.Close()
|
|
||||||
}
|
|
||||||
// If retrying, cancel the current per-try timeout context
|
|
||||||
tryCancel()
|
|
||||||
}
|
|
||||||
return response, err // Not retryable or too many retries; return the last response/error
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// contextCancelReadCloser helps to invoke context's cancelFunc properly when the ReadCloser is closed.
|
|
||||||
type contextCancelReadCloser struct {
|
|
||||||
cf context.CancelFunc
|
|
||||||
body io.ReadCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *contextCancelReadCloser) Read(p []byte) (n int, err error) {
|
|
||||||
return rc.body.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *contextCancelReadCloser) Close() error {
|
|
||||||
err := rc.body.Close()
|
|
||||||
if rc.cf != nil {
|
|
||||||
rc.cf()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// isNotRetriable checks if the provided net.Error isn't retriable.
|
|
||||||
func isNotRetriable(errToParse net.Error) bool {
|
|
||||||
// No error, so this is NOT retriable.
|
|
||||||
if errToParse == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// The error is either temporary or a timeout so it IS retriable (not not retriable).
|
|
||||||
if errToParse.Temporary() || errToParse.Timeout() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
genericErr := error(errToParse)
|
|
||||||
|
|
||||||
// From here all the error are neither Temporary() nor Timeout().
|
|
||||||
switch err := errToParse.(type) {
|
|
||||||
case *net.OpError:
|
|
||||||
// The net.Error is also a net.OpError but the inner error is nil, so this is not retriable.
|
|
||||||
if err.Err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
genericErr = err.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch genericErr.(type) {
|
|
||||||
case *net.AddrError, net.UnknownNetworkError, *net.DNSError, net.InvalidAddrError, *net.ParseError, *net.DNSConfigError:
|
|
||||||
// If the error is one of the ones listed, then it is NOT retriable.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's invalid header field name/value error thrown by http module, then it is NOT retriable.
|
|
||||||
// This could happen when metadata's key or value is invalid. (RoundTrip in transport.go)
|
|
||||||
if strings.Contains(genericErr.Error(), "invalid header field") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume the error is retriable.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var successStatusCodes = []int{http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent, http.StatusPartialContent}
|
|
||||||
|
|
||||||
func isSuccessStatusCode(resp *http.Response) bool {
|
|
||||||
if resp == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, i := range successStatusCodes {
|
|
||||||
if i == resp.StatusCode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// According to https://github.com/golang/go/wiki/CompilerOptimizations, the compiler will inline this method and hopefully optimize all calls to it away
|
|
||||||
var logf = func(format string, a ...interface{}) {}
|
|
||||||
|
|
||||||
// Use this version to see the retry method's code path (import "fmt")
|
|
||||||
//var logf = fmt.Printf
|
|
||||||
|
|
||||||
/*
|
|
||||||
type deadlineExceededReadCloser struct {
|
|
||||||
r io.ReadCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *deadlineExceededReadCloser) Read(p []byte) (int, error) {
|
|
||||||
n, err := 0, io.EOF
|
|
||||||
if r.r != nil {
|
|
||||||
n, err = r.r.Read(p)
|
|
||||||
}
|
|
||||||
return n, improveDeadlineExceeded(err)
|
|
||||||
}
|
|
||||||
func (r *deadlineExceededReadCloser) Seek(offset int64, whence int) (int64, error) {
|
|
||||||
// For an HTTP request, the ReadCloser MUST also implement seek
|
|
||||||
// For an HTTP response, Seek MUST not be called (or this will panic)
|
|
||||||
o, err := r.r.(io.Seeker).Seek(offset, whence)
|
|
||||||
return o, improveDeadlineExceeded(err)
|
|
||||||
}
|
|
||||||
func (r *deadlineExceededReadCloser) Close() error {
|
|
||||||
if c, ok := r.r.(io.Closer); ok {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// timeoutError is the internal struct that implements our richer timeout error.
|
|
||||||
type deadlineExceeded struct {
|
|
||||||
responseError
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = (*deadlineExceeded)(nil) // Ensure deadlineExceeded implements the net.Error interface at compile time
|
|
||||||
|
|
||||||
// improveDeadlineExceeded creates a timeoutError object that implements the error interface IF cause is a context.DeadlineExceeded error.
|
|
||||||
func improveDeadlineExceeded(cause error) error {
|
|
||||||
// If cause is not DeadlineExceeded, return the same error passed in.
|
|
||||||
if cause != context.DeadlineExceeded {
|
|
||||||
return cause
|
|
||||||
}
|
|
||||||
// Else, convert DeadlineExceeded to our timeoutError which gives a richer string message
|
|
||||||
return &deadlineExceeded{
|
|
||||||
responseError: responseError{
|
|
||||||
ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface's Error method to return a string representation of the error.
|
|
||||||
func (e *deadlineExceeded) Error() string {
|
|
||||||
return e.ErrorNode.Error("context deadline exceeded; when creating a pipeline, consider increasing RetryOptions' TryTimeout field")
|
|
||||||
}
|
|
||||||
*/
|
|
51
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_telemetry.go
generated
vendored
51
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_telemetry.go
generated
vendored
@ -1,51 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TelemetryOptions configures the telemetry policy's behavior.
|
|
||||||
type TelemetryOptions struct {
|
|
||||||
// Value is a string prepended to each request's User-Agent and sent to the service.
|
|
||||||
// The service records the user-agent in logs for diagnostics and tracking of client requests.
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTelemetryPolicyFactory creates a factory that can create telemetry policy objects
|
|
||||||
// which add telemetry information to outgoing HTTP requests.
|
|
||||||
func NewTelemetryPolicyFactory(o TelemetryOptions) pipeline.Factory {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
b.WriteString(o.Value)
|
|
||||||
if b.Len() > 0 {
|
|
||||||
b.WriteRune(' ')
|
|
||||||
}
|
|
||||||
fmt.Fprintf(b, "Azure-Storage/%s %s", serviceLibVersion, platformInfo)
|
|
||||||
telemetryValue := b.String()
|
|
||||||
|
|
||||||
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
|
|
||||||
return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
request.Header.Set("User-Agent", telemetryValue)
|
|
||||||
return next.Do(ctx, request)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: the ONLY function that should write to this variable is this func
|
|
||||||
var platformInfo = func() string {
|
|
||||||
// Azure-Storage/version (runtime; os type and version)”
|
|
||||||
// Azure-Storage/1.4.0 (NODE-VERSION v4.5.0; Windows_NT 10.0.14393)'
|
|
||||||
operatingSystem := runtime.GOOS // Default OS string
|
|
||||||
switch operatingSystem {
|
|
||||||
case "windows":
|
|
||||||
operatingSystem = os.Getenv("OS") // Get more specific OS information
|
|
||||||
case "linux": // accept default OS info
|
|
||||||
case "freebsd": // accept default OS info
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("(%s; %s)", runtime.Version(), operatingSystem)
|
|
||||||
}()
|
|
24
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_unique_request_id.go
generated
vendored
24
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_policy_unique_request_id.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewUniqueRequestIDPolicyFactory creates a UniqueRequestIDPolicyFactory object
|
|
||||||
// that sets the request's x-ms-client-request-id header if it doesn't already exist.
|
|
||||||
func NewUniqueRequestIDPolicyFactory() pipeline.Factory {
|
|
||||||
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
|
|
||||||
// This is Policy's Do method:
|
|
||||||
return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
id := request.Header.Get(xMsClientRequestID)
|
|
||||||
if id == "" { // Add a unique request ID if the caller didn't specify one already
|
|
||||||
request.Header.Set(xMsClientRequestID, newUUID().String())
|
|
||||||
}
|
|
||||||
return next.Do(ctx, request)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const xMsClientRequestID = "x-ms-client-request-id"
|
|
184
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_retry_reader.go
generated
vendored
184
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_retry_reader.go
generated
vendored
@ -1,184 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const CountToEnd = 0
|
|
||||||
|
|
||||||
// HTTPGetter is a function type that refers to a method that performs an HTTP GET operation.
|
|
||||||
type HTTPGetter func(ctx context.Context, i HTTPGetterInfo) (*http.Response, error)
|
|
||||||
|
|
||||||
// HTTPGetterInfo is passed to an HTTPGetter function passing it parameters
|
|
||||||
// that should be used to make an HTTP GET request.
|
|
||||||
type HTTPGetterInfo struct {
|
|
||||||
// Offset specifies the start offset that should be used when
|
|
||||||
// creating the HTTP GET request's Range header
|
|
||||||
Offset int64
|
|
||||||
|
|
||||||
// Count specifies the count of bytes that should be used to calculate
|
|
||||||
// the end offset when creating the HTTP GET request's Range header
|
|
||||||
Count int64
|
|
||||||
|
|
||||||
// ETag specifies the resource's etag that should be used when creating
|
|
||||||
// the HTTP GET request's If-Match header
|
|
||||||
ETag ETag
|
|
||||||
}
|
|
||||||
|
|
||||||
// FailedReadNotifier is a function type that represents the notification function called when a read fails
|
|
||||||
type FailedReadNotifier func(failureCount int, lastError error, offset int64, count int64, willRetry bool)
|
|
||||||
|
|
||||||
// RetryReaderOptions contains properties which can help to decide when to do retry.
|
|
||||||
type RetryReaderOptions struct {
|
|
||||||
// MaxRetryRequests specifies the maximum number of HTTP GET requests that will be made
|
|
||||||
// while reading from a RetryReader. A value of zero means that no additional HTTP
|
|
||||||
// GET requests will be made.
|
|
||||||
MaxRetryRequests int
|
|
||||||
doInjectError bool
|
|
||||||
doInjectErrorRound int
|
|
||||||
injectedError error
|
|
||||||
|
|
||||||
// NotifyFailedRead is called, if non-nil, after any failure to read. Expected usage is diagnostic logging.
|
|
||||||
NotifyFailedRead FailedReadNotifier
|
|
||||||
|
|
||||||
// TreatEarlyCloseAsError can be set to true to prevent retries after "read on closed response body". By default,
|
|
||||||
// retryReader has the following special behaviour: closing the response body before it is all read is treated as a
|
|
||||||
// retryable error. This is to allow callers to force a retry by closing the body from another goroutine (e.g. if the =
|
|
||||||
// read is too slow, caller may want to force a retry in the hope that the retry will be quicker). If
|
|
||||||
// TreatEarlyCloseAsError is true, then retryReader's special behaviour is suppressed, and "read on closed body" is instead
|
|
||||||
// treated as a fatal (non-retryable) error.
|
|
||||||
// Note that setting TreatEarlyCloseAsError only guarantees that Closing will produce a fatal error if the Close happens
|
|
||||||
// from the same "thread" (goroutine) as Read. Concurrent Close calls from other goroutines may instead produce network errors
|
|
||||||
// which will be retried.
|
|
||||||
TreatEarlyCloseAsError bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// retryReader implements io.ReaderCloser methods.
|
|
||||||
// retryReader tries to read from response, and if there is retriable network error
|
|
||||||
// returned during reading, it will retry according to retry reader option through executing
|
|
||||||
// user defined action with provided data to get a new response, and continue the overall reading process
|
|
||||||
// through reading from the new response.
|
|
||||||
type retryReader struct {
|
|
||||||
ctx context.Context
|
|
||||||
info HTTPGetterInfo
|
|
||||||
countWasBounded bool
|
|
||||||
o RetryReaderOptions
|
|
||||||
getter HTTPGetter
|
|
||||||
|
|
||||||
// we support Close-ing during Reads (from other goroutines), so we protect the shared state, which is response
|
|
||||||
responseMu *sync.Mutex
|
|
||||||
response *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRetryReader creates a retry reader.
|
|
||||||
func NewRetryReader(ctx context.Context, initialResponse *http.Response,
|
|
||||||
info HTTPGetterInfo, o RetryReaderOptions, getter HTTPGetter) io.ReadCloser {
|
|
||||||
return &retryReader{
|
|
||||||
ctx: ctx,
|
|
||||||
getter: getter,
|
|
||||||
info: info,
|
|
||||||
countWasBounded: info.Count != CountToEnd,
|
|
||||||
response: initialResponse,
|
|
||||||
responseMu: &sync.Mutex{},
|
|
||||||
o: o}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *retryReader) setResponse(r *http.Response) {
|
|
||||||
s.responseMu.Lock()
|
|
||||||
defer s.responseMu.Unlock()
|
|
||||||
s.response = r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *retryReader) Read(p []byte) (n int, err error) {
|
|
||||||
for try := 0; ; try++ {
|
|
||||||
//fmt.Println(try) // Comment out for debugging.
|
|
||||||
if s.countWasBounded && s.info.Count == CountToEnd {
|
|
||||||
// User specified an original count and the remaining bytes are 0, return 0, EOF
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
s.responseMu.Lock()
|
|
||||||
resp := s.response
|
|
||||||
s.responseMu.Unlock()
|
|
||||||
if resp == nil { // We don't have a response stream to read from, try to get one.
|
|
||||||
newResponse, err := s.getter(s.ctx, s.info)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Successful GET; this is the network stream we'll read from.
|
|
||||||
s.setResponse(newResponse)
|
|
||||||
resp = newResponse
|
|
||||||
}
|
|
||||||
n, err := resp.Body.Read(p) // Read from the stream (this will return non-nil err if forceRetry is called, from another goroutine, while it is running)
|
|
||||||
|
|
||||||
// Injection mechanism for testing.
|
|
||||||
if s.o.doInjectError && try == s.o.doInjectErrorRound {
|
|
||||||
if s.o.injectedError != nil {
|
|
||||||
err = s.o.injectedError
|
|
||||||
} else {
|
|
||||||
err = &net.DNSError{IsTemporary: true}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We successfully read data or end EOF.
|
|
||||||
if err == nil || err == io.EOF {
|
|
||||||
s.info.Offset += int64(n) // Increments the start offset in case we need to make a new HTTP request in the future
|
|
||||||
if s.info.Count != CountToEnd {
|
|
||||||
s.info.Count -= int64(n) // Decrement the count in case we need to make a new HTTP request in the future
|
|
||||||
}
|
|
||||||
return n, err // Return the return to the caller
|
|
||||||
}
|
|
||||||
s.Close() // Error, close stream
|
|
||||||
s.setResponse(nil) // Our stream is no longer good
|
|
||||||
|
|
||||||
// Check the retry count and error code, and decide whether to retry.
|
|
||||||
retriesExhausted := try >= s.o.MaxRetryRequests
|
|
||||||
_, isNetError := err.(net.Error)
|
|
||||||
isUnexpectedEOF := err == io.ErrUnexpectedEOF
|
|
||||||
willRetry := (isNetError || isUnexpectedEOF || s.wasRetryableEarlyClose(err)) && !retriesExhausted
|
|
||||||
|
|
||||||
// Notify, for logging purposes, of any failures
|
|
||||||
if s.o.NotifyFailedRead != nil {
|
|
||||||
failureCount := try + 1 // because try is zero-based
|
|
||||||
s.o.NotifyFailedRead(failureCount, err, s.info.Offset, s.info.Count, willRetry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if willRetry {
|
|
||||||
continue
|
|
||||||
// Loop around and try to get and read from new stream.
|
|
||||||
}
|
|
||||||
return n, err // Not retryable, or retries exhausted, so just return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default, we allow early Closing, from another concurrent goroutine, to be used to force a retry
|
|
||||||
// Is this safe, to close early from another goroutine? Early close ultimately ends up calling
|
|
||||||
// net.Conn.Close, and that is documented as "Any blocked Read or Write operations will be unblocked and return errors"
|
|
||||||
// which is exactly the behaviour we want.
|
|
||||||
// NOTE: that if caller has forced an early Close from a separate goroutine (separate from the Read)
|
|
||||||
// then there are two different types of error that may happen - either the one one we check for here,
|
|
||||||
// or a net.Error (due to closure of connection). Which one happens depends on timing. We only need this routine
|
|
||||||
// to check for one, since the other is a net.Error, which our main Read retry loop is already handing.
|
|
||||||
func (s *retryReader) wasRetryableEarlyClose(err error) bool {
|
|
||||||
if s.o.TreatEarlyCloseAsError {
|
|
||||||
return false // user wants all early closes to be errors, and so not retryable
|
|
||||||
}
|
|
||||||
// unfortunately, http.errReadOnClosedResBody is private, so the best we can do here is to check for its text
|
|
||||||
return strings.HasSuffix(err.Error(), ReadOnClosedBodyMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReadOnClosedBodyMessage = "read on closed response body"
|
|
||||||
|
|
||||||
func (s *retryReader) Close() error {
|
|
||||||
s.responseMu.Lock()
|
|
||||||
defer s.responseMu.Unlock()
|
|
||||||
if s.response != nil && s.response.Body != nil {
|
|
||||||
return s.response.Body.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
219
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_sas_account.go
generated
vendored
219
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_sas_account.go
generated
vendored
@ -1,219 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AccountSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account.
|
|
||||||
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-an-account-sas
|
|
||||||
type AccountSASSignatureValues struct {
|
|
||||||
Version string `param:"sv"` // If not specified, this defaults to SASVersion
|
|
||||||
Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants
|
|
||||||
StartTime time.Time `param:"st"` // Not specified if IsZero
|
|
||||||
ExpiryTime time.Time `param:"se"` // Not specified if IsZero
|
|
||||||
Permissions string `param:"sp"` // Create by initializing a AccountSASPermissions and then call String()
|
|
||||||
IPRange IPRange `param:"sip"`
|
|
||||||
Services string `param:"ss"` // Create by initializing AccountSASServices and then call String()
|
|
||||||
ResourceTypes string `param:"srt"` // Create by initializing AccountSASResourceTypes and then call String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce
|
|
||||||
// the proper SAS query parameters.
|
|
||||||
func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) (SASQueryParameters, error) {
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS
|
|
||||||
if v.ExpiryTime.IsZero() || v.Permissions == "" || v.ResourceTypes == "" || v.Services == "" {
|
|
||||||
return SASQueryParameters{}, errors.New("account SAS is missing at least one of these: ExpiryTime, Permissions, Service, or ResourceType")
|
|
||||||
}
|
|
||||||
if v.Version == "" {
|
|
||||||
v.Version = SASVersion
|
|
||||||
}
|
|
||||||
perms := &AccountSASPermissions{}
|
|
||||||
if err := perms.Parse(v.Permissions); err != nil {
|
|
||||||
return SASQueryParameters{}, err
|
|
||||||
}
|
|
||||||
v.Permissions = perms.String()
|
|
||||||
|
|
||||||
startTime, expiryTime, _ := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime, time.Time{})
|
|
||||||
|
|
||||||
stringToSign := strings.Join([]string{
|
|
||||||
sharedKeyCredential.AccountName(),
|
|
||||||
v.Permissions,
|
|
||||||
v.Services,
|
|
||||||
v.ResourceTypes,
|
|
||||||
startTime,
|
|
||||||
expiryTime,
|
|
||||||
v.IPRange.String(),
|
|
||||||
string(v.Protocol),
|
|
||||||
v.Version,
|
|
||||||
""}, // That right, the account SAS requires a terminating extra newline
|
|
||||||
"\n")
|
|
||||||
|
|
||||||
signature := sharedKeyCredential.ComputeHMACSHA256(stringToSign)
|
|
||||||
p := SASQueryParameters{
|
|
||||||
// Common SAS parameters
|
|
||||||
version: v.Version,
|
|
||||||
protocol: v.Protocol,
|
|
||||||
startTime: v.StartTime,
|
|
||||||
expiryTime: v.ExpiryTime,
|
|
||||||
permissions: v.Permissions,
|
|
||||||
ipRange: v.IPRange,
|
|
||||||
|
|
||||||
// Account-specific SAS parameters
|
|
||||||
services: v.Services,
|
|
||||||
resourceTypes: v.ResourceTypes,
|
|
||||||
|
|
||||||
// Calculated SAS signature
|
|
||||||
signature: signature,
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS.
|
|
||||||
// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Permissions field.
|
|
||||||
type AccountSASPermissions struct {
|
|
||||||
Read, Write, Delete, List, Add, Create, Update, Process bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String produces the SAS permissions string for an Azure Storage account.
|
|
||||||
// Call this method to set AccountSASSignatureValues's Permissions field.
|
|
||||||
func (p AccountSASPermissions) String() string {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
if p.Read {
|
|
||||||
buffer.WriteRune('r')
|
|
||||||
}
|
|
||||||
if p.Write {
|
|
||||||
buffer.WriteRune('w')
|
|
||||||
}
|
|
||||||
if p.Delete {
|
|
||||||
buffer.WriteRune('d')
|
|
||||||
}
|
|
||||||
if p.List {
|
|
||||||
buffer.WriteRune('l')
|
|
||||||
}
|
|
||||||
if p.Add {
|
|
||||||
buffer.WriteRune('a')
|
|
||||||
}
|
|
||||||
if p.Create {
|
|
||||||
buffer.WriteRune('c')
|
|
||||||
}
|
|
||||||
if p.Update {
|
|
||||||
buffer.WriteRune('u')
|
|
||||||
}
|
|
||||||
if p.Process {
|
|
||||||
buffer.WriteRune('p')
|
|
||||||
}
|
|
||||||
return buffer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the AccountSASPermissions's fields from a string.
|
|
||||||
func (p *AccountSASPermissions) Parse(s string) error {
|
|
||||||
*p = AccountSASPermissions{} // Clear out the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 'r':
|
|
||||||
p.Read = true
|
|
||||||
case 'w':
|
|
||||||
p.Write = true
|
|
||||||
case 'd':
|
|
||||||
p.Delete = true
|
|
||||||
case 'l':
|
|
||||||
p.List = true
|
|
||||||
case 'a':
|
|
||||||
p.Add = true
|
|
||||||
case 'c':
|
|
||||||
p.Create = true
|
|
||||||
case 'u':
|
|
||||||
p.Update = true
|
|
||||||
case 'p':
|
|
||||||
p.Process = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid permission character: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The AccountSASServices type simplifies creating the services string for an Azure Storage Account SAS.
|
|
||||||
// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Services field.
|
|
||||||
type AccountSASServices struct {
|
|
||||||
Blob, Queue, File bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String produces the SAS services string for an Azure Storage account.
|
|
||||||
// Call this method to set AccountSASSignatureValues's Services field.
|
|
||||||
func (s AccountSASServices) String() string {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
if s.Blob {
|
|
||||||
buffer.WriteRune('b')
|
|
||||||
}
|
|
||||||
if s.Queue {
|
|
||||||
buffer.WriteRune('q')
|
|
||||||
}
|
|
||||||
if s.File {
|
|
||||||
buffer.WriteRune('f')
|
|
||||||
}
|
|
||||||
return buffer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the AccountSASServices' fields from a string.
|
|
||||||
func (a *AccountSASServices) Parse(s string) error {
|
|
||||||
*a = AccountSASServices{} // Clear out the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 'b':
|
|
||||||
a.Blob = true
|
|
||||||
case 'q':
|
|
||||||
a.Queue = true
|
|
||||||
case 'f':
|
|
||||||
a.File = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid service character: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The AccountSASResourceTypes type simplifies creating the resource types string for an Azure Storage Account SAS.
|
|
||||||
// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's ResourceTypes field.
|
|
||||||
type AccountSASResourceTypes struct {
|
|
||||||
Service, Container, Object bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String produces the SAS resource types string for an Azure Storage account.
|
|
||||||
// Call this method to set AccountSASSignatureValues's ResourceTypes field.
|
|
||||||
func (rt AccountSASResourceTypes) String() string {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
if rt.Service {
|
|
||||||
buffer.WriteRune('s')
|
|
||||||
}
|
|
||||||
if rt.Container {
|
|
||||||
buffer.WriteRune('c')
|
|
||||||
}
|
|
||||||
if rt.Object {
|
|
||||||
buffer.WriteRune('o')
|
|
||||||
}
|
|
||||||
return buffer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse initializes the AccountSASResourceType's fields from a string.
|
|
||||||
func (rt *AccountSASResourceTypes) Parse(s string) error {
|
|
||||||
*rt = AccountSASResourceTypes{} // Clear out the flags
|
|
||||||
for _, r := range s {
|
|
||||||
switch r {
|
|
||||||
case 's':
|
|
||||||
rt.Service = true
|
|
||||||
case 'c':
|
|
||||||
rt.Container = true
|
|
||||||
case 'o':
|
|
||||||
rt.Object = true
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid resource type: '%v'", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
358
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_sas_query_params.go
generated
vendored
358
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_sas_query_params.go
generated
vendored
@ -1,358 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SASVersion indicates the SAS version.
|
|
||||||
const SASVersion = ServiceVersion
|
|
||||||
|
|
||||||
type SASProtocol string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SASProtocolHTTPS can be specified for a SAS protocol
|
|
||||||
SASProtocolHTTPS SASProtocol = "https"
|
|
||||||
|
|
||||||
// SASProtocolHTTPSandHTTP can be specified for a SAS protocol
|
|
||||||
SASProtocolHTTPSandHTTP SASProtocol = "https,http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormatTimesForSASSigning converts a time.Time to a snapshotTimeFormat string suitable for a
|
|
||||||
// SASField's StartTime or ExpiryTime fields. Returns "" if value.IsZero().
|
|
||||||
func FormatTimesForSASSigning(startTime, expiryTime, snapshotTime time.Time) (string, string, string) {
|
|
||||||
ss := ""
|
|
||||||
if !startTime.IsZero() {
|
|
||||||
ss = formatSASTimeWithDefaultFormat(&startTime)
|
|
||||||
}
|
|
||||||
se := ""
|
|
||||||
if !expiryTime.IsZero() {
|
|
||||||
se = formatSASTimeWithDefaultFormat(&expiryTime)
|
|
||||||
}
|
|
||||||
sh := ""
|
|
||||||
if !snapshotTime.IsZero() {
|
|
||||||
sh = snapshotTime.Format(SnapshotTimeFormat)
|
|
||||||
}
|
|
||||||
return ss, se, sh
|
|
||||||
}
|
|
||||||
|
|
||||||
// SASTimeFormat represents the format of a SAS start or expiry time. Use it when formatting/parsing a time.Time.
|
|
||||||
const SASTimeFormat = "2006-01-02T15:04:05Z" //"2017-07-27T00:00:00Z" // ISO 8601
|
|
||||||
var SASTimeFormats = []string{"2006-01-02T15:04:05.0000000Z", SASTimeFormat, "2006-01-02T15:04Z", "2006-01-02"} // ISO 8601 formats, please refer to https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas for more details.
|
|
||||||
|
|
||||||
// formatSASTimeWithDefaultFormat format time with ISO 8601 in "yyyy-MM-ddTHH:mm:ssZ".
|
|
||||||
func formatSASTimeWithDefaultFormat(t *time.Time) string {
|
|
||||||
return formatSASTime(t, SASTimeFormat) // By default, "yyyy-MM-ddTHH:mm:ssZ" is used
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatSASTime format time with given format, use ISO 8601 in "yyyy-MM-ddTHH:mm:ssZ" by default.
|
|
||||||
func formatSASTime(t *time.Time, format string) string {
|
|
||||||
if format != "" {
|
|
||||||
return t.Format(format)
|
|
||||||
}
|
|
||||||
return t.Format(SASTimeFormat) // By default, "yyyy-MM-ddTHH:mm:ssZ" is used
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseSASTimeString try to parse sas time string.
|
|
||||||
func parseSASTimeString(val string) (t time.Time, timeFormat string, err error) {
|
|
||||||
for _, sasTimeFormat := range SASTimeFormats {
|
|
||||||
t, err = time.Parse(sasTimeFormat, val)
|
|
||||||
if err == nil {
|
|
||||||
timeFormat = sasTimeFormat
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
err = errors.New("fail to parse time with IOS 8601 formats, please refer to https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas for more details")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
|
|
||||||
|
|
||||||
// A SASQueryParameters object represents the components that make up an Azure Storage SAS' query parameters.
|
|
||||||
// You parse a map of query parameters into its fields by calling NewSASQueryParameters(). You add the components
|
|
||||||
// to a query parameter map by calling AddToValues().
|
|
||||||
// NOTE: Changing any field requires computing a new SAS signature using a XxxSASSignatureValues type.
|
|
||||||
//
|
|
||||||
// This type defines the components used by all Azure Storage resources (Containers, Blobs, Files, & Queues).
|
|
||||||
type SASQueryParameters struct {
|
|
||||||
// All members are immutable or values so copies of this struct are goroutine-safe.
|
|
||||||
version string `param:"sv"`
|
|
||||||
services string `param:"ss"`
|
|
||||||
resourceTypes string `param:"srt"`
|
|
||||||
protocol SASProtocol `param:"spr"`
|
|
||||||
startTime time.Time `param:"st"`
|
|
||||||
expiryTime time.Time `param:"se"`
|
|
||||||
snapshotTime time.Time `param:"snapshot"`
|
|
||||||
ipRange IPRange `param:"sip"`
|
|
||||||
identifier string `param:"si"`
|
|
||||||
resource string `param:"sr"`
|
|
||||||
permissions string `param:"sp"`
|
|
||||||
signature string `param:"sig"`
|
|
||||||
cacheControl string `param:"rscc"`
|
|
||||||
contentDisposition string `param:"rscd"`
|
|
||||||
contentEncoding string `param:"rsce"`
|
|
||||||
contentLanguage string `param:"rscl"`
|
|
||||||
contentType string `param:"rsct"`
|
|
||||||
signedOid string `param:"skoid"`
|
|
||||||
signedTid string `param:"sktid"`
|
|
||||||
signedStart time.Time `param:"skt"`
|
|
||||||
signedExpiry time.Time `param:"ske"`
|
|
||||||
signedService string `param:"sks"`
|
|
||||||
signedVersion string `param:"skv"`
|
|
||||||
|
|
||||||
// private member used for startTime and expiryTime formatting.
|
|
||||||
stTimeFormat string
|
|
||||||
seTimeFormat string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedOid() string {
|
|
||||||
return p.signedOid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedTid() string {
|
|
||||||
return p.signedTid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedStart() time.Time {
|
|
||||||
return p.signedStart
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedExpiry() time.Time {
|
|
||||||
return p.signedExpiry
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedService() string {
|
|
||||||
return p.signedService
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SignedVersion() string {
|
|
||||||
return p.signedVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) SnapshotTime() time.Time {
|
|
||||||
return p.snapshotTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) Version() string {
|
|
||||||
return p.version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) Services() string {
|
|
||||||
return p.services
|
|
||||||
}
|
|
||||||
func (p *SASQueryParameters) ResourceTypes() string {
|
|
||||||
return p.resourceTypes
|
|
||||||
}
|
|
||||||
func (p *SASQueryParameters) Protocol() SASProtocol {
|
|
||||||
return p.protocol
|
|
||||||
}
|
|
||||||
func (p *SASQueryParameters) StartTime() time.Time {
|
|
||||||
return p.startTime
|
|
||||||
}
|
|
||||||
func (p *SASQueryParameters) ExpiryTime() time.Time {
|
|
||||||
return p.expiryTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) IPRange() IPRange {
|
|
||||||
return p.ipRange
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) Identifier() string {
|
|
||||||
return p.identifier
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) Resource() string {
|
|
||||||
return p.resource
|
|
||||||
}
|
|
||||||
func (p *SASQueryParameters) Permissions() string {
|
|
||||||
return p.permissions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) Signature() string {
|
|
||||||
return p.signature
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) CacheControl() string {
|
|
||||||
return p.cacheControl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) ContentDisposition() string {
|
|
||||||
return p.contentDisposition
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) ContentEncoding() string {
|
|
||||||
return p.contentEncoding
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) ContentLanguage() string {
|
|
||||||
return p.contentLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SASQueryParameters) ContentType() string {
|
|
||||||
return p.contentType
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPRange represents a SAS IP range's start IP and (optionally) end IP.
|
|
||||||
type IPRange struct {
|
|
||||||
Start net.IP // Not specified if length = 0
|
|
||||||
End net.IP // Not specified if length = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of an IPRange.
|
|
||||||
func (ipr *IPRange) String() string {
|
|
||||||
if len(ipr.Start) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
start := ipr.Start.String()
|
|
||||||
if len(ipr.End) == 0 {
|
|
||||||
return start
|
|
||||||
}
|
|
||||||
return start + "-" + ipr.End.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSASQueryParameters creates and initializes a SASQueryParameters object based on the
|
|
||||||
// query parameter map's passed-in values. If deleteSASParametersFromValues is true,
|
|
||||||
// all SAS-related query parameters are removed from the passed-in map. If
|
|
||||||
// deleteSASParametersFromValues is false, the map passed-in map is unaltered.
|
|
||||||
func newSASQueryParameters(values url.Values, deleteSASParametersFromValues bool) SASQueryParameters {
|
|
||||||
p := SASQueryParameters{}
|
|
||||||
for k, v := range values {
|
|
||||||
val := v[0]
|
|
||||||
isSASKey := true
|
|
||||||
switch strings.ToLower(k) {
|
|
||||||
case "sv":
|
|
||||||
p.version = val
|
|
||||||
case "ss":
|
|
||||||
p.services = val
|
|
||||||
case "srt":
|
|
||||||
p.resourceTypes = val
|
|
||||||
case "spr":
|
|
||||||
p.protocol = SASProtocol(val)
|
|
||||||
case "snapshot":
|
|
||||||
p.snapshotTime, _ = time.Parse(SnapshotTimeFormat, val)
|
|
||||||
case "st":
|
|
||||||
p.startTime, p.stTimeFormat, _ = parseSASTimeString(val)
|
|
||||||
case "se":
|
|
||||||
p.expiryTime, p.seTimeFormat, _ = parseSASTimeString(val)
|
|
||||||
case "sip":
|
|
||||||
dashIndex := strings.Index(val, "-")
|
|
||||||
if dashIndex == -1 {
|
|
||||||
p.ipRange.Start = net.ParseIP(val)
|
|
||||||
} else {
|
|
||||||
p.ipRange.Start = net.ParseIP(val[:dashIndex])
|
|
||||||
p.ipRange.End = net.ParseIP(val[dashIndex+1:])
|
|
||||||
}
|
|
||||||
case "si":
|
|
||||||
p.identifier = val
|
|
||||||
case "sr":
|
|
||||||
p.resource = val
|
|
||||||
case "sp":
|
|
||||||
p.permissions = val
|
|
||||||
case "sig":
|
|
||||||
p.signature = val
|
|
||||||
case "rscc":
|
|
||||||
p.cacheControl = val
|
|
||||||
case "rscd":
|
|
||||||
p.contentDisposition = val
|
|
||||||
case "rsce":
|
|
||||||
p.contentEncoding = val
|
|
||||||
case "rscl":
|
|
||||||
p.contentLanguage = val
|
|
||||||
case "rsct":
|
|
||||||
p.contentType = val
|
|
||||||
case "skoid":
|
|
||||||
p.signedOid = val
|
|
||||||
case "sktid":
|
|
||||||
p.signedTid = val
|
|
||||||
case "skt":
|
|
||||||
p.signedStart, _ = time.Parse(SASTimeFormat, val)
|
|
||||||
case "ske":
|
|
||||||
p.signedExpiry, _ = time.Parse(SASTimeFormat, val)
|
|
||||||
case "sks":
|
|
||||||
p.signedService = val
|
|
||||||
case "skv":
|
|
||||||
p.signedVersion = val
|
|
||||||
default:
|
|
||||||
isSASKey = false // We didn't recognize the query parameter
|
|
||||||
}
|
|
||||||
if isSASKey && deleteSASParametersFromValues {
|
|
||||||
delete(values, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddToValues adds the SAS components to the specified query parameters map.
|
|
||||||
func (p *SASQueryParameters) addToValues(v url.Values) url.Values {
|
|
||||||
if p.version != "" {
|
|
||||||
v.Add("sv", p.version)
|
|
||||||
}
|
|
||||||
if p.services != "" {
|
|
||||||
v.Add("ss", p.services)
|
|
||||||
}
|
|
||||||
if p.resourceTypes != "" {
|
|
||||||
v.Add("srt", p.resourceTypes)
|
|
||||||
}
|
|
||||||
if p.protocol != "" {
|
|
||||||
v.Add("spr", string(p.protocol))
|
|
||||||
}
|
|
||||||
if !p.startTime.IsZero() {
|
|
||||||
v.Add("st", formatSASTime(&(p.startTime), p.stTimeFormat))
|
|
||||||
}
|
|
||||||
if !p.expiryTime.IsZero() {
|
|
||||||
v.Add("se", formatSASTime(&(p.expiryTime), p.seTimeFormat))
|
|
||||||
}
|
|
||||||
if len(p.ipRange.Start) > 0 {
|
|
||||||
v.Add("sip", p.ipRange.String())
|
|
||||||
}
|
|
||||||
if p.identifier != "" {
|
|
||||||
v.Add("si", p.identifier)
|
|
||||||
}
|
|
||||||
if p.resource != "" {
|
|
||||||
v.Add("sr", p.resource)
|
|
||||||
}
|
|
||||||
if p.permissions != "" {
|
|
||||||
v.Add("sp", p.permissions)
|
|
||||||
}
|
|
||||||
if p.signedOid != "" {
|
|
||||||
v.Add("skoid", p.signedOid)
|
|
||||||
v.Add("sktid", p.signedTid)
|
|
||||||
v.Add("skt", p.signedStart.Format(SASTimeFormat))
|
|
||||||
v.Add("ske", p.signedExpiry.Format(SASTimeFormat))
|
|
||||||
v.Add("sks", p.signedService)
|
|
||||||
v.Add("skv", p.signedVersion)
|
|
||||||
}
|
|
||||||
if p.signature != "" {
|
|
||||||
v.Add("sig", p.signature)
|
|
||||||
}
|
|
||||||
if p.cacheControl != "" {
|
|
||||||
v.Add("rscc", p.cacheControl)
|
|
||||||
}
|
|
||||||
if p.contentDisposition != "" {
|
|
||||||
v.Add("rscd", p.contentDisposition)
|
|
||||||
}
|
|
||||||
if p.contentEncoding != "" {
|
|
||||||
v.Add("rsce", p.contentEncoding)
|
|
||||||
}
|
|
||||||
if p.contentLanguage != "" {
|
|
||||||
v.Add("rscl", p.contentLanguage)
|
|
||||||
}
|
|
||||||
if p.contentType != "" {
|
|
||||||
v.Add("rsct", p.contentType)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode encodes the SAS query parameters into URL encoded form sorted by key.
|
|
||||||
func (p *SASQueryParameters) Encode() string {
|
|
||||||
v := url.Values{}
|
|
||||||
p.addToValues(v)
|
|
||||||
return v.Encode()
|
|
||||||
}
|
|
131
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_service_codes_common.go
generated
vendored
131
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_service_codes_common.go
generated
vendored
@ -1,131 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/rest/api/storageservices/common-rest-api-error-codes
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ServiceCodeNone is the default value. It indicates that the error was related to the service or that the service didn't return a code.
|
|
||||||
ServiceCodeNone ServiceCodeType = ""
|
|
||||||
|
|
||||||
// ServiceCodeAccountAlreadyExists means the specified account already exists.
|
|
||||||
ServiceCodeAccountAlreadyExists ServiceCodeType = "AccountAlreadyExists"
|
|
||||||
|
|
||||||
// ServiceCodeAccountBeingCreated means the specified account is in the process of being created (403).
|
|
||||||
ServiceCodeAccountBeingCreated ServiceCodeType = "AccountBeingCreated"
|
|
||||||
|
|
||||||
// ServiceCodeAccountIsDisabled means the specified account is disabled (403).
|
|
||||||
ServiceCodeAccountIsDisabled ServiceCodeType = "AccountIsDisabled"
|
|
||||||
|
|
||||||
// ServiceCodeAuthenticationFailed means the server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature (403).
|
|
||||||
ServiceCodeAuthenticationFailed ServiceCodeType = "AuthenticationFailed"
|
|
||||||
|
|
||||||
// ServiceCodeConditionHeadersNotSupported means the condition headers are not supported (400).
|
|
||||||
ServiceCodeConditionHeadersNotSupported ServiceCodeType = "ConditionHeadersNotSupported"
|
|
||||||
|
|
||||||
// ServiceCodeConditionNotMet means the condition specified in the conditional header(s) was not met for a read/write operation (304/412).
|
|
||||||
ServiceCodeConditionNotMet ServiceCodeType = "ConditionNotMet"
|
|
||||||
|
|
||||||
// ServiceCodeEmptyMetadataKey means the key for one of the metadata key-value pairs is empty (400).
|
|
||||||
ServiceCodeEmptyMetadataKey ServiceCodeType = "EmptyMetadataKey"
|
|
||||||
|
|
||||||
// ServiceCodeInsufficientAccountPermissions means read operations are currently disabled or Write operations are not allowed or The account being accessed does not have sufficient permissions to execute this operation (403).
|
|
||||||
ServiceCodeInsufficientAccountPermissions ServiceCodeType = "InsufficientAccountPermissions"
|
|
||||||
|
|
||||||
// ServiceCodeInternalError means the server encountered an internal error. Please retry the request (500).
|
|
||||||
ServiceCodeInternalError ServiceCodeType = "InternalError"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidAuthenticationInfo means the authentication information was not provided in the correct format. Verify the value of Authorization header (400).
|
|
||||||
ServiceCodeInvalidAuthenticationInfo ServiceCodeType = "InvalidAuthenticationInfo"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidHeaderValue means the value provided for one of the HTTP headers was not in the correct format (400).
|
|
||||||
ServiceCodeInvalidHeaderValue ServiceCodeType = "InvalidHeaderValue"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidHTTPVerb means the HTTP verb specified was not recognized by the server (400).
|
|
||||||
ServiceCodeInvalidHTTPVerb ServiceCodeType = "InvalidHttpVerb"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidInput means one of the request inputs is not valid (400).
|
|
||||||
ServiceCodeInvalidInput ServiceCodeType = "InvalidInput"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidMd5 means the MD5 value specified in the request is invalid. The MD5 value must be 128 bits and Base64-encoded (400).
|
|
||||||
ServiceCodeInvalidMd5 ServiceCodeType = "InvalidMd5"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidMetadata means the specified metadata is invalid. It includes characters that are not permitted (400).
|
|
||||||
ServiceCodeInvalidMetadata ServiceCodeType = "InvalidMetadata"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidQueryParameterValue means an invalid value was specified for one of the query parameters in the request URI (400).
|
|
||||||
ServiceCodeInvalidQueryParameterValue ServiceCodeType = "InvalidQueryParameterValue"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidRange means the range specified is invalid for the current size of the resource (416).
|
|
||||||
ServiceCodeInvalidRange ServiceCodeType = "InvalidRange"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidResourceName means the specified resource name contains invalid characters (400).
|
|
||||||
ServiceCodeInvalidResourceName ServiceCodeType = "InvalidResourceName"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidURI means the requested URI does not represent any resource on the server (400).
|
|
||||||
ServiceCodeInvalidURI ServiceCodeType = "InvalidUri"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidXMLDocument means the specified XML is not syntactically valid (400).
|
|
||||||
ServiceCodeInvalidXMLDocument ServiceCodeType = "InvalidXmlDocument"
|
|
||||||
|
|
||||||
// ServiceCodeInvalidXMLNodeValue means the value provided for one of the XML nodes in the request body was not in the correct format (400).
|
|
||||||
ServiceCodeInvalidXMLNodeValue ServiceCodeType = "InvalidXmlNodeValue"
|
|
||||||
|
|
||||||
// ServiceCodeMd5Mismatch means the MD5 value specified in the request did not match the MD5 value calculated by the server (400).
|
|
||||||
ServiceCodeMd5Mismatch ServiceCodeType = "Md5Mismatch"
|
|
||||||
|
|
||||||
// ServiceCodeMetadataTooLarge means the size of the specified metadata exceeds the maximum size permitted (400).
|
|
||||||
ServiceCodeMetadataTooLarge ServiceCodeType = "MetadataTooLarge"
|
|
||||||
|
|
||||||
// ServiceCodeMissingContentLengthHeader means the Content-Length header was not specified (411).
|
|
||||||
ServiceCodeMissingContentLengthHeader ServiceCodeType = "MissingContentLengthHeader"
|
|
||||||
|
|
||||||
// ServiceCodeMissingRequiredQueryParameter means a required query parameter was not specified for this request (400).
|
|
||||||
ServiceCodeMissingRequiredQueryParameter ServiceCodeType = "MissingRequiredQueryParameter"
|
|
||||||
|
|
||||||
// ServiceCodeMissingRequiredHeader means a required HTTP header was not specified (400).
|
|
||||||
ServiceCodeMissingRequiredHeader ServiceCodeType = "MissingRequiredHeader"
|
|
||||||
|
|
||||||
// ServiceCodeMissingRequiredXMLNode means a required XML node was not specified in the request body (400).
|
|
||||||
ServiceCodeMissingRequiredXMLNode ServiceCodeType = "MissingRequiredXmlNode"
|
|
||||||
|
|
||||||
// ServiceCodeMultipleConditionHeadersNotSupported means multiple condition headers are not supported (400).
|
|
||||||
ServiceCodeMultipleConditionHeadersNotSupported ServiceCodeType = "MultipleConditionHeadersNotSupported"
|
|
||||||
|
|
||||||
// ServiceCodeOperationTimedOut means the operation could not be completed within the permitted time (500).
|
|
||||||
ServiceCodeOperationTimedOut ServiceCodeType = "OperationTimedOut"
|
|
||||||
|
|
||||||
// ServiceCodeOutOfRangeInput means one of the request inputs is out of range (400).
|
|
||||||
ServiceCodeOutOfRangeInput ServiceCodeType = "OutOfRangeInput"
|
|
||||||
|
|
||||||
// ServiceCodeOutOfRangeQueryParameterValue means a query parameter specified in the request URI is outside the permissible range (400).
|
|
||||||
ServiceCodeOutOfRangeQueryParameterValue ServiceCodeType = "OutOfRangeQueryParameterValue"
|
|
||||||
|
|
||||||
// ServiceCodeRequestBodyTooLarge means the size of the request body exceeds the maximum size permitted (413).
|
|
||||||
ServiceCodeRequestBodyTooLarge ServiceCodeType = "RequestBodyTooLarge"
|
|
||||||
|
|
||||||
// ServiceCodeResourceTypeMismatch means the specified resource type does not match the type of the existing resource (409).
|
|
||||||
ServiceCodeResourceTypeMismatch ServiceCodeType = "ResourceTypeMismatch"
|
|
||||||
|
|
||||||
// ServiceCodeRequestURLFailedToParse means the url in the request could not be parsed (400).
|
|
||||||
ServiceCodeRequestURLFailedToParse ServiceCodeType = "RequestUrlFailedToParse"
|
|
||||||
|
|
||||||
// ServiceCodeResourceAlreadyExists means the specified resource already exists (409).
|
|
||||||
ServiceCodeResourceAlreadyExists ServiceCodeType = "ResourceAlreadyExists"
|
|
||||||
|
|
||||||
// ServiceCodeResourceNotFound means the specified resource does not exist (404).
|
|
||||||
ServiceCodeResourceNotFound ServiceCodeType = "ResourceNotFound"
|
|
||||||
|
|
||||||
// ServiceCodeServerBusy means the server is currently unable to receive requests. Please retry your request or Ingress/egress is over the account limit or operations per second is over the account limit (503).
|
|
||||||
ServiceCodeServerBusy ServiceCodeType = "ServerBusy"
|
|
||||||
|
|
||||||
// ServiceCodeUnsupportedHeader means one of the HTTP headers specified in the request is not supported (400).
|
|
||||||
ServiceCodeUnsupportedHeader ServiceCodeType = "UnsupportedHeader"
|
|
||||||
|
|
||||||
// ServiceCodeUnsupportedXMLNode means one of the XML nodes specified in the request body is not supported (400).
|
|
||||||
ServiceCodeUnsupportedXMLNode ServiceCodeType = "UnsupportedXmlNode"
|
|
||||||
|
|
||||||
// ServiceCodeUnsupportedQueryParameter means one of the query parameters specified in the request URI is not supported (400).
|
|
||||||
ServiceCodeUnsupportedQueryParameter ServiceCodeType = "UnsupportedQueryParameter"
|
|
||||||
|
|
||||||
// ServiceCodeUnsupportedHTTPVerb means the resource doesn't support the specified HTTP verb (405).
|
|
||||||
ServiceCodeUnsupportedHTTPVerb ServiceCodeType = "UnsupportedHttpVerb"
|
|
||||||
)
|
|
111
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_storage_error.go
generated
vendored
111
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_storage_error.go
generated
vendored
@ -1,111 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// wire up our custom error handling constructor
|
|
||||||
responseErrorFactory = newStorageError
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceCodeType is a string identifying a storage service error.
|
|
||||||
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/status-and-error-codes2
|
|
||||||
type ServiceCodeType string
|
|
||||||
|
|
||||||
// StorageError identifies a responder-generated network or response parsing error.
|
|
||||||
type StorageError interface {
|
|
||||||
// ResponseError implements error's Error(), net.Error's Temporary() and Timeout() methods & Response().
|
|
||||||
ResponseError
|
|
||||||
|
|
||||||
// ServiceCode returns a service error code. Your code can use this to make error recovery decisions.
|
|
||||||
ServiceCode() ServiceCodeType
|
|
||||||
}
|
|
||||||
|
|
||||||
// storageError is the internal struct that implements the public StorageError interface.
|
|
||||||
type storageError struct {
|
|
||||||
responseError
|
|
||||||
serviceCode ServiceCodeType
|
|
||||||
details map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newStorageError creates an error object that implements the error interface.
|
|
||||||
func newStorageError(cause error, response *http.Response, description string) error {
|
|
||||||
return &storageError{
|
|
||||||
responseError: responseError{
|
|
||||||
ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3),
|
|
||||||
response: response,
|
|
||||||
description: description,
|
|
||||||
},
|
|
||||||
serviceCode: ServiceCodeType(response.Header.Get("x-ms-error-code")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceCode returns service-error information. The caller may examine these values but should not modify any of them.
|
|
||||||
func (e *storageError) ServiceCode() ServiceCodeType {
|
|
||||||
return e.serviceCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface's Error method to return a string representation of the error.
|
|
||||||
func (e *storageError) Error() string {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
fmt.Fprintf(b, "===== RESPONSE ERROR (ServiceCode=%s) =====\n", e.serviceCode)
|
|
||||||
fmt.Fprintf(b, "Description=%s, Details: ", e.description)
|
|
||||||
if len(e.details) == 0 {
|
|
||||||
b.WriteString("(none)\n")
|
|
||||||
} else {
|
|
||||||
b.WriteRune('\n')
|
|
||||||
keys := make([]string, 0, len(e.details))
|
|
||||||
// Alphabetize the details
|
|
||||||
for k := range e.details {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for _, k := range keys {
|
|
||||||
fmt.Fprintf(b, " %s: %+v\n", k, e.details[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req := pipeline.Request{Request: e.response.Request}.Copy() // Make a copy of the response's request
|
|
||||||
pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(req), e.response, nil)
|
|
||||||
return e.ErrorNode.Error(b.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary returns true if the error occurred due to a temporary condition (including an HTTP status of 500 or 503).
|
|
||||||
func (e *storageError) Temporary() bool {
|
|
||||||
if e.response != nil {
|
|
||||||
if (e.response.StatusCode == http.StatusInternalServerError) || (e.response.StatusCode == http.StatusServiceUnavailable) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e.ErrorNode.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalXML performs custom unmarshalling of XML-formatted Azure storage request errors.
|
|
||||||
func (e *storageError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
|
|
||||||
tokName := ""
|
|
||||||
var t xml.Token
|
|
||||||
for t, err = d.Token(); err == nil; t, err = d.Token() {
|
|
||||||
switch tt := t.(type) {
|
|
||||||
case xml.StartElement:
|
|
||||||
tokName = tt.Name.Local
|
|
||||||
break
|
|
||||||
case xml.CharData:
|
|
||||||
switch tokName {
|
|
||||||
case "Message":
|
|
||||||
e.description = string(tt)
|
|
||||||
default:
|
|
||||||
if e.details == nil {
|
|
||||||
e.details = map[string]string{}
|
|
||||||
}
|
|
||||||
e.details[tokName] = string(tt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
64
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_util_validate.go
generated
vendored
64
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_util_validate.go
generated
vendored
@ -1,64 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// httpRange defines a range of bytes within an HTTP resource, starting at offset and
|
|
||||||
// ending at offset+count. A zero-value httpRange indicates the entire resource. An httpRange
|
|
||||||
// which has an offset but na zero value count indicates from the offset to the resource's end.
|
|
||||||
type httpRange struct {
|
|
||||||
offset int64
|
|
||||||
count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r httpRange) pointers() *string {
|
|
||||||
if r.offset == 0 && r.count == CountToEnd { // Do common case first for performance
|
|
||||||
return nil // No specified range
|
|
||||||
}
|
|
||||||
endOffset := "" // if count == CountToEnd (0)
|
|
||||||
if r.count > 0 {
|
|
||||||
endOffset = strconv.FormatInt((r.offset+r.count)-1, 10)
|
|
||||||
}
|
|
||||||
dataRange := fmt.Sprintf("bytes=%v-%s", r.offset, endOffset)
|
|
||||||
return &dataRange
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
func validateSeekableStreamAt0AndGetCount(body io.ReadSeeker) (int64, error) {
|
|
||||||
if body == nil { // nil body's are "logically" seekable to 0 and are 0 bytes long
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validateSeekableStreamAt0(body)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := body.Seek(0, io.SeekEnd)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("body stream must be seekable")
|
|
||||||
}
|
|
||||||
|
|
||||||
body.Seek(0, io.SeekStart)
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// return an error if body is not a valid seekable stream at 0
|
|
||||||
func validateSeekableStreamAt0(body io.ReadSeeker) error {
|
|
||||||
if body == nil { // nil body's are "logically" seekable to 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if pos, err := body.Seek(0, io.SeekCurrent); pos != 0 || err != nil {
|
|
||||||
// Help detect programmer error
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("body stream must be seekable")
|
|
||||||
}
|
|
||||||
return errors.New("body stream must be set to position 0")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
77
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_uuid.go
generated
vendored
77
vendor/github.com/Azure/azure-storage-blob-go/azblob/zc_uuid.go
generated
vendored
@ -1,77 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The UUID reserved variants.
|
|
||||||
const (
|
|
||||||
reservedNCS byte = 0x80
|
|
||||||
reservedRFC4122 byte = 0x40
|
|
||||||
reservedMicrosoft byte = 0x20
|
|
||||||
reservedFuture byte = 0x00
|
|
||||||
)
|
|
||||||
|
|
||||||
// A UUID representation compliant with specification in RFC 4122 document.
|
|
||||||
type uuid [16]byte
|
|
||||||
|
|
||||||
// NewUUID returns a new uuid using RFC 4122 algorithm.
|
|
||||||
func newUUID() (u uuid) {
|
|
||||||
u = uuid{}
|
|
||||||
// Set all bits to randomly (or pseudo-randomly) chosen values.
|
|
||||||
rand.Read(u[:])
|
|
||||||
u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122)
|
|
||||||
|
|
||||||
var version byte = 4
|
|
||||||
u[6] = (u[6] & 0xF) | (version << 4) // u.setVersion(4)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns an unparsed version of the generated UUID sequence.
|
|
||||||
func (u uuid) String() string {
|
|
||||||
return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseUUID parses a string formatted as "003020100-0504-0706-0809-0a0b0c0d0e0f"
|
|
||||||
// or "{03020100-0504-0706-0809-0a0b0c0d0e0f}" into a UUID.
|
|
||||||
func parseUUID(uuidStr string) uuid {
|
|
||||||
char := func(hexString string) byte {
|
|
||||||
i, _ := strconv.ParseUint(hexString, 16, 8)
|
|
||||||
return byte(i)
|
|
||||||
}
|
|
||||||
if uuidStr[0] == '{' {
|
|
||||||
uuidStr = uuidStr[1:] // Skip over the '{'
|
|
||||||
}
|
|
||||||
// 03020100 - 05 04 - 07 06 - 08 09 - 0a 0b 0c 0d 0e 0f
|
|
||||||
// 1 11 1 11 11 1 12 22 2 22 22 22 33 33 33
|
|
||||||
// 01234567 8 90 12 3 45 67 8 90 12 3 45 67 89 01 23 45
|
|
||||||
uuidVal := uuid{
|
|
||||||
char(uuidStr[0:2]),
|
|
||||||
char(uuidStr[2:4]),
|
|
||||||
char(uuidStr[4:6]),
|
|
||||||
char(uuidStr[6:8]),
|
|
||||||
|
|
||||||
char(uuidStr[9:11]),
|
|
||||||
char(uuidStr[11:13]),
|
|
||||||
|
|
||||||
char(uuidStr[14:16]),
|
|
||||||
char(uuidStr[16:18]),
|
|
||||||
|
|
||||||
char(uuidStr[19:21]),
|
|
||||||
char(uuidStr[21:23]),
|
|
||||||
|
|
||||||
char(uuidStr[24:26]),
|
|
||||||
char(uuidStr[26:28]),
|
|
||||||
char(uuidStr[28:30]),
|
|
||||||
char(uuidStr[30:32]),
|
|
||||||
char(uuidStr[32:34]),
|
|
||||||
char(uuidStr[34:36]),
|
|
||||||
}
|
|
||||||
return uuidVal
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u uuid) bytes() []byte {
|
|
||||||
return u[:]
|
|
||||||
}
|
|
89
vendor/github.com/Azure/azure-storage-blob-go/azblob/zt_doc.go
generated
vendored
89
vendor/github.com/Azure/azure-storage-blob-go/azblob/zt_doc.go
generated
vendored
@ -1,89 +0,0 @@
|
|||||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
|
||||||
// Use of this source code is governed by an MIT
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package azblob allows you to manipulate Azure Storage containers and blobs objects.
|
|
||||||
|
|
||||||
URL Types
|
|
||||||
|
|
||||||
The most common types you'll work with are the XxxURL types. The methods of these types make requests
|
|
||||||
against the Azure Storage Service.
|
|
||||||
|
|
||||||
- ServiceURL's methods perform operations on a storage account.
|
|
||||||
- ContainerURL's methods perform operations on an account's container.
|
|
||||||
- BlockBlobURL's methods perform operations on a container's block blob.
|
|
||||||
- AppendBlobURL's methods perform operations on a container's append blob.
|
|
||||||
- PageBlobURL's methods perform operations on a container's page blob.
|
|
||||||
- BlobURL's methods perform operations on a container's blob regardless of the blob's type.
|
|
||||||
|
|
||||||
Internally, each XxxURL object contains a URL and a request pipeline. The URL indicates the endpoint where each HTTP
|
|
||||||
request is sent and the pipeline indicates how the outgoing HTTP request and incoming HTTP response is processed.
|
|
||||||
The pipeline specifies things like retry policies, logging, deserialization of HTTP response payloads, and more.
|
|
||||||
|
|
||||||
Pipelines are threadsafe and may be shared by multiple XxxURL objects. When you create a ServiceURL, you pass
|
|
||||||
an initial pipeline. When you call ServiceURL's NewContainerURL method, the new ContainerURL object has its own
|
|
||||||
URL but it shares the same pipeline as the parent ServiceURL object.
|
|
||||||
|
|
||||||
To work with a blob, call one of ContainerURL's 4 NewXxxBlobURL methods depending on how you want to treat the blob.
|
|
||||||
To treat the blob as a block blob, append blob, or page blob, call NewBlockBlobURL, NewAppendBlobURL, or NewPageBlobURL
|
|
||||||
respectively. These three types are all identical except for the methods they expose; each type exposes the methods
|
|
||||||
relevant to the type of blob represented. If you're not sure how you want to treat a blob, you can call NewBlobURL;
|
|
||||||
this returns an object whose methods are relevant to any kind of blob. When you call ContainerURL's NewXxxBlobURL,
|
|
||||||
the new XxxBlobURL object has its own URL but it shares the same pipeline as the parent ContainerURL object. You
|
|
||||||
can easily switch between blob types (method sets) by calling a ToXxxBlobURL method.
|
|
||||||
|
|
||||||
If you'd like to use a different pipeline with a ServiceURL, ContainerURL, or XxxBlobURL object, then call the XxxURL
|
|
||||||
object's WithPipeline method passing in the desired pipeline. The WithPipeline methods create a new XxxURL object
|
|
||||||
with the same URL as the original but with the specified pipeline.
|
|
||||||
|
|
||||||
Note that XxxURL objects use little memory, are goroutine-safe, and many objects share the same pipeline. This means that
|
|
||||||
XxxURL objects share a lot of system resources making them very efficient.
|
|
||||||
|
|
||||||
All of XxxURL's methods that make HTTP requests return rich error handling information so you can discern network failures,
|
|
||||||
transient failures, timeout failures, service failures, etc. See the StorageError interface for more information and an
|
|
||||||
example of how to do deal with errors.
|
|
||||||
|
|
||||||
URL and Shared Access Signature Manipulation
|
|
||||||
|
|
||||||
The library includes a BlobURLParts type for deconstructing and reconstructing URLs. And you can use the following types
|
|
||||||
for generating and parsing Shared Access Signature (SAS)
|
|
||||||
- Use the AccountSASSignatureValues type to create a SAS for a storage account.
|
|
||||||
- Use the BlobSASSignatureValues type to create a SAS for a container or blob.
|
|
||||||
- Use the SASQueryParameters type to turn signature values in to query parameres or to parse query parameters.
|
|
||||||
|
|
||||||
To generate a SAS, you must use the SharedKeyCredential type.
|
|
||||||
|
|
||||||
Credentials
|
|
||||||
|
|
||||||
When creating a request pipeline, you must specify one of this package's credential types.
|
|
||||||
- Call the NewAnonymousCredential function for requests that contain a Shared Access Signature (SAS).
|
|
||||||
- Call the NewSharedKeyCredential function (with an account name & key) to access any account resources. You must also use this
|
|
||||||
to generate Shared Access Signatures.
|
|
||||||
|
|
||||||
HTTP Request Policy Factories
|
|
||||||
|
|
||||||
This package defines several request policy factories for use with the pipeline package.
|
|
||||||
Most applications will not use these factories directly; instead, the NewPipeline
|
|
||||||
function creates these factories, initializes them (via the PipelineOptions type)
|
|
||||||
and returns a pipeline object for use by the XxxURL objects.
|
|
||||||
|
|
||||||
However, for advanced scenarios, developers can access these policy factories directly
|
|
||||||
and even create their own and then construct their own pipeline in order to affect HTTP
|
|
||||||
requests and responses performed by the XxxURL objects. For example, developers can
|
|
||||||
introduce their own logging, random failures, request recording & playback for fast
|
|
||||||
testing, HTTP request pacing, alternate retry mechanisms, metering, metrics, etc. The
|
|
||||||
possibilities are endless!
|
|
||||||
|
|
||||||
Below are the request pipeline policy factory functions that are provided with this
|
|
||||||
package:
|
|
||||||
- NewRetryPolicyFactory Enables rich retry semantics for failed HTTP requests.
|
|
||||||
- NewRequestLogPolicyFactory Enables rich logging support for HTTP requests/responses & failures.
|
|
||||||
- NewTelemetryPolicyFactory Enables simple modification of the HTTP request's User-Agent header so each request reports the SDK version & language/runtime making the requests.
|
|
||||||
- NewUniqueRequestIDPolicyFactory Adds a x-ms-client-request-id header with a unique UUID value to an HTTP request to help with diagnosing failures.
|
|
||||||
|
|
||||||
Also, note that all the NewXxxCredential functions return request policy factory objects which get injected into the pipeline.
|
|
||||||
*/
|
|
||||||
package azblob
|
|
||||||
|
|
||||||
// TokenCredential Use this to access resources using Role-Based Access Control (RBAC).
|
|
403
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_append_blob.go
generated
vendored
403
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_append_blob.go
generated
vendored
@ -1,403 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// appendBlobClient is the client for the AppendBlob methods of the Azblob service.
|
|
||||||
type appendBlobClient struct {
|
|
||||||
managementClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// newAppendBlobClient creates an instance of the appendBlobClient client.
|
|
||||||
func newAppendBlobClient(url url.URL, p pipeline.Pipeline) appendBlobClient {
|
|
||||||
return appendBlobClient{newManagementClient(url, p)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendBlock the Append Block operation commits a new block of data to the end of an existing append blob. The Append
|
|
||||||
// Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is
|
|
||||||
// supported only on version 2015-02-21 version or later.
|
|
||||||
//
|
|
||||||
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
|
|
||||||
// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
|
|
||||||
// information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
|
|
||||||
// be validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to be
|
|
||||||
// validated by the service. leaseID is if specified, the operation only succeeds if the resource's lease is active and
|
|
||||||
// matches this ID. maxSize is optional conditional header. The max length in bytes permitted for the append blob. If
|
|
||||||
// the Append Block operation would cause the blob to exceed that limit or if the blob size is already greater than the
|
|
||||||
// value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code 412 -
|
|
||||||
// Precondition Failed). appendPosition is optional conditional header, used only for the Append Block operation. A
|
|
||||||
// number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to this
|
|
||||||
// number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412 -
|
|
||||||
// Precondition Failed). encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in
|
|
||||||
// the request. If not specified, encryption is performed with the root account encryption key. For more information,
|
|
||||||
// see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided
|
|
||||||
// encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm
|
|
||||||
// used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the
|
|
||||||
// x-ms-encryption-key header is provided. ifModifiedSince is specify this header value to operate only on a blob if it
|
|
||||||
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
|
|
||||||
// blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
|
|
||||||
// blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
|
|
||||||
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
|
|
||||||
// logs when storage analytics logging is enabled.
|
|
||||||
func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, leaseID *string, maxSize *int64, appendPosition *int64, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: body,
|
|
||||||
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.appendBlockPreparer(body, contentLength, timeout, transactionalContentMD5, transactionalContentCrc64, leaseID, maxSize, appendPosition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.appendBlockResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*AppendBlobAppendBlockResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendBlockPreparer prepares the AppendBlock request.
|
|
||||||
func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, leaseID *string, maxSize *int64, appendPosition *int64, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "appendblock")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
if transactionalContentCrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if maxSize != nil {
|
|
||||||
req.Header.Set("x-ms-blob-condition-maxsize", strconv.FormatInt(*maxSize, 10))
|
|
||||||
}
|
|
||||||
if appendPosition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10))
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendBlockResponder handles the response to the AppendBlock request.
|
|
||||||
func (client appendBlobClient) appendBlockResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &AppendBlobAppendBlockResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendBlockFromURL the Append Block operation commits a new block of data to the end of an existing append blob
|
|
||||||
// where the contents are read from a source url. The Append Block operation is permitted only if the blob was created
|
|
||||||
// with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later.
|
|
||||||
//
|
|
||||||
// sourceURL is specify a URL to the copy source. contentLength is the length of the request. sourceRange is bytes of
|
|
||||||
// source data in the specified range. sourceContentMD5 is specify the md5 calculated for the range of bytes that must
|
|
||||||
// be read from the copy source. sourceContentcrc64 is specify the crc64 calculated for the range of bytes that must be
|
|
||||||
// read from the copy source. timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
|
|
||||||
// be validated by the service. encryptionKey is optional. Specifies the encryption key to use to encrypt the data
|
|
||||||
// provided in the request. If not specified, encryption is performed with the root account encryption key. For more
|
|
||||||
// information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
|
|
||||||
// provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
|
|
||||||
// algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
|
|
||||||
// if the x-ms-encryption-key header is provided. leaseID is if specified, the operation only succeeds if the
|
|
||||||
// resource's lease is active and matches this ID. maxSize is optional conditional header. The max length in bytes
|
|
||||||
// permitted for the append blob. If the Append Block operation would cause the blob to exceed that limit or if the
|
|
||||||
// blob size is already greater than the value specified in this header, the request will fail with
|
|
||||||
// MaxBlobSizeConditionNotMet error (HTTP status code 412 - Precondition Failed). appendPosition is optional
|
|
||||||
// conditional header, used only for the Append Block operation. A number indicating the byte offset to compare. Append
|
|
||||||
// Block will succeed only if the append position is equal to this number. If it is not, the request will fail with the
|
|
||||||
// AppendPositionConditionNotMet error (HTTP status code 412 - Precondition Failed). ifModifiedSince is specify this
|
|
||||||
// header value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is
|
|
||||||
// specify this header value to operate only on a blob if it has not been modified since the specified date/time.
|
|
||||||
// ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag
|
|
||||||
// value to operate only on blobs without a matching value. sourceIfModifiedSince is specify this header value to
|
|
||||||
// operate only on a blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify
|
|
||||||
// this header value to operate only on a blob if it has not been modified since the specified date/time. sourceIfMatch
|
|
||||||
// is specify an ETag value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value
|
|
||||||
// to operate only on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1
|
|
||||||
// KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client appendBlobClient) AppendBlockFromURL(ctx context.Context, sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, transactionalContentMD5 []byte, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockFromURLResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.appendBlockFromURLPreparer(sourceURL, contentLength, sourceRange, sourceContentMD5, sourceContentcrc64, timeout, transactionalContentMD5, encryptionKey, encryptionKeySha256, encryptionAlgorithm, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.appendBlockFromURLResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*AppendBlobAppendBlockFromURLResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendBlockFromURLPreparer prepares the AppendBlockFromURL request.
|
|
||||||
func (client appendBlobClient) appendBlockFromURLPreparer(sourceURL string, contentLength int64, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, transactionalContentMD5 []byte, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "appendblock")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-copy-source", sourceURL)
|
|
||||||
if sourceRange != nil {
|
|
||||||
req.Header.Set("x-ms-source-range", *sourceRange)
|
|
||||||
}
|
|
||||||
if sourceContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
|
|
||||||
}
|
|
||||||
if sourceContentcrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if maxSize != nil {
|
|
||||||
req.Header.Set("x-ms-blob-condition-maxsize", strconv.FormatInt(*maxSize, 10))
|
|
||||||
}
|
|
||||||
if appendPosition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
if sourceIfModifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-match", string(*sourceIfMatch))
|
|
||||||
}
|
|
||||||
if sourceIfNoneMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendBlockFromURLResponder handles the response to the AppendBlockFromURL request.
|
|
||||||
func (client appendBlobClient) appendBlockFromURLResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &AppendBlobAppendBlockFromURLResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the Create Append Blob operation creates a new append blob.
|
|
||||||
//
|
|
||||||
// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
|
|
||||||
// information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> blobContentType is optional. Sets the blob's content type. If specified,
|
|
||||||
// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the
|
|
||||||
// blob's content encoding. If specified, this property is stored with the blob and returned with a read request.
|
|
||||||
// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the
|
|
||||||
// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this
|
|
||||||
// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded.
|
|
||||||
// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and
|
|
||||||
// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the
|
|
||||||
// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the
|
|
||||||
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified
|
|
||||||
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19,
|
|
||||||
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
|
|
||||||
// Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
|
|
||||||
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
|
|
||||||
// encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
|
|
||||||
// specified, encryption is performed with the root account encryption key. For more information, see Encryption at
|
|
||||||
// Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
|
|
||||||
// provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
|
|
||||||
// encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
|
|
||||||
// header is provided. ifModifiedSince is specify this header value to operate only on a blob if it has been modified
|
|
||||||
// since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has
|
|
||||||
// not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a
|
|
||||||
// matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is
|
|
||||||
// provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when
|
|
||||||
// storage analytics logging is enabled.
|
|
||||||
func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobCreateResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*AppendBlobCreateResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// createPreparer prepares the Create request.
|
|
||||||
func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if blobContentType != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-type", *blobContentType)
|
|
||||||
}
|
|
||||||
if blobContentEncoding != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding)
|
|
||||||
}
|
|
||||||
if blobContentLanguage != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-language", *blobContentLanguage)
|
|
||||||
}
|
|
||||||
if blobContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5))
|
|
||||||
}
|
|
||||||
if blobCacheControl != nil {
|
|
||||||
req.Header.Set("x-ms-blob-cache-control", *blobCacheControl)
|
|
||||||
}
|
|
||||||
if metadata != nil {
|
|
||||||
for k, v := range metadata {
|
|
||||||
req.Header.Set("x-ms-meta-"+k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if blobContentDisposition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-blob-type", "AppendBlob")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createResponder handles the response to the Create request.
|
|
||||||
func (client appendBlobClient) createResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &AppendBlobCreateResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
1620
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_blob.go
generated
vendored
1620
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_blob.go
generated
vendored
File diff suppressed because it is too large
Load Diff
592
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_block_blob.go
generated
vendored
592
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_block_blob.go
generated
vendored
@ -1,592 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/xml"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// blockBlobClient is the client for the BlockBlob methods of the Azblob service.
|
|
||||||
type blockBlobClient struct {
|
|
||||||
managementClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// newBlockBlobClient creates an instance of the blockBlobClient client.
|
|
||||||
func newBlockBlobClient(url url.URL, p pipeline.Pipeline) blockBlobClient {
|
|
||||||
return blockBlobClient{newManagementClient(url, p)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommitBlockList the Commit Block List operation writes a blob by specifying the list of block IDs that make up the
|
|
||||||
// blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior
|
|
||||||
// Put Block operation. You can call Put Block List to update a blob by uploading only those blocks that have changed,
|
|
||||||
// then committing the new and existing blocks together. You can do this by specifying whether to commit a block from
|
|
||||||
// the committed block list or from the uncommitted block list, or to commit the most recently uploaded version of the
|
|
||||||
// block, whichever list it may belong to.
|
|
||||||
//
|
|
||||||
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> blobCacheControl is optional. Sets the blob's cache control. If specified,
|
|
||||||
// this property is stored with the blob and returned with a read request. blobContentType is optional. Sets the blob's
|
|
||||||
// content type. If specified, this property is stored with the blob and returned with a read request.
|
|
||||||
// blobContentEncoding is optional. Sets the blob's content encoding. If specified, this property is stored with the
|
|
||||||
// blob and returned with a read request. blobContentLanguage is optional. Set the blob's content language. If
|
|
||||||
// specified, this property is stored with the blob and returned with a read request. blobContentMD5 is optional. An
|
|
||||||
// MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were
|
|
||||||
// validated when each was uploaded. transactionalContentMD5 is specify the transactional md5 for the body, to be
|
|
||||||
// validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to be validated
|
|
||||||
// by the service. metadata is optional. Specifies a user-defined name-value pair associated with the blob. If no
|
|
||||||
// name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination
|
|
||||||
// blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata,
|
|
||||||
// and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names
|
|
||||||
// must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for
|
|
||||||
// more information. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches
|
|
||||||
// this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. encryptionKey is optional.
|
|
||||||
// Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is
|
|
||||||
// performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage
|
|
||||||
// Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be provided if the
|
|
||||||
// x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the encryption key
|
|
||||||
// hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is
|
|
||||||
// provided. tier is optional. Indicates the tier to be set on the blob. ifModifiedSince is specify this header value
|
|
||||||
// to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this
|
|
||||||
// header value to operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify
|
|
||||||
// an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only
|
|
||||||
// on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character
|
|
||||||
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobCommitBlockListResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, transactionalContentMD5, transactionalContentCrc64, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, tier, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.commitBlockListResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*BlockBlobCommitBlockListResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// commitBlockListPreparer prepares the CommitBlockList request.
|
|
||||||
func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "blocklist")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if blobCacheControl != nil {
|
|
||||||
req.Header.Set("x-ms-blob-cache-control", *blobCacheControl)
|
|
||||||
}
|
|
||||||
if blobContentType != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-type", *blobContentType)
|
|
||||||
}
|
|
||||||
if blobContentEncoding != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding)
|
|
||||||
}
|
|
||||||
if blobContentLanguage != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-language", *blobContentLanguage)
|
|
||||||
}
|
|
||||||
if blobContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5))
|
|
||||||
}
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
if transactionalContentCrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
|
|
||||||
}
|
|
||||||
if metadata != nil {
|
|
||||||
for k, v := range metadata {
|
|
||||||
req.Header.Set("x-ms-meta-"+k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if blobContentDisposition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if tier != AccessTierNone {
|
|
||||||
req.Header.Set("x-ms-access-tier", string(tier))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
b, err := xml.Marshal(blocks)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to marshal request body")
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/xml")
|
|
||||||
err = req.SetBody(bytes.NewReader(b))
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to set request body")
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// commitBlockListResponder handles the response to the CommitBlockList request.
|
|
||||||
func (client blockBlobClient) commitBlockListResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &BlockBlobCommitBlockListResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlockList the Get Block List operation retrieves the list of blocks that have been uploaded as part of a block
|
|
||||||
// blob
|
|
||||||
//
|
|
||||||
// listType is specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists
|
|
||||||
// together. snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob
|
|
||||||
// snapshot to retrieve. For more information on working with blob snapshots, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
|
|
||||||
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
|
|
||||||
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
|
|
||||||
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (*BlockList, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getBlockListPreparer(listType, snapshot, timeout, leaseID, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getBlockListResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*BlockList), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBlockListPreparer prepares the GetBlockList request.
|
|
||||||
func (client blockBlobClient) getBlockListPreparer(listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if snapshot != nil && len(*snapshot) > 0 {
|
|
||||||
params.Set("snapshot", *snapshot)
|
|
||||||
}
|
|
||||||
params.Set("blocklisttype", string(listType))
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "blocklist")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getBlockListResponder handles the response to the GetBlockList request.
|
|
||||||
func (client blockBlobClient) getBlockListResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &BlockList{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StageBlock the Stage Block operation creates a new block to be committed as part of a blob
|
|
||||||
//
|
|
||||||
// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or
|
|
||||||
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
|
|
||||||
// same size for each block. contentLength is the length of the request. body is initial data body will be closed upon
|
|
||||||
// successful return. Callers should ensure closure when receiving an error.transactionalContentMD5 is specify the
|
|
||||||
// transactional md5 for the body, to be validated by the service. transactionalContentCrc64 is specify the
|
|
||||||
// transactional crc64 for the body, to be validated by the service. timeout is the timeout parameter is expressed in
|
|
||||||
// seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
|
|
||||||
// lease is active and matches this ID. encryptionKey is optional. Specifies the encryption key to use to encrypt the
|
|
||||||
// data provided in the request. If not specified, encryption is performed with the root account encryption key. For
|
|
||||||
// more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
|
|
||||||
// provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
|
|
||||||
// algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
|
|
||||||
// if the x-ms-encryption-key header is provided. requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, requestID *string) (*BlockBlobStageBlockResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: body,
|
|
||||||
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.stageBlockPreparer(blockID, contentLength, body, transactionalContentMD5, transactionalContentCrc64, timeout, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.stageBlockResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*BlockBlobStageBlockResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// stageBlockPreparer prepares the StageBlock request.
|
|
||||||
func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
params.Set("blockid", blockID)
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "block")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
if transactionalContentCrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// stageBlockResponder handles the response to the StageBlock request.
|
|
||||||
func (client blockBlobClient) stageBlockResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &BlockBlobStageBlockResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// StageBlockFromURL the Stage Block operation creates a new block to be committed as part of a blob where the contents
|
|
||||||
// are read from a URL.
|
|
||||||
//
|
|
||||||
// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or
|
|
||||||
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
|
|
||||||
// same size for each block. contentLength is the length of the request. sourceURL is specify a URL to the copy source.
|
|
||||||
// sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated for the
|
|
||||||
// range of bytes that must be read from the copy source. sourceContentcrc64 is specify the crc64 calculated for the
|
|
||||||
// range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in seconds. For
|
|
||||||
// more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> encryptionKey is optional. Specifies the encryption key to use to encrypt
|
|
||||||
// the data provided in the request. If not specified, encryption is performed with the root account encryption key.
|
|
||||||
// For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of
|
|
||||||
// the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is
|
|
||||||
// the algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be
|
|
||||||
// provided if the x-ms-encryption-key header is provided. leaseID is if specified, the operation only succeeds if the
|
|
||||||
// resource's lease is active and matches this ID. sourceIfModifiedSince is specify this header value to operate only
|
|
||||||
// on a blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header
|
|
||||||
// value to operate only on a blob if it has not been modified since the specified date/time. sourceIfMatch is specify
|
|
||||||
// an ETag value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to operate
|
|
||||||
// only on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character
|
|
||||||
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.stageBlockFromURLPreparer(blockID, contentLength, sourceURL, sourceRange, sourceContentMD5, sourceContentcrc64, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, leaseID, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.stageBlockFromURLResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*BlockBlobStageBlockFromURLResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// stageBlockFromURLPreparer prepares the StageBlockFromURL request.
|
|
||||||
func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
params.Set("blockid", blockID)
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "block")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
req.Header.Set("x-ms-copy-source", sourceURL)
|
|
||||||
if sourceRange != nil {
|
|
||||||
req.Header.Set("x-ms-source-range", *sourceRange)
|
|
||||||
}
|
|
||||||
if sourceContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
|
|
||||||
}
|
|
||||||
if sourceContentcrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if sourceIfModifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-match", string(*sourceIfMatch))
|
|
||||||
}
|
|
||||||
if sourceIfNoneMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// stageBlockFromURLResponder handles the response to the StageBlockFromURL request.
|
|
||||||
func (client blockBlobClient) stageBlockFromURLResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &BlockBlobStageBlockFromURLResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload the Upload Block Blob operation updates the content of an existing block blob. Updating an existing block
|
|
||||||
// blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of
|
|
||||||
// the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a
|
|
||||||
// block blob, use the Put Block List operation.
|
|
||||||
//
|
|
||||||
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
|
|
||||||
// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
|
|
||||||
// information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
|
|
||||||
// be validated by the service. blobContentType is optional. Sets the blob's content type. If specified, this property
|
|
||||||
// is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the blob's content
|
|
||||||
// encoding. If specified, this property is stored with the blob and returned with a read request. blobContentLanguage
|
|
||||||
// is optional. Set the blob's content language. If specified, this property is stored with the blob and returned with
|
|
||||||
// a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this hash is not validated,
|
|
||||||
// as the hashes for the individual blocks were validated when each was uploaded. blobCacheControl is optional. Sets
|
|
||||||
// the blob's cache control. If specified, this property is stored with the blob and returned with a read request.
|
|
||||||
// metadata is optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are
|
|
||||||
// specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more
|
|
||||||
// name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not
|
|
||||||
// copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the
|
|
||||||
// naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information.
|
|
||||||
// leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
|
|
||||||
// blobContentDisposition is optional. Sets the blob's Content-Disposition header. encryptionKey is optional. Specifies
|
|
||||||
// the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed
|
|
||||||
// with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services.
|
|
||||||
// encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key
|
|
||||||
// header is provided. encryptionAlgorithm is the algorithm used to produce the encryption key hash. Currently, the
|
|
||||||
// only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. tier is optional.
|
|
||||||
// Indicates the tier to be set on the blob. ifModifiedSince is specify this header value to operate only on a blob if
|
|
||||||
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
|
|
||||||
// on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
|
|
||||||
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
|
|
||||||
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
|
|
||||||
// in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobUploadResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: body,
|
|
||||||
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.uploadPreparer(body, contentLength, timeout, transactionalContentMD5, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, tier, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.uploadResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*BlockBlobUploadResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadPreparer prepares the Upload request.
|
|
||||||
func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, tier AccessTierType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if blobContentType != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-type", *blobContentType)
|
|
||||||
}
|
|
||||||
if blobContentEncoding != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding)
|
|
||||||
}
|
|
||||||
if blobContentLanguage != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-language", *blobContentLanguage)
|
|
||||||
}
|
|
||||||
if blobContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5))
|
|
||||||
}
|
|
||||||
if blobCacheControl != nil {
|
|
||||||
req.Header.Set("x-ms-blob-cache-control", *blobCacheControl)
|
|
||||||
}
|
|
||||||
if metadata != nil {
|
|
||||||
for k, v := range metadata {
|
|
||||||
req.Header.Set("x-ms-meta-"+k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if blobContentDisposition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if tier != AccessTierNone {
|
|
||||||
req.Header.Set("x-ms-access-tier", string(tier))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-blob-type", "BlockBlob")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadResponder handles the response to the Upload request.
|
|
||||||
func (client blockBlobClient) uploadResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &BlockBlobUploadResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_client.go
generated
vendored
38
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_client.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ServiceVersion specifies the version of the operations used in this package.
|
|
||||||
ServiceVersion = "2019-02-02"
|
|
||||||
)
|
|
||||||
|
|
||||||
// managementClient is the base client for Azblob.
|
|
||||||
type managementClient struct {
|
|
||||||
url url.URL
|
|
||||||
p pipeline.Pipeline
|
|
||||||
}
|
|
||||||
|
|
||||||
// newManagementClient creates an instance of the managementClient client.
|
|
||||||
func newManagementClient(url url.URL, p pipeline.Pipeline) managementClient {
|
|
||||||
return managementClient{
|
|
||||||
url: url,
|
|
||||||
p: p,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL returns a copy of the URL for this client.
|
|
||||||
func (mc managementClient) URL() url.URL {
|
|
||||||
return mc.url
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pipeline returns the pipeline for this client.
|
|
||||||
func (mc managementClient) Pipeline() pipeline.Pipeline {
|
|
||||||
return mc.p
|
|
||||||
}
|
|
1037
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_container.go
generated
vendored
1037
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_container.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6421
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_models.go
generated
vendored
6421
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_models.go
generated
vendored
File diff suppressed because it is too large
Load Diff
977
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_page_blob.go
generated
vendored
977
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_page_blob.go
generated
vendored
@ -1,977 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/xml"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// pageBlobClient is the client for the PageBlob methods of the Azblob service.
|
|
||||||
type pageBlobClient struct {
|
|
||||||
managementClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// newPageBlobClient creates an instance of the pageBlobClient client.
|
|
||||||
func newPageBlobClient(url url.URL, p pipeline.Pipeline) pageBlobClient {
|
|
||||||
return pageBlobClient{newManagementClient(url, p)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearPages the Clear Pages operation clears a set of pages from a page blob
|
|
||||||
//
|
|
||||||
// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
|
|
||||||
// information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
|
|
||||||
// range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
|
|
||||||
// encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
|
|
||||||
// specified, encryption is performed with the root account encryption key. For more information, see Encryption at
|
|
||||||
// Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
|
|
||||||
// provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
|
|
||||||
// encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
|
|
||||||
// header is provided. ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it
|
|
||||||
// has a sequence number less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to
|
|
||||||
// operate only on a blob if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this
|
|
||||||
// header value to operate only on a blob if it has the specified sequence number. ifModifiedSince is specify this
|
|
||||||
// header value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is
|
|
||||||
// specify this header value to operate only on a blob if it has not been modified since the specified date/time.
|
|
||||||
// ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag
|
|
||||||
// value to operate only on blobs without a matching value. requestID is provides a client-generated, opaque value with
|
|
||||||
// a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.clearPagesResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobClearPagesResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearPagesPreparer prepares the ClearPages request.
|
|
||||||
func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "page")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if rangeParameter != nil {
|
|
||||||
req.Header.Set("x-ms-range", *rangeParameter)
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThanOrEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThan != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-lt", strconv.FormatInt(*ifSequenceNumberLessThan, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-eq", strconv.FormatInt(*ifSequenceNumberEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-page-write", "clear")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearPagesResponder handles the response to the ClearPages request.
|
|
||||||
func (client pageBlobClient) clearPagesResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobClearPagesResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyIncremental the Copy Incremental operation copies a snapshot of the source page blob to a destination page blob.
|
|
||||||
// The snapshot is copied such that only the differential changes between the previously copied snapshot are
|
|
||||||
// transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read or
|
|
||||||
// copied from as usual. This API is supported since REST version 2016-05-31.
|
|
||||||
//
|
|
||||||
// copySource is specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that
|
|
||||||
// specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob
|
|
||||||
// must either be public or must be authenticated via a shared access signature. timeout is the timeout parameter is
|
|
||||||
// expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
|
|
||||||
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
|
|
||||||
// on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
|
|
||||||
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
|
|
||||||
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
|
|
||||||
// in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) CopyIncremental(ctx context.Context, copySource string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobCopyIncrementalResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.copyIncrementalPreparer(copySource, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.copyIncrementalResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobCopyIncrementalResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyIncrementalPreparer prepares the CopyIncremental request.
|
|
||||||
func (client pageBlobClient) copyIncrementalPreparer(copySource string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "incrementalcopy")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-copy-source", copySource)
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyIncrementalResponder handles the response to the CopyIncremental request.
|
|
||||||
func (client pageBlobClient) copyIncrementalResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusAccepted)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobCopyIncrementalResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the Create operation creates a new page blob.
|
|
||||||
//
|
|
||||||
// contentLength is the length of the request. blobContentLength is this header specifies the maximum size for the page
|
|
||||||
// blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. timeout is the timeout parameter is
|
|
||||||
// expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> tier is optional. Indicates the tier to be set on the page blob.
|
|
||||||
// blobContentType is optional. Sets the blob's content type. If specified, this property is stored with the blob and
|
|
||||||
// returned with a read request. blobContentEncoding is optional. Sets the blob's content encoding. If specified, this
|
|
||||||
// property is stored with the blob and returned with a read request. blobContentLanguage is optional. Set the blob's
|
|
||||||
// content language. If specified, this property is stored with the blob and returned with a read request.
|
|
||||||
// blobContentMD5 is optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for
|
|
||||||
// the individual blocks were validated when each was uploaded. blobCacheControl is optional. Sets the blob's cache
|
|
||||||
// control. If specified, this property is stored with the blob and returned with a read request. metadata is optional.
|
|
||||||
// Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the
|
|
||||||
// operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value
|
|
||||||
// pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from
|
|
||||||
// the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules
|
|
||||||
// for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. leaseID is if
|
|
||||||
// specified, the operation only succeeds if the resource's lease is active and matches this ID. blobContentDisposition
|
|
||||||
// is optional. Sets the blob's Content-Disposition header. encryptionKey is optional. Specifies the encryption key to
|
|
||||||
// use to encrypt the data provided in the request. If not specified, encryption is performed with the root account
|
|
||||||
// encryption key. For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the
|
|
||||||
// SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided.
|
|
||||||
// encryptionAlgorithm is the algorithm used to produce the encryption key hash. Currently, the only accepted value is
|
|
||||||
// "AES256". Must be provided if the x-ms-encryption-key header is provided. ifModifiedSince is specify this header
|
|
||||||
// value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify
|
|
||||||
// this header value to operate only on a blob if it has not been modified since the specified date/time. ifMatch is
|
|
||||||
// specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to
|
|
||||||
// operate only on blobs without a matching value. blobSequenceNumber is set for page blobs only. The sequence number
|
|
||||||
// is a user-controlled value that you can use to track requests. The value of the sequence number must be between 0
|
|
||||||
// and 2^63 - 1. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in
|
|
||||||
// the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) Create(ctx context.Context, contentLength int64, blobContentLength int64, timeout *int32, tier PremiumPageBlobAccessTierType, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobCreateResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.createPreparer(contentLength, blobContentLength, timeout, tier, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobSequenceNumber, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobCreateResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// createPreparer prepares the Create request.
|
|
||||||
func (client pageBlobClient) createPreparer(contentLength int64, blobContentLength int64, timeout *int32, tier PremiumPageBlobAccessTierType, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if tier != PremiumPageBlobAccessTierNone {
|
|
||||||
req.Header.Set("x-ms-access-tier", string(tier))
|
|
||||||
}
|
|
||||||
if blobContentType != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-type", *blobContentType)
|
|
||||||
}
|
|
||||||
if blobContentEncoding != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding)
|
|
||||||
}
|
|
||||||
if blobContentLanguage != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-language", *blobContentLanguage)
|
|
||||||
}
|
|
||||||
if blobContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5))
|
|
||||||
}
|
|
||||||
if blobCacheControl != nil {
|
|
||||||
req.Header.Set("x-ms-blob-cache-control", *blobCacheControl)
|
|
||||||
}
|
|
||||||
if metadata != nil {
|
|
||||||
for k, v := range metadata {
|
|
||||||
req.Header.Set("x-ms-meta-"+k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if blobContentDisposition != nil {
|
|
||||||
req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10))
|
|
||||||
if blobSequenceNumber != nil {
|
|
||||||
req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-blob-type", "PageBlob")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createResponder handles the response to the Create request.
|
|
||||||
func (client pageBlobClient) createResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobCreateResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPageRanges the Get Page Ranges operation returns the list of valid page ranges for a page blob or snapshot of a
|
|
||||||
// page blob
|
|
||||||
//
|
|
||||||
// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to
|
|
||||||
// retrieve. For more information on working with blob snapshots, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
|
|
||||||
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
|
|
||||||
// range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
|
|
||||||
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
|
|
||||||
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
|
|
||||||
// since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
|
|
||||||
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a
|
|
||||||
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
|
|
||||||
// analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPageRangesResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageList), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPageRangesPreparer prepares the GetPageRanges request.
|
|
||||||
func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if snapshot != nil && len(*snapshot) > 0 {
|
|
||||||
params.Set("snapshot", *snapshot)
|
|
||||||
}
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "pagelist")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if rangeParameter != nil {
|
|
||||||
req.Header.Set("x-ms-range", *rangeParameter)
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPageRangesResponder handles the response to the GetPageRanges request.
|
|
||||||
func (client pageBlobClient) getPageRangesResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &PageList{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPageRangesDiff the Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that were
|
|
||||||
// changed between target blob and previous snapshot.
|
|
||||||
//
|
|
||||||
// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to
|
|
||||||
// retrieve. For more information on working with blob snapshots, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
|
|
||||||
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> prevsnapshot is optional in version 2015-07-08 and newer. The prevsnapshot
|
|
||||||
// parameter is a DateTime value that specifies that the response will contain only pages that were changed between
|
|
||||||
// target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a
|
|
||||||
// snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots
|
|
||||||
// are currently supported only for blobs created on or after January 1, 2016. rangeParameter is return only the bytes
|
|
||||||
// of the blob in the specified range. leaseID is if specified, the operation only succeeds if the resource's lease is
|
|
||||||
// active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it has been
|
|
||||||
// modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if
|
|
||||||
// it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs
|
|
||||||
// with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
|
|
||||||
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
|
|
||||||
// logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPageRangesDiffResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageList), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPageRangesDiffPreparer prepares the GetPageRangesDiff request.
|
|
||||||
func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if snapshot != nil && len(*snapshot) > 0 {
|
|
||||||
params.Set("snapshot", *snapshot)
|
|
||||||
}
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
if prevsnapshot != nil && len(*prevsnapshot) > 0 {
|
|
||||||
params.Set("prevsnapshot", *prevsnapshot)
|
|
||||||
}
|
|
||||||
params.Set("comp", "pagelist")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if rangeParameter != nil {
|
|
||||||
req.Header.Set("x-ms-range", *rangeParameter)
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPageRangesDiffResponder handles the response to the GetPageRangesDiff request.
|
|
||||||
func (client pageBlobClient) getPageRangesDiffResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &PageList{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize resize the Blob
|
|
||||||
//
|
|
||||||
// blobContentLength is this header specifies the maximum size for the page blob, up to 1 TB. The page blob size must
|
|
||||||
// be aligned to a 512-byte boundary. timeout is the timeout parameter is expressed in seconds. For more information,
|
|
||||||
// see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
|
|
||||||
// lease is active and matches this ID. encryptionKey is optional. Specifies the encryption key to use to encrypt the
|
|
||||||
// data provided in the request. If not specified, encryption is performed with the root account encryption key. For
|
|
||||||
// more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the
|
|
||||||
// provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the
|
|
||||||
// algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided
|
|
||||||
// if the x-ms-encryption-key header is provided. ifModifiedSince is specify this header value to operate only on a
|
|
||||||
// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
|
|
||||||
// operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
|
|
||||||
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
|
|
||||||
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
|
|
||||||
// recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.resizePreparer(blobContentLength, timeout, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.resizeResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobResizeResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// resizePreparer prepares the Resize request.
|
|
||||||
func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "properties")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10))
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// resizeResponder handles the response to the Resize request.
|
|
||||||
func (client pageBlobClient) resizeResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobResizeResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateSequenceNumber update the sequence number of the blob
|
|
||||||
//
|
|
||||||
// sequenceNumberAction is required if the x-ms-blob-sequence-number header is set for the request. This property
|
|
||||||
// applies to page blobs only. This property indicates how the service should modify the blob's sequence number timeout
|
|
||||||
// is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
|
|
||||||
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
|
|
||||||
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
|
|
||||||
// blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
|
|
||||||
// blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
|
|
||||||
// blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can use to
|
|
||||||
// track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a
|
|
||||||
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
|
|
||||||
// analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobUpdateSequenceNumberResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.updateSequenceNumberPreparer(sequenceNumberAction, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobSequenceNumber, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.updateSequenceNumberResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobUpdateSequenceNumberResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateSequenceNumberPreparer prepares the UpdateSequenceNumber request.
|
|
||||||
func (client pageBlobClient) updateSequenceNumberPreparer(sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "properties")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-sequence-number-action", string(sequenceNumberAction))
|
|
||||||
if blobSequenceNumber != nil {
|
|
||||||
req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateSequenceNumberResponder handles the response to the UpdateSequenceNumber request.
|
|
||||||
func (client pageBlobClient) updateSequenceNumberResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobUpdateSequenceNumberResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadPages the Upload Pages operation writes a range of pages to a page blob
|
|
||||||
//
|
|
||||||
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
|
|
||||||
// error.contentLength is the length of the request. transactionalContentMD5 is specify the transactional md5 for the
|
|
||||||
// body, to be validated by the service. transactionalContentCrc64 is specify the transactional crc64 for the body, to
|
|
||||||
// be validated by the service. timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
|
|
||||||
// range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
|
|
||||||
// encryptionKey is optional. Specifies the encryption key to use to encrypt the data provided in the request. If not
|
|
||||||
// specified, encryption is performed with the root account encryption key. For more information, see Encryption at
|
|
||||||
// Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of the provided encryption key. Must be
|
|
||||||
// provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is the algorithm used to produce the
|
|
||||||
// encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key
|
|
||||||
// header is provided. ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it
|
|
||||||
// has a sequence number less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to
|
|
||||||
// operate only on a blob if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this
|
|
||||||
// header value to operate only on a blob if it has the specified sequence number. ifModifiedSince is specify this
|
|
||||||
// header value to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is
|
|
||||||
// specify this header value to operate only on a blob if it has not been modified since the specified date/time.
|
|
||||||
// ifMatch is specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag
|
|
||||||
// value to operate only on blobs without a matching value. requestID is provides a client-generated, opaque value with
|
|
||||||
// a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: body,
|
|
||||||
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.uploadPagesPreparer(body, contentLength, transactionalContentMD5, transactionalContentCrc64, timeout, rangeParameter, leaseID, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.uploadPagesResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobUploadPagesResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadPagesPreparer prepares the UploadPages request.
|
|
||||||
func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, transactionalContentCrc64 []byte, timeout *int32, rangeParameter *string, leaseID *string, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "page")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
if transactionalContentMD5 != nil {
|
|
||||||
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
|
|
||||||
}
|
|
||||||
if transactionalContentCrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-content-crc64", base64.StdEncoding.EncodeToString(transactionalContentCrc64))
|
|
||||||
}
|
|
||||||
if rangeParameter != nil {
|
|
||||||
req.Header.Set("x-ms-range", *rangeParameter)
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThanOrEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThan != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-lt", strconv.FormatInt(*ifSequenceNumberLessThan, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-eq", strconv.FormatInt(*ifSequenceNumberEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-page-write", "update")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadPagesResponder handles the response to the UploadPages request.
|
|
||||||
func (client pageBlobClient) uploadPagesResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobUploadPagesResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadPagesFromURL the Upload Pages operation writes a range of pages to a page blob where the contents are read
|
|
||||||
// from a URL
|
|
||||||
//
|
|
||||||
// sourceURL is specify a URL to the copy source. sourceRange is bytes of source data in the specified range. The
|
|
||||||
// length of this range should match the ContentLength header and x-ms-range/Range destination range header.
|
|
||||||
// contentLength is the length of the request. rangeParameter is the range of bytes to which the source range would be
|
|
||||||
// written. The range should be 512 aligned and range-end is required. sourceContentMD5 is specify the md5 calculated
|
|
||||||
// for the range of bytes that must be read from the copy source. sourceContentcrc64 is specify the crc64 calculated
|
|
||||||
// for the range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in
|
|
||||||
// seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> encryptionKey is optional. Specifies the encryption key to use to encrypt
|
|
||||||
// the data provided in the request. If not specified, encryption is performed with the root account encryption key.
|
|
||||||
// For more information, see Encryption at Rest for Azure Storage Services. encryptionKeySha256 is the SHA-256 hash of
|
|
||||||
// the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. encryptionAlgorithm is
|
|
||||||
// the algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be
|
|
||||||
// provided if the x-ms-encryption-key header is provided. leaseID is if specified, the operation only succeeds if the
|
|
||||||
// resource's lease is active and matches this ID. ifSequenceNumberLessThanOrEqualTo is specify this header value to
|
|
||||||
// operate only on a blob if it has a sequence number less than or equal to the specified. ifSequenceNumberLessThan is
|
|
||||||
// specify this header value to operate only on a blob if it has a sequence number less than the specified.
|
|
||||||
// ifSequenceNumberEqualTo is specify this header value to operate only on a blob if it has the specified sequence
|
|
||||||
// number. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the
|
|
||||||
// specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been
|
|
||||||
// modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching
|
|
||||||
// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. sourceIfModifiedSince
|
|
||||||
// is specify this header value to operate only on a blob if it has been modified since the specified date/time.
|
|
||||||
// sourceIfUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified since the
|
|
||||||
// specified date/time. sourceIfMatch is specify an ETag value to operate only on blobs with a matching value.
|
|
||||||
// sourceIfNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides
|
|
||||||
// a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
|
|
||||||
// analytics logging is enabled.
|
|
||||||
func (client pageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesFromURLResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.uploadPagesFromURLPreparer(sourceURL, sourceRange, contentLength, rangeParameter, sourceContentMD5, sourceContentcrc64, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.uploadPagesFromURLResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*PageBlobUploadPagesFromURLResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadPagesFromURLPreparer prepares the UploadPagesFromURL request.
|
|
||||||
func (client pageBlobClient) uploadPagesFromURLPreparer(sourceURL string, sourceRange string, contentLength int64, rangeParameter string, sourceContentMD5 []byte, sourceContentcrc64 []byte, timeout *int32, encryptionKey *string, encryptionKeySha256 *string, encryptionAlgorithm EncryptionAlgorithmType, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "page")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-copy-source", sourceURL)
|
|
||||||
req.Header.Set("x-ms-source-range", sourceRange)
|
|
||||||
if sourceContentMD5 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5))
|
|
||||||
}
|
|
||||||
if sourceContentcrc64 != nil {
|
|
||||||
req.Header.Set("x-ms-source-content-crc64", base64.StdEncoding.EncodeToString(sourceContentcrc64))
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
req.Header.Set("x-ms-range", rangeParameter)
|
|
||||||
if encryptionKey != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key", *encryptionKey)
|
|
||||||
}
|
|
||||||
if encryptionKeySha256 != nil {
|
|
||||||
req.Header.Set("x-ms-encryption-key-sha256", *encryptionKeySha256)
|
|
||||||
}
|
|
||||||
if encryptionAlgorithm != EncryptionAlgorithmNone {
|
|
||||||
req.Header.Set("x-ms-encryption-algorithm", string(encryptionAlgorithm))
|
|
||||||
}
|
|
||||||
if leaseID != nil {
|
|
||||||
req.Header.Set("x-ms-lease-id", *leaseID)
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThanOrEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberLessThan != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-lt", strconv.FormatInt(*ifSequenceNumberLessThan, 10))
|
|
||||||
}
|
|
||||||
if ifSequenceNumberEqualTo != nil {
|
|
||||||
req.Header.Set("x-ms-if-sequence-number-eq", strconv.FormatInt(*ifSequenceNumberEqualTo, 10))
|
|
||||||
}
|
|
||||||
if ifModifiedSince != nil {
|
|
||||||
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if ifMatch != nil {
|
|
||||||
req.Header.Set("If-Match", string(*ifMatch))
|
|
||||||
}
|
|
||||||
if ifNoneMatch != nil {
|
|
||||||
req.Header.Set("If-None-Match", string(*ifNoneMatch))
|
|
||||||
}
|
|
||||||
if sourceIfModifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfUnmodifiedSince != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123))
|
|
||||||
}
|
|
||||||
if sourceIfMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-match", string(*sourceIfMatch))
|
|
||||||
}
|
|
||||||
if sourceIfNoneMatch != nil {
|
|
||||||
req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch))
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
req.Header.Set("x-ms-page-write", "update")
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadPagesFromURLResponder handles the response to the UploadPagesFromURL request.
|
|
||||||
func (client pageBlobClient) uploadPagesFromURLResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusCreated)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &PageBlobUploadPagesFromURLResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
74
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_responder_policy.go
generated
vendored
74
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_responder_policy.go
generated
vendored
@ -1,74 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/xml"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type responder func(resp pipeline.Response) (result pipeline.Response, err error)
|
|
||||||
|
|
||||||
// ResponderPolicyFactory is a Factory capable of creating a responder pipeline.
|
|
||||||
type responderPolicyFactory struct {
|
|
||||||
responder responder
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a responder policy factory.
|
|
||||||
func (arpf responderPolicyFactory) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
|
||||||
return responderPolicy{next: next, responder: arpf.responder}
|
|
||||||
}
|
|
||||||
|
|
||||||
type responderPolicy struct {
|
|
||||||
next pipeline.Policy
|
|
||||||
responder responder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do sends the request to the service and validates/deserializes the HTTP response.
|
|
||||||
func (arp responderPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
|
|
||||||
resp, err := arp.next.Do(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return resp, err
|
|
||||||
}
|
|
||||||
return arp.responder(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateResponse checks an HTTP response's status code against a legal set of codes.
|
|
||||||
// If the response code is not legal, then validateResponse reads all of the response's body
|
|
||||||
// (containing error information) and returns a response error.
|
|
||||||
func validateResponse(resp pipeline.Response, successStatusCodes ...int) error {
|
|
||||||
if resp == nil {
|
|
||||||
return NewResponseError(nil, nil, "nil response")
|
|
||||||
}
|
|
||||||
responseCode := resp.Response().StatusCode
|
|
||||||
for _, i := range successStatusCodes {
|
|
||||||
if i == responseCode {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// only close the body in the failure case. in the
|
|
||||||
// success case responders will close the body as required.
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// the service code, description and details will be populated during unmarshalling
|
|
||||||
responseError := NewResponseError(nil, resp.Response(), resp.Response().Status)
|
|
||||||
if len(b) > 0 {
|
|
||||||
if err = xml.Unmarshal(b, &responseError); err != nil {
|
|
||||||
return NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return responseError
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes any BOM from the byte slice
|
|
||||||
func removeBOM(b []byte) []byte {
|
|
||||||
// UTF8
|
|
||||||
return bytes.TrimPrefix(b, []byte("\xef\xbb\xbf"))
|
|
||||||
}
|
|
95
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_response_error.go
generated
vendored
95
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_response_error.go
generated
vendored
@ -1,95 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// if you want to provide custom error handling set this variable to your constructor function
|
|
||||||
var responseErrorFactory func(cause error, response *http.Response, description string) error
|
|
||||||
|
|
||||||
// ResponseError identifies a responder-generated network or response parsing error.
|
|
||||||
type ResponseError interface {
|
|
||||||
// Error exposes the Error(), Temporary() and Timeout() methods.
|
|
||||||
net.Error // Includes the Go error interface
|
|
||||||
// Response returns the HTTP response. You may examine this but you should not modify it.
|
|
||||||
Response() *http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResponseError creates an error object that implements the error interface.
|
|
||||||
func NewResponseError(cause error, response *http.Response, description string) error {
|
|
||||||
if responseErrorFactory != nil {
|
|
||||||
return responseErrorFactory(cause, response, description)
|
|
||||||
}
|
|
||||||
return &responseError{
|
|
||||||
ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3),
|
|
||||||
response: response,
|
|
||||||
description: description,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// responseError is the internal struct that implements the public ResponseError interface.
|
|
||||||
type responseError struct {
|
|
||||||
pipeline.ErrorNode // This is embedded so that responseError "inherits" Error, Temporary, Timeout, and Cause
|
|
||||||
response *http.Response
|
|
||||||
description string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface's Error method to return a string representation of the error.
|
|
||||||
func (e *responseError) Error() string {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
fmt.Fprintf(b, "===== RESPONSE ERROR (Code=%v) =====\n", e.response.StatusCode)
|
|
||||||
fmt.Fprintf(b, "Status=%s, Description: %s\n", e.response.Status, e.description)
|
|
||||||
s := b.String()
|
|
||||||
return e.ErrorNode.Error(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response implements the ResponseError interface's method to return the HTTP response.
|
|
||||||
func (e *responseError) Response() *http.Response {
|
|
||||||
return e.response
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC7807 PROBLEM ------------------------------------------------------------------------------------
|
|
||||||
// RFC7807Problem ... This type can be publicly embedded in another type that wants to add additional members.
|
|
||||||
/*type RFC7807Problem struct {
|
|
||||||
// Mandatory: A (relative) URI reference identifying the problem type (it MAY refer to human-readable documentation).
|
|
||||||
typeURI string // Should default to "about:blank"
|
|
||||||
// Optional: Short, human-readable summary (maybe localized).
|
|
||||||
title string
|
|
||||||
// Optional: HTTP status code generated by the origin server
|
|
||||||
status int
|
|
||||||
// Optional: Human-readable explanation for this problem occurance.
|
|
||||||
// Should help client correct the problem. Clients should NOT parse this string.
|
|
||||||
detail string
|
|
||||||
// Optional: A (relative) URI identifying this specific problem occurence (it may or may not be dereferenced).
|
|
||||||
instance string
|
|
||||||
}
|
|
||||||
// NewRFC7807Problem ...
|
|
||||||
func NewRFC7807Problem(typeURI string, status int, titleFormat string, a ...interface{}) error {
|
|
||||||
return &RFC7807Problem{
|
|
||||||
typeURI: typeURI,
|
|
||||||
status: status,
|
|
||||||
title: fmt.Sprintf(titleFormat, a...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Error returns the error information as a string.
|
|
||||||
func (e *RFC7807Problem) Error() string {
|
|
||||||
return e.title
|
|
||||||
}
|
|
||||||
// TypeURI ...
|
|
||||||
func (e *RFC7807Problem) TypeURI() string {
|
|
||||||
if e.typeURI == "" {
|
|
||||||
e.typeURI = "about:blank"
|
|
||||||
}
|
|
||||||
return e.typeURI
|
|
||||||
}
|
|
||||||
// Members ...
|
|
||||||
func (e *RFC7807Problem) Members() (status int, title, detail, instance string) {
|
|
||||||
return e.status, e.title, e.detail, e.instance
|
|
||||||
}*/
|
|
526
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_service.go
generated
vendored
526
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_service.go
generated
vendored
@ -1,526 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/xml"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// serviceClient is the client for the Service methods of the Azblob service.
|
|
||||||
type serviceClient struct {
|
|
||||||
managementClient
|
|
||||||
}
|
|
||||||
|
|
||||||
// newServiceClient creates an instance of the serviceClient client.
|
|
||||||
func newServiceClient(url url.URL, p pipeline.Pipeline) serviceClient {
|
|
||||||
return serviceClient{newManagementClient(url, p)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountInfo returns the sku name and account kind
|
|
||||||
func (client serviceClient) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) {
|
|
||||||
req, err := client.getAccountInfoPreparer()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getAccountInfoResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*ServiceGetAccountInfoResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAccountInfoPreparer prepares the GetAccountInfo request.
|
|
||||||
func (client serviceClient) getAccountInfoPreparer() (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
params.Set("restype", "account")
|
|
||||||
params.Set("comp", "properties")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAccountInfoResponder handles the response to the GetAccountInfo request.
|
|
||||||
func (client serviceClient) getAccountInfoResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &ServiceGetAccountInfoResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProperties gets the properties of a storage account's Blob service, including properties for Storage Analytics
|
|
||||||
// and CORS (Cross-Origin Resource Sharing) rules.
|
|
||||||
//
|
|
||||||
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) GetProperties(ctx context.Context, timeout *int32, requestID *string) (*StorageServiceProperties, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getPropertiesPreparer(timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPropertiesResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*StorageServiceProperties), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPropertiesPreparer prepares the GetProperties request.
|
|
||||||
func (client serviceClient) getPropertiesPreparer(timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("restype", "service")
|
|
||||||
params.Set("comp", "properties")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPropertiesResponder handles the response to the GetProperties request.
|
|
||||||
func (client serviceClient) getPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &StorageServiceProperties{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStatistics retrieves statistics related to replication for the Blob service. It is only available on the
|
|
||||||
// secondary location endpoint when read-access geo-redundant replication is enabled for the storage account.
|
|
||||||
//
|
|
||||||
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) GetStatistics(ctx context.Context, timeout *int32, requestID *string) (*StorageServiceStats, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getStatisticsPreparer(timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getStatisticsResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*StorageServiceStats), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getStatisticsPreparer prepares the GetStatistics request.
|
|
||||||
func (client serviceClient) getStatisticsPreparer(timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("restype", "service")
|
|
||||||
params.Set("comp", "stats")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getStatisticsResponder handles the response to the GetStatistics request.
|
|
||||||
func (client serviceClient) getStatisticsResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &StorageServiceStats{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserDelegationKey retrieves a user delegation key for the Blob service. This is only a valid operation when using
|
|
||||||
// bearer token authentication.
|
|
||||||
//
|
|
||||||
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) GetUserDelegationKey(ctx context.Context, keyInfo KeyInfo, timeout *int32, requestID *string) (*UserDelegationKey, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.getUserDelegationKeyPreparer(keyInfo, timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getUserDelegationKeyResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*UserDelegationKey), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUserDelegationKeyPreparer prepares the GetUserDelegationKey request.
|
|
||||||
func (client serviceClient) getUserDelegationKeyPreparer(keyInfo KeyInfo, timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("POST", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("restype", "service")
|
|
||||||
params.Set("comp", "userdelegationkey")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
b, err := xml.Marshal(keyInfo)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to marshal request body")
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/xml")
|
|
||||||
err = req.SetBody(bytes.NewReader(b))
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to set request body")
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUserDelegationKeyResponder handles the response to the GetUserDelegationKey request.
|
|
||||||
func (client serviceClient) getUserDelegationKeyResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &UserDelegationKey{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListContainersSegment the List Containers Segment operation returns a list of the containers under the specified
|
|
||||||
// account
|
|
||||||
//
|
|
||||||
// prefix is filters the results to return only containers whose name begins with the specified prefix. marker is a
|
|
||||||
// string value that identifies the portion of the list of containers to be returned with the next listing operation.
|
|
||||||
// The operation returns the NextMarker value within the response body if the listing operation did not return all
|
|
||||||
// containers remaining to be listed with the current page. The NextMarker value can be used as the value for the
|
|
||||||
// marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the
|
|
||||||
// client. maxresults is specifies the maximum number of containers to return. If the request does not specify
|
|
||||||
// maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the
|
|
||||||
// listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the
|
|
||||||
// remainder of the results. For this reason, it is possible that the service will return fewer results than specified
|
|
||||||
// by maxresults, or than the default of 5000. include is include this parameter to specify that the container's
|
|
||||||
// metadata be returned as part of the response body. timeout is the timeout parameter is expressed in seconds. For
|
|
||||||
// more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersSegmentResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: maxresults,
|
|
||||||
constraints: []constraint{{target: "maxresults", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.listContainersSegmentPreparer(prefix, marker, maxresults, include, timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.listContainersSegmentResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*ListContainersSegmentResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// listContainersSegmentPreparer prepares the ListContainersSegment request.
|
|
||||||
func (client serviceClient) listContainersSegmentPreparer(prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("GET", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if prefix != nil && len(*prefix) > 0 {
|
|
||||||
params.Set("prefix", *prefix)
|
|
||||||
}
|
|
||||||
if marker != nil && len(*marker) > 0 {
|
|
||||||
params.Set("marker", *marker)
|
|
||||||
}
|
|
||||||
if maxresults != nil {
|
|
||||||
params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10))
|
|
||||||
}
|
|
||||||
if include != ListContainersIncludeNone {
|
|
||||||
params.Set("include", string(include))
|
|
||||||
}
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "list")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// listContainersSegmentResponder handles the response to the ListContainersSegment request.
|
|
||||||
func (client serviceClient) listContainersSegmentResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := &ListContainersSegmentResponse{rawResponse: resp.Response()}
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
defer resp.Response().Body.Close()
|
|
||||||
b, err := ioutil.ReadAll(resp.Response().Body)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
if len(b) > 0 {
|
|
||||||
b = removeBOM(b)
|
|
||||||
err = xml.Unmarshal(b, result)
|
|
||||||
if err != nil {
|
|
||||||
return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetProperties sets properties for a storage account's Blob service endpoint, including properties for Storage
|
|
||||||
// Analytics and CORS (Cross-Origin Resource Sharing) rules
|
|
||||||
//
|
|
||||||
// storageServiceProperties is the StorageService properties. timeout is the timeout parameter is expressed in seconds.
|
|
||||||
// For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) SetProperties(ctx context.Context, storageServiceProperties StorageServiceProperties, timeout *int32, requestID *string) (*ServiceSetPropertiesResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: storageServiceProperties,
|
|
||||||
constraints: []constraint{{target: "storageServiceProperties.Logging", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy", name: null, rule: true,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy.Days", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
{target: "storageServiceProperties.HourMetrics", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy.Days", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
{target: "storageServiceProperties.MinuteMetrics", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy.Days", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
{target: "storageServiceProperties.DeleteRetentionPolicy", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.DeleteRetentionPolicy.Days", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "storageServiceProperties.DeleteRetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}},
|
|
||||||
}}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.setPropertiesPreparer(storageServiceProperties, timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setPropertiesResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*ServiceSetPropertiesResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// setPropertiesPreparer prepares the SetProperties request.
|
|
||||||
func (client serviceClient) setPropertiesPreparer(storageServiceProperties StorageServiceProperties, timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("PUT", client.url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("restype", "service")
|
|
||||||
params.Set("comp", "properties")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
b, err := xml.Marshal(storageServiceProperties)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to marshal request body")
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/xml")
|
|
||||||
err = req.SetBody(bytes.NewReader(b))
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to set request body")
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setPropertiesResponder handles the response to the SetProperties request.
|
|
||||||
func (client serviceClient) setPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK, http.StatusAccepted)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
io.Copy(ioutil.Discard, resp.Response().Body)
|
|
||||||
resp.Response().Body.Close()
|
|
||||||
return &ServiceSetPropertiesResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubmitBatch the Batch operation allows multiple API calls to be embedded into a single HTTP request.
|
|
||||||
//
|
|
||||||
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
|
|
||||||
// error.contentLength is the length of the request. multipartContentType is required. The value of this header must be
|
|
||||||
// multipart/mixed with a batch boundary. Example header value: multipart/mixed; boundary=batch_<GUID> timeout is the
|
|
||||||
// timeout parameter is expressed in seconds. For more information, see <a
|
|
||||||
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
|
|
||||||
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
|
|
||||||
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
|
|
||||||
func (client serviceClient) SubmitBatch(ctx context.Context, body io.ReadSeeker, contentLength int64, multipartContentType string, timeout *int32, requestID *string) (*SubmitBatchResponse, error) {
|
|
||||||
if err := validate([]validation{
|
|
||||||
{targetValue: body,
|
|
||||||
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
|
|
||||||
{targetValue: timeout,
|
|
||||||
constraints: []constraint{{target: "timeout", name: null, rule: false,
|
|
||||||
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req, err := client.submitBatchPreparer(body, contentLength, multipartContentType, timeout, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.submitBatchResponder}, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.(*SubmitBatchResponse), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// submitBatchPreparer prepares the SubmitBatch request.
|
|
||||||
func (client serviceClient) submitBatchPreparer(body io.ReadSeeker, contentLength int64, multipartContentType string, timeout *int32, requestID *string) (pipeline.Request, error) {
|
|
||||||
req, err := pipeline.NewRequest("POST", client.url, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, pipeline.NewError(err, "failed to create request")
|
|
||||||
}
|
|
||||||
params := req.URL.Query()
|
|
||||||
if timeout != nil {
|
|
||||||
params.Set("timeout", strconv.FormatInt(int64(*timeout), 10))
|
|
||||||
}
|
|
||||||
params.Set("comp", "batch")
|
|
||||||
req.URL.RawQuery = params.Encode()
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
|
|
||||||
req.Header.Set("Content-Type", multipartContentType)
|
|
||||||
req.Header.Set("x-ms-version", ServiceVersion)
|
|
||||||
if requestID != nil {
|
|
||||||
req.Header.Set("x-ms-client-request-id", *requestID)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// submitBatchResponder handles the response to the SubmitBatch request.
|
|
||||||
func (client serviceClient) submitBatchResponder(resp pipeline.Response) (pipeline.Response, error) {
|
|
||||||
err := validateResponse(resp, http.StatusOK)
|
|
||||||
if resp == nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &SubmitBatchResponse{rawResponse: resp.Response()}, err
|
|
||||||
}
|
|
367
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_validation.go
generated
vendored
367
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_validation.go
generated
vendored
@ -1,367 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Constraint stores constraint name, target field name
|
|
||||||
// Rule and chain validations.
|
|
||||||
type constraint struct {
|
|
||||||
// Target field name for validation.
|
|
||||||
target string
|
|
||||||
|
|
||||||
// Constraint name e.g. minLength, MaxLength, Pattern, etc.
|
|
||||||
name string
|
|
||||||
|
|
||||||
// Rule for constraint e.g. greater than 10, less than 5 etc.
|
|
||||||
rule interface{}
|
|
||||||
|
|
||||||
// Chain validations for struct type
|
|
||||||
chain []constraint
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validation stores parameter-wise validation.
|
|
||||||
type validation struct {
|
|
||||||
targetValue interface{}
|
|
||||||
constraints []constraint
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constraint list
|
|
||||||
const (
|
|
||||||
empty = "Empty"
|
|
||||||
null = "Null"
|
|
||||||
readOnly = "ReadOnly"
|
|
||||||
pattern = "Pattern"
|
|
||||||
maxLength = "MaxLength"
|
|
||||||
minLength = "MinLength"
|
|
||||||
maxItems = "MaxItems"
|
|
||||||
minItems = "MinItems"
|
|
||||||
multipleOf = "MultipleOf"
|
|
||||||
uniqueItems = "UniqueItems"
|
|
||||||
inclusiveMaximum = "InclusiveMaximum"
|
|
||||||
exclusiveMaximum = "ExclusiveMaximum"
|
|
||||||
exclusiveMinimum = "ExclusiveMinimum"
|
|
||||||
inclusiveMinimum = "InclusiveMinimum"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate method validates constraints on parameter
|
|
||||||
// passed in validation array.
|
|
||||||
func validate(m []validation) error {
|
|
||||||
for _, item := range m {
|
|
||||||
v := reflect.ValueOf(item.targetValue)
|
|
||||||
for _, constraint := range item.constraints {
|
|
||||||
var err error
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Ptr:
|
|
||||||
err = validatePtr(v, constraint)
|
|
||||||
case reflect.String:
|
|
||||||
err = validateString(v, constraint)
|
|
||||||
case reflect.Struct:
|
|
||||||
err = validateStruct(v, constraint)
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
err = validateInt(v, constraint)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
err = validateFloat(v, constraint)
|
|
||||||
case reflect.Array, reflect.Slice, reflect.Map:
|
|
||||||
err = validateArrayMap(v, constraint)
|
|
||||||
default:
|
|
||||||
err = createError(v, constraint, fmt.Sprintf("unknown type %v", v.Kind()))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateStruct(x reflect.Value, v constraint, name ...string) error {
|
|
||||||
//Get field name from target name which is in format a.b.c
|
|
||||||
s := strings.Split(v.target, ".")
|
|
||||||
f := x.FieldByName(s[len(s)-1])
|
|
||||||
if isZero(f) {
|
|
||||||
return createError(x, v, fmt.Sprintf("field %q doesn't exist", v.target))
|
|
||||||
}
|
|
||||||
err := validate([]validation{
|
|
||||||
{
|
|
||||||
targetValue: getInterfaceValue(f),
|
|
||||||
constraints: []constraint{v},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func validatePtr(x reflect.Value, v constraint) error {
|
|
||||||
if v.name == readOnly {
|
|
||||||
if !x.IsNil() {
|
|
||||||
return createError(x.Elem(), v, "readonly parameter; must send as nil or empty in request")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if x.IsNil() {
|
|
||||||
return checkNil(x, v)
|
|
||||||
}
|
|
||||||
if v.chain != nil {
|
|
||||||
return validate([]validation{
|
|
||||||
{
|
|
||||||
targetValue: getInterfaceValue(x.Elem()),
|
|
||||||
constraints: v.chain,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateInt(x reflect.Value, v constraint) error {
|
|
||||||
i := x.Int()
|
|
||||||
r, ok := v.rule.(int)
|
|
||||||
if !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
switch v.name {
|
|
||||||
case multipleOf:
|
|
||||||
if i%int64(r) != 0 {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be a multiple of %v", r))
|
|
||||||
}
|
|
||||||
case exclusiveMinimum:
|
|
||||||
if i <= int64(r) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be greater than %v", r))
|
|
||||||
}
|
|
||||||
case exclusiveMaximum:
|
|
||||||
if i >= int64(r) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be less than %v", r))
|
|
||||||
}
|
|
||||||
case inclusiveMinimum:
|
|
||||||
if i < int64(r) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r))
|
|
||||||
}
|
|
||||||
case inclusiveMaximum:
|
|
||||||
if i > int64(r) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return createError(x, v, fmt.Sprintf("constraint %v is not applicable for type integer", v.name))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateFloat(x reflect.Value, v constraint) error {
|
|
||||||
f := x.Float()
|
|
||||||
r, ok := v.rule.(float64)
|
|
||||||
if !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be float value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
switch v.name {
|
|
||||||
case exclusiveMinimum:
|
|
||||||
if f <= r {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be greater than %v", r))
|
|
||||||
}
|
|
||||||
case exclusiveMaximum:
|
|
||||||
if f >= r {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be less than %v", r))
|
|
||||||
}
|
|
||||||
case inclusiveMinimum:
|
|
||||||
if f < r {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r))
|
|
||||||
}
|
|
||||||
case inclusiveMaximum:
|
|
||||||
if f > r {
|
|
||||||
return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return createError(x, v, fmt.Sprintf("constraint %s is not applicable for type float", v.name))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateString(x reflect.Value, v constraint) error {
|
|
||||||
s := x.String()
|
|
||||||
switch v.name {
|
|
||||||
case empty:
|
|
||||||
if len(s) == 0 {
|
|
||||||
return checkEmpty(x, v)
|
|
||||||
}
|
|
||||||
case pattern:
|
|
||||||
reg, err := regexp.Compile(v.rule.(string))
|
|
||||||
if err != nil {
|
|
||||||
return createError(x, v, err.Error())
|
|
||||||
}
|
|
||||||
if !reg.MatchString(s) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value doesn't match pattern %v", v.rule))
|
|
||||||
}
|
|
||||||
case maxLength:
|
|
||||||
if _, ok := v.rule.(int); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if len(s) > v.rule.(int) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value length must be less than %v", v.rule))
|
|
||||||
}
|
|
||||||
case minLength:
|
|
||||||
if _, ok := v.rule.(int); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if len(s) < v.rule.(int) {
|
|
||||||
return createError(x, v, fmt.Sprintf("value length must be greater than %v", v.rule))
|
|
||||||
}
|
|
||||||
case readOnly:
|
|
||||||
if len(s) > 0 {
|
|
||||||
return createError(reflect.ValueOf(s), v, "readonly parameter; must send as nil or empty in request")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return createError(x, v, fmt.Sprintf("constraint %s is not applicable to string type", v.name))
|
|
||||||
}
|
|
||||||
if v.chain != nil {
|
|
||||||
return validate([]validation{
|
|
||||||
{
|
|
||||||
targetValue: getInterfaceValue(x),
|
|
||||||
constraints: v.chain,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateArrayMap(x reflect.Value, v constraint) error {
|
|
||||||
switch v.name {
|
|
||||||
case null:
|
|
||||||
if x.IsNil() {
|
|
||||||
return checkNil(x, v)
|
|
||||||
}
|
|
||||||
case empty:
|
|
||||||
if x.IsNil() || x.Len() == 0 {
|
|
||||||
return checkEmpty(x, v)
|
|
||||||
}
|
|
||||||
case maxItems:
|
|
||||||
if _, ok := v.rule.(int); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if x.Len() > v.rule.(int) {
|
|
||||||
return createError(x, v, fmt.Sprintf("maximum item limit is %v; got: %v", v.rule, x.Len()))
|
|
||||||
}
|
|
||||||
case minItems:
|
|
||||||
if _, ok := v.rule.(int); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if x.Len() < v.rule.(int) {
|
|
||||||
return createError(x, v, fmt.Sprintf("minimum item limit is %v; got: %v", v.rule, x.Len()))
|
|
||||||
}
|
|
||||||
case uniqueItems:
|
|
||||||
if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
|
|
||||||
if !checkForUniqueInArray(x) {
|
|
||||||
return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.target, x))
|
|
||||||
}
|
|
||||||
} else if x.Kind() == reflect.Map {
|
|
||||||
if !checkForUniqueInMap(x) {
|
|
||||||
return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.target, x))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return createError(x, v, fmt.Sprintf("type must be array, slice or map for constraint %v; got: %v", v.name, x.Kind()))
|
|
||||||
}
|
|
||||||
case readOnly:
|
|
||||||
if x.Len() != 0 {
|
|
||||||
return createError(x, v, "readonly parameter; must send as nil or empty in request")
|
|
||||||
}
|
|
||||||
case pattern:
|
|
||||||
reg, err := regexp.Compile(v.rule.(string))
|
|
||||||
if err != nil {
|
|
||||||
return createError(x, v, err.Error())
|
|
||||||
}
|
|
||||||
keys := x.MapKeys()
|
|
||||||
for _, k := range keys {
|
|
||||||
if !reg.MatchString(k.String()) {
|
|
||||||
return createError(k, v, fmt.Sprintf("map key doesn't match pattern %v", v.rule))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return createError(x, v, fmt.Sprintf("constraint %v is not applicable to array, slice and map type", v.name))
|
|
||||||
}
|
|
||||||
if v.chain != nil {
|
|
||||||
return validate([]validation{
|
|
||||||
{
|
|
||||||
targetValue: getInterfaceValue(x),
|
|
||||||
constraints: v.chain,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNil(x reflect.Value, v constraint) error {
|
|
||||||
if _, ok := v.rule.(bool); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if v.rule.(bool) {
|
|
||||||
return createError(x, v, "value can not be null; required parameter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkEmpty(x reflect.Value, v constraint) error {
|
|
||||||
if _, ok := v.rule.(bool); !ok {
|
|
||||||
return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.name, v.rule))
|
|
||||||
}
|
|
||||||
if v.rule.(bool) {
|
|
||||||
return createError(x, v, "value can not be null or empty; required parameter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkForUniqueInArray(x reflect.Value) bool {
|
|
||||||
if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
arrOfInterface := make([]interface{}, x.Len())
|
|
||||||
for i := 0; i < x.Len(); i++ {
|
|
||||||
arrOfInterface[i] = x.Index(i).Interface()
|
|
||||||
}
|
|
||||||
m := make(map[interface{}]bool)
|
|
||||||
for _, val := range arrOfInterface {
|
|
||||||
if m[val] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m[val] = true
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkForUniqueInMap(x reflect.Value) bool {
|
|
||||||
if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
mapOfInterface := make(map[interface{}]interface{}, x.Len())
|
|
||||||
keys := x.MapKeys()
|
|
||||||
for _, k := range keys {
|
|
||||||
mapOfInterface[k.Interface()] = x.MapIndex(k).Interface()
|
|
||||||
}
|
|
||||||
m := make(map[interface{}]bool)
|
|
||||||
for _, val := range mapOfInterface {
|
|
||||||
if m[val] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m[val] = true
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInterfaceValue(x reflect.Value) interface{} {
|
|
||||||
if x.Kind() == reflect.Invalid {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return x.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
func isZero(x interface{}) bool {
|
|
||||||
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createError(x reflect.Value, v constraint, message string) error {
|
|
||||||
return pipeline.NewError(nil, fmt.Sprintf("validation failed: parameter=%s constraint=%s value=%#v details: %s",
|
|
||||||
v.target, v.name, getInterfaceValue(x), message))
|
|
||||||
}
|
|
14
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_version.go
generated
vendored
14
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_generated_version.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
|
||||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
||||||
|
|
||||||
// UserAgent returns the UserAgent string to use when sending http.Requests.
|
|
||||||
func UserAgent() string {
|
|
||||||
return "Azure-SDK-For-Go/0.0.0 azblob/2019-02-02"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version returns the semantic version (see http://semver.org) of the client.
|
|
||||||
func Version() string {
|
|
||||||
return "0.0.0"
|
|
||||||
}
|
|
242
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_response_helpers.go
generated
vendored
242
vendor/github.com/Azure/azure-storage-blob-go/azblob/zz_response_helpers.go
generated
vendored
@ -1,242 +0,0 @@
|
|||||||
package azblob
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BlobHTTPHeaders contains read/writeable blob properties.
|
|
||||||
type BlobHTTPHeaders struct {
|
|
||||||
ContentType string
|
|
||||||
ContentMD5 []byte
|
|
||||||
ContentEncoding string
|
|
||||||
ContentLanguage string
|
|
||||||
ContentDisposition string
|
|
||||||
CacheControl string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHTTPHeaders returns the user-modifiable properties for this blob.
|
|
||||||
func (bgpr BlobGetPropertiesResponse) NewHTTPHeaders() BlobHTTPHeaders {
|
|
||||||
return BlobHTTPHeaders{
|
|
||||||
ContentType: bgpr.ContentType(),
|
|
||||||
ContentEncoding: bgpr.ContentEncoding(),
|
|
||||||
ContentLanguage: bgpr.ContentLanguage(),
|
|
||||||
ContentDisposition: bgpr.ContentDisposition(),
|
|
||||||
CacheControl: bgpr.CacheControl(),
|
|
||||||
ContentMD5: bgpr.ContentMD5(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// NewHTTPHeaders returns the user-modifiable properties for this blob.
|
|
||||||
func (dr downloadResponse) NewHTTPHeaders() BlobHTTPHeaders {
|
|
||||||
return BlobHTTPHeaders{
|
|
||||||
ContentType: dr.ContentType(),
|
|
||||||
ContentEncoding: dr.ContentEncoding(),
|
|
||||||
ContentLanguage: dr.ContentLanguage(),
|
|
||||||
ContentDisposition: dr.ContentDisposition(),
|
|
||||||
CacheControl: dr.CacheControl(),
|
|
||||||
ContentMD5: dr.ContentMD5(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// DownloadResponse wraps AutoRest generated DownloadResponse and helps to provide info for retry.
|
|
||||||
type DownloadResponse struct {
|
|
||||||
r *downloadResponse
|
|
||||||
ctx context.Context
|
|
||||||
b BlobURL
|
|
||||||
getInfo HTTPGetterInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Body constructs new RetryReader stream for reading data. If a connection failes
|
|
||||||
// while reading, it will make additional requests to reestablish a connection and
|
|
||||||
// continue reading. Specifying a RetryReaderOption's with MaxRetryRequests set to 0
|
|
||||||
// (the default), returns the original response body and no retries will be performed.
|
|
||||||
func (r *DownloadResponse) Body(o RetryReaderOptions) io.ReadCloser {
|
|
||||||
if o.MaxRetryRequests == 0 { // No additional retries
|
|
||||||
return r.Response().Body
|
|
||||||
}
|
|
||||||
return NewRetryReader(r.ctx, r.Response(), r.getInfo, o,
|
|
||||||
func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) {
|
|
||||||
resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count,
|
|
||||||
BlobAccessConditions{
|
|
||||||
ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: getInfo.ETag},
|
|
||||||
},
|
|
||||||
false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Response(), err
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response returns the raw HTTP response object.
|
|
||||||
func (r DownloadResponse) Response() *http.Response {
|
|
||||||
return r.r.Response()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHTTPHeaders returns the user-modifiable properties for this blob.
|
|
||||||
func (r DownloadResponse) NewHTTPHeaders() BlobHTTPHeaders {
|
|
||||||
return r.r.NewHTTPHeaders()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobContentMD5 returns the value for header x-ms-blob-content-md5.
|
|
||||||
func (r DownloadResponse) BlobContentMD5() []byte {
|
|
||||||
return r.r.BlobContentMD5()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentMD5 returns the value for header Content-MD5.
|
|
||||||
func (r DownloadResponse) ContentMD5() []byte {
|
|
||||||
return r.r.ContentMD5()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusCode returns the HTTP status code of the response, e.g. 200.
|
|
||||||
func (r DownloadResponse) StatusCode() int {
|
|
||||||
return r.r.StatusCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status returns the HTTP status message of the response, e.g. "200 OK".
|
|
||||||
func (r DownloadResponse) Status() string {
|
|
||||||
return r.r.Status()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcceptRanges returns the value for header Accept-Ranges.
|
|
||||||
func (r DownloadResponse) AcceptRanges() string {
|
|
||||||
return r.r.AcceptRanges()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobCommittedBlockCount returns the value for header x-ms-blob-committed-block-count.
|
|
||||||
func (r DownloadResponse) BlobCommittedBlockCount() int32 {
|
|
||||||
return r.r.BlobCommittedBlockCount()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number.
|
|
||||||
func (r DownloadResponse) BlobSequenceNumber() int64 {
|
|
||||||
return r.r.BlobSequenceNumber()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlobType returns the value for header x-ms-blob-type.
|
|
||||||
func (r DownloadResponse) BlobType() BlobType {
|
|
||||||
return r.r.BlobType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheControl returns the value for header Cache-Control.
|
|
||||||
func (r DownloadResponse) CacheControl() string {
|
|
||||||
return r.r.CacheControl()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentDisposition returns the value for header Content-Disposition.
|
|
||||||
func (r DownloadResponse) ContentDisposition() string {
|
|
||||||
return r.r.ContentDisposition()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentEncoding returns the value for header Content-Encoding.
|
|
||||||
func (r DownloadResponse) ContentEncoding() string {
|
|
||||||
return r.r.ContentEncoding()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentLanguage returns the value for header Content-Language.
|
|
||||||
func (r DownloadResponse) ContentLanguage() string {
|
|
||||||
return r.r.ContentLanguage()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentLength returns the value for header Content-Length.
|
|
||||||
func (r DownloadResponse) ContentLength() int64 {
|
|
||||||
return r.r.ContentLength()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentRange returns the value for header Content-Range.
|
|
||||||
func (r DownloadResponse) ContentRange() string {
|
|
||||||
return r.r.ContentRange()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContentType returns the value for header Content-Type.
|
|
||||||
func (r DownloadResponse) ContentType() string {
|
|
||||||
return r.r.ContentType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyCompletionTime returns the value for header x-ms-copy-completion-time.
|
|
||||||
func (r DownloadResponse) CopyCompletionTime() time.Time {
|
|
||||||
return r.r.CopyCompletionTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyID returns the value for header x-ms-copy-id.
|
|
||||||
func (r DownloadResponse) CopyID() string {
|
|
||||||
return r.r.CopyID()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyProgress returns the value for header x-ms-copy-progress.
|
|
||||||
func (r DownloadResponse) CopyProgress() string {
|
|
||||||
return r.r.CopyProgress()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopySource returns the value for header x-ms-copy-source.
|
|
||||||
func (r DownloadResponse) CopySource() string {
|
|
||||||
return r.r.CopySource()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyStatus returns the value for header x-ms-copy-status.
|
|
||||||
func (r DownloadResponse) CopyStatus() CopyStatusType {
|
|
||||||
return r.r.CopyStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyStatusDescription returns the value for header x-ms-copy-status-description.
|
|
||||||
func (r DownloadResponse) CopyStatusDescription() string {
|
|
||||||
return r.r.CopyStatusDescription()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date returns the value for header Date.
|
|
||||||
func (r DownloadResponse) Date() time.Time {
|
|
||||||
return r.r.Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ETag returns the value for header ETag.
|
|
||||||
func (r DownloadResponse) ETag() ETag {
|
|
||||||
return r.r.ETag()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsServerEncrypted returns the value for header x-ms-server-encrypted.
|
|
||||||
func (r DownloadResponse) IsServerEncrypted() string {
|
|
||||||
return r.r.IsServerEncrypted()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LastModified returns the value for header Last-Modified.
|
|
||||||
func (r DownloadResponse) LastModified() time.Time {
|
|
||||||
return r.r.LastModified()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaseDuration returns the value for header x-ms-lease-duration.
|
|
||||||
func (r DownloadResponse) LeaseDuration() LeaseDurationType {
|
|
||||||
return r.r.LeaseDuration()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaseState returns the value for header x-ms-lease-state.
|
|
||||||
func (r DownloadResponse) LeaseState() LeaseStateType {
|
|
||||||
return r.r.LeaseState()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaseStatus returns the value for header x-ms-lease-status.
|
|
||||||
func (r DownloadResponse) LeaseStatus() LeaseStatusType {
|
|
||||||
return r.r.LeaseStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestID returns the value for header x-ms-request-id.
|
|
||||||
func (r DownloadResponse) RequestID() string {
|
|
||||||
return r.r.RequestID()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version returns the value for header x-ms-version.
|
|
||||||
func (r DownloadResponse) Version() string {
|
|
||||||
return r.r.Version()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMetadata returns user-defined key/value pairs.
|
|
||||||
func (r DownloadResponse) NewMetadata() Metadata {
|
|
||||||
return r.r.NewMetadata()
|
|
||||||
}
|
|
3
vendor/github.com/Unknwon/goconfig/.gitignore
generated
vendored
3
vendor/github.com/Unknwon/goconfig/.gitignore
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
*.iml
|
|
||||||
.idea
|
|
191
vendor/github.com/Unknwon/goconfig/LICENSE
generated
vendored
191
vendor/github.com/Unknwon/goconfig/LICENSE
generated
vendored
@ -1,191 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and
|
|
||||||
distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
|
||||||
owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
|
||||||
that control, are controlled by, or are under common control with that entity.
|
|
||||||
For the purposes of this definition, "control" means (i) the power, direct or
|
|
||||||
indirect, to cause the direction or management of such entity, whether by
|
|
||||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
|
||||||
permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications, including
|
|
||||||
but not limited to software source code, documentation source, and configuration
|
|
||||||
files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or
|
|
||||||
translation of a Source form, including but not limited to compiled object code,
|
|
||||||
generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
|
||||||
available under the License, as indicated by a copyright notice that is included
|
|
||||||
in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
|
||||||
is based on (or derived from) the Work and for which the editorial revisions,
|
|
||||||
annotations, elaborations, or other modifications represent, as a whole, an
|
|
||||||
original work of authorship. For the purposes of this License, Derivative Works
|
|
||||||
shall not include works that remain separable from, or merely link (or bind by
|
|
||||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including the original version
|
|
||||||
of the Work and any modifications or additions to that Work or Derivative Works
|
|
||||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
|
||||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
|
||||||
on behalf of the copyright owner. For the purposes of this definition,
|
|
||||||
"submitted" means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems, and
|
|
||||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
|
||||||
the purpose of discussing and improving the Work, but excluding communication
|
|
||||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
|
||||||
owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
|
||||||
of whom a Contribution has been received by Licensor and subsequently
|
|
||||||
incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
|
||||||
Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable (except as stated in this section) patent license to make, have
|
|
||||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
|
||||||
such license applies only to those patent claims licensable by such Contributor
|
|
||||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
|
||||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
|
||||||
submitted. If You institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
|
||||||
Contribution incorporated within the Work constitutes direct or contributory
|
|
||||||
patent infringement, then any patent licenses granted to You under this License
|
|
||||||
for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution.
|
|
||||||
|
|
||||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
|
||||||
in any medium, with or without modifications, and in Source or Object form,
|
|
||||||
provided that You meet the following conditions:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of
|
|
||||||
this License; and
|
|
||||||
You must cause any modified files to carry prominent notices stating that You
|
|
||||||
changed the files; and
|
|
||||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
|
||||||
all copyright, patent, trademark, and attribution notices from the Source form
|
|
||||||
of the Work, excluding those notices that do not pertain to any part of the
|
|
||||||
Derivative Works; and
|
|
||||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
|
||||||
Derivative Works that You distribute must include a readable copy of the
|
|
||||||
attribution notices contained within such NOTICE file, excluding those notices
|
|
||||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
|
||||||
following places: within a NOTICE text file distributed as part of the
|
|
||||||
Derivative Works; within the Source form or documentation, if provided along
|
|
||||||
with the Derivative Works; or, within a display generated by the Derivative
|
|
||||||
Works, if and wherever such third-party notices normally appear. The contents of
|
|
||||||
the NOTICE file are for informational purposes only and do not modify the
|
|
||||||
License. You may add Your own attribution notices within Derivative Works that
|
|
||||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
|
||||||
provided that such additional attribution notices cannot be construed as
|
|
||||||
modifying the License.
|
|
||||||
You may add Your own copyright statement to Your modifications and may provide
|
|
||||||
additional or different license terms and conditions for use, reproduction, or
|
|
||||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
|
||||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
|
||||||
with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions.
|
|
||||||
|
|
||||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
|
||||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
|
||||||
conditions of this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
|
||||||
any separate license agreement you may have executed with Licensor regarding
|
|
||||||
such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks.
|
|
||||||
|
|
||||||
This License does not grant permission to use the trade names, trademarks,
|
|
||||||
service marks, or product names of the Licensor, except as required for
|
|
||||||
reasonable and customary use in describing the origin of the Work and
|
|
||||||
reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
|
||||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
|
||||||
including, without limitation, any warranties or conditions of TITLE,
|
|
||||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
|
||||||
solely responsible for determining the appropriateness of using or
|
|
||||||
redistributing the Work and assume any risks associated with Your exercise of
|
|
||||||
permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability.
|
|
||||||
|
|
||||||
In no event and under no legal theory, whether in tort (including negligence),
|
|
||||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
|
||||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special, incidental,
|
|
||||||
or consequential damages of any character arising as a result of this License or
|
|
||||||
out of the use or inability to use the Work (including but not limited to
|
|
||||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
|
||||||
any and all other commercial damages or losses), even if such Contributor has
|
|
||||||
been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability.
|
|
||||||
|
|
||||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
|
||||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
|
||||||
other liability obligations and/or rights consistent with this License. However,
|
|
||||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
|
||||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
|
||||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason of your
|
|
||||||
accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following boilerplate
|
|
||||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
|
||||||
identifying information. (Don't include the brackets!) The text should be
|
|
||||||
enclosed in the appropriate comment syntax for the file format. We also
|
|
||||||
recommend that a file or class name and description of purpose be included on
|
|
||||||
the same "printed page" as the copyright notice for easier identification within
|
|
||||||
third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
68
vendor/github.com/Unknwon/goconfig/README.md
generated
vendored
68
vendor/github.com/Unknwon/goconfig/README.md
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
goconfig [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/goconfig)
|
|
||||||
========
|
|
||||||
|
|
||||||
[中文文档](README_ZH.md)
|
|
||||||
|
|
||||||
**IMPORTANT**
|
|
||||||
|
|
||||||
- This library is under bug fix only mode, which means no more features will be added.
|
|
||||||
- I'm continuing working on better Go code with a different library: [ini](https://github.com/go-ini/ini).
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
Package goconfig is a easy-use, comments-support configuration file parser for the Go Programming Language, which provides a structure similar to what you would find on Microsoft Windows INI files.
|
|
||||||
|
|
||||||
The configuration file consists of sections, led by a `[section]` header and followed by `name:value` or `name=value` entries. Note that leading whitespace is removed from values. The optional values can contain format strings which refer to other values in the same section, or values in a special DEFAULT section. Comments are indicated by ";" or "#"; comments may begin anywhere on a single line.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- It simplified operation processes, easy to use and undersatnd; therefore, there are less chances to have errors.
|
|
||||||
- It uses exactly the same way to access a configuration file as you use Windows APIs, so you don't need to change your code style.
|
|
||||||
- It supports read recursion sections.
|
|
||||||
- It supports auto increment of key.
|
|
||||||
- It supports **READ** and **WRITE** configuration file with comments each section or key which all the other parsers don't support!!!!!!!
|
|
||||||
- It supports get value through type bool, float64, int, int64 and string, methods that start with "Must" means ignore errors and get zero-value if error occurs, or you can specify a default value.
|
|
||||||
- It's able to load multiple files to overwrite key values.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
go get github.com/unknwon/goconfig
|
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
[Go Walker](http://gowalker.org/github.com/unknwon/goconfig).
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
Please see [conf.ini](testdata/conf.ini) as an example.
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
- Function `LoadConfigFile` load file(s) depends on your situation, and return a variable with type `ConfigFile`.
|
|
||||||
- `GetValue` gives basic functionality of getting a value of given section and key.
|
|
||||||
- Methods like `Bool`, `Int`, `Int64` return corresponding type of values.
|
|
||||||
- Methods start with `Must` return corresponding type of values and returns zero-value of given type if something goes wrong.
|
|
||||||
- `SetValue` sets value to given section and key, and inserts somewhere if it does not exist.
|
|
||||||
- `DeleteKey` deletes by given section and key.
|
|
||||||
- Finally, `SaveConfigFile` saves your configuration to local file system.
|
|
||||||
- Use method `Reload` in case someone else modified your file(s).
|
|
||||||
- Methods contains `Comment` help you manipulate comments.
|
|
||||||
- `LoadFromReader` allows loading data without an intermediate file.
|
|
||||||
- `SaveConfigData` added, which writes configuration to an arbitrary writer.
|
|
||||||
- `ReloadData` allows to reload data from memory.
|
|
||||||
|
|
||||||
Note that you cannot mix in-memory configuration with on-disk configuration.
|
|
||||||
|
|
||||||
## More Information
|
|
||||||
|
|
||||||
- All characters are CASE SENSITIVE, BE CAREFUL!
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- [goconf](http://code.google.com/p/goconf/)
|
|
||||||
- [robfig/config](https://github.com/robfig/config)
|
|
||||||
- [Delete an item from a slice](https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/lYz8ftASMQ0)
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user