Update Swift bindings
Signed-off-by: Sylvain Baubeau <sbaubeau@redhat.com>
This commit is contained in:
parent
326ec6c121
commit
7759153f2f
7 changed files with 137 additions and 18 deletions
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
|
@ -122,7 +122,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/ncw/swift",
|
||||
"Rev": "ca8cbbde50d4e12dd8ad70b1bd66589ae98efc5c"
|
||||
"Rev": "c54732e87b0b283d1baf0a18db689d0aea460ba3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/noahdesu/go-ceph/rados",
|
||||
|
|
2
Godeps/_workspace/src/github.com/ncw/swift/README.md
generated
vendored
2
Godeps/_workspace/src/github.com/ncw/swift/README.md
generated
vendored
|
@ -132,3 +132,5 @@ Contributors
|
|||
- Dai HaoJun <haojun.dai@hp.com>
|
||||
- Hua Wang <wanghua.humble@gmail.com>
|
||||
- Fabian Ruff <fabian@progra.de>
|
||||
- Arturo Reuschenbach Puncernau <reuschenbach@gmail.com>
|
||||
- Petr Kotek <petr.kotek@bigcommerce.com>
|
||||
|
|
1
Godeps/_workspace/src/github.com/ncw/swift/auth.go
generated
vendored
1
Godeps/_workspace/src/github.com/ncw/swift/auth.go
generated
vendored
|
@ -156,6 +156,7 @@ func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
|
|||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
|
|
1
Godeps/_workspace/src/github.com/ncw/swift/auth_v3.go
generated
vendored
1
Godeps/_workspace/src/github.com/ncw/swift/auth_v3.go
generated
vendored
|
@ -177,6 +177,7 @@ func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
|
|||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
|
|
50
Godeps/_workspace/src/github.com/ncw/swift/swift.go
generated
vendored
50
Godeps/_workspace/src/github.com/ncw/swift/swift.go
generated
vendored
|
@ -392,6 +392,26 @@ func (c *Connection) authenticated() bool {
|
|||
return c.StorageUrl != "" && c.AuthToken != ""
|
||||
}
|
||||
|
||||
// SwiftInfo contains the JSON object returned by Swift when the /info
|
||||
// route is queried. The object contains, among others, the Swift version,
|
||||
// the enabled middlewares and their configuration
|
||||
type SwiftInfo map[string]interface{}
|
||||
|
||||
// Discover Swift configuration by doing a request against /info
|
||||
func (c *Connection) QueryInfo() (infos SwiftInfo, err error) {
|
||||
infoUrl, err := url.Parse(c.StorageUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
infoUrl.Path = path.Join(infoUrl.Path, "..", "..", "info")
|
||||
resp, err := http.Get(infoUrl.String())
|
||||
if err == nil {
|
||||
err = readJson(resp, &infos)
|
||||
return infos, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// RequestOpts contains parameters for Connection.storage.
|
||||
type RequestOpts struct {
|
||||
Container string
|
||||
|
@ -418,6 +438,10 @@ type RequestOpts struct {
|
|||
// resp.Body.Close() must be called on it, unless noResponse is set in
|
||||
// which case the body will be closed in this function
|
||||
//
|
||||
// If "Content-Length" is set in p.Headers it will be used - this can
|
||||
// be used to override the default chunked transfer encoding for
|
||||
// uploads.
|
||||
//
|
||||
// This will Authenticate if necessary, and re-authenticate if it
|
||||
// receives a 401 error which means the token has expired
|
||||
//
|
||||
|
@ -433,8 +457,9 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
|
|||
var req *http.Request
|
||||
for {
|
||||
var authToken string
|
||||
targetUrl, authToken, err = c.getUrlAndAuthToken(targetUrl, p.OnReAuth)
|
||||
|
||||
if targetUrl, authToken, err = c.getUrlAndAuthToken(targetUrl, p.OnReAuth); err != nil {
|
||||
return //authentication failure
|
||||
}
|
||||
var URL *url.URL
|
||||
URL, err = url.Parse(targetUrl)
|
||||
if err != nil {
|
||||
|
@ -460,18 +485,27 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
|
|||
}
|
||||
if p.Headers != nil {
|
||||
for k, v := range p.Headers {
|
||||
// Set ContentLength in req if the user passed it in in the headers
|
||||
if k == "Content-Length" {
|
||||
contentLength, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid %q header %q: %v", k, v, err)
|
||||
}
|
||||
req.ContentLength = contentLength
|
||||
} else {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
}
|
||||
req.Header.Add("User-Agent", DefaultUserAgent)
|
||||
}
|
||||
req.Header.Add("User-Agent", c.UserAgent)
|
||||
req.Header.Add("X-Auth-Token", authToken)
|
||||
resp, err = c.doTimeoutRequest(timer, req)
|
||||
if err != nil {
|
||||
if p.Operation == "HEAD" || p.Operation == "GET" {
|
||||
if (p.Operation == "HEAD" || p.Operation == "GET") && retries > 0 {
|
||||
retries--
|
||||
continue
|
||||
}
|
||||
return
|
||||
return nil, nil, err
|
||||
}
|
||||
// Check to see if token has expired
|
||||
if resp.StatusCode == 401 && retries > 0 {
|
||||
|
@ -566,7 +600,8 @@ func readJson(resp *http.Response, result interface{}) (err error) {
|
|||
// ContainersOpts is options for Containers() and ContainerNames()
|
||||
type ContainersOpts struct {
|
||||
Limit int // For an integer value n, limits the number of results to at most n values.
|
||||
Marker string // Given a string value x, return object names greater in value than the specified marker.
|
||||
Prefix string // Given a string value x, return container names matching the specified prefix.
|
||||
Marker string // Given a string value x, return container names greater in value than the specified marker.
|
||||
EndMarker string // Given a string value x, return container names less in value than the specified marker.
|
||||
Headers Headers // Any additional HTTP headers - can be nil
|
||||
}
|
||||
|
@ -579,6 +614,9 @@ func (opts *ContainersOpts) parse() (url.Values, Headers) {
|
|||
if opts.Limit > 0 {
|
||||
v.Set("limit", strconv.Itoa(opts.Limit))
|
||||
}
|
||||
if opts.Prefix != "" {
|
||||
v.Set("prefix", opts.Prefix)
|
||||
}
|
||||
if opts.Marker != "" {
|
||||
v.Set("marker", opts.Marker)
|
||||
}
|
||||
|
|
59
Godeps/_workspace/src/github.com/ncw/swift/swift_test.go
generated
vendored
59
Godeps/_workspace/src/github.com/ncw/swift/swift_test.go
generated
vendored
|
@ -65,6 +65,7 @@ func makeConnection() (*swift.Connection, error) {
|
|||
UserName := os.Getenv("SWIFT_API_USER")
|
||||
ApiKey := os.Getenv("SWIFT_API_KEY")
|
||||
AuthUrl := os.Getenv("SWIFT_AUTH_URL")
|
||||
Region := os.Getenv("SWIFT_REGION_NAME")
|
||||
|
||||
Insecure := os.Getenv("SWIFT_AUTH_INSECURE")
|
||||
ConnectionChannelTimeout := os.Getenv("SWIFT_CONNECTION_CHANNEL_TIMEOUT")
|
||||
|
@ -96,6 +97,7 @@ func makeConnection() (*swift.Connection, error) {
|
|||
UserName: UserName,
|
||||
ApiKey: ApiKey,
|
||||
AuthUrl: AuthUrl,
|
||||
Region: Region,
|
||||
Transport: transport,
|
||||
ConnectTimeout: 60 * time.Second,
|
||||
Timeout: 60 * time.Second,
|
||||
|
@ -601,6 +603,45 @@ func TestObjectPutString(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestObjectPut(t *testing.T) {
|
||||
headers := swift.Headers{}
|
||||
|
||||
// Set content size incorrectly - should produce an error
|
||||
headers["Content-Length"] = strconv.FormatInt(CONTENT_SIZE-1, 10)
|
||||
contents := bytes.NewBufferString(CONTENTS)
|
||||
h, err := c.ObjectPut(CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
|
||||
if err == nil {
|
||||
t.Fatal("Expecting error but didn't get one")
|
||||
}
|
||||
|
||||
// Now set content size correctly
|
||||
contents = bytes.NewBufferString(CONTENTS)
|
||||
headers["Content-Length"] = strconv.FormatInt(CONTENT_SIZE, 10)
|
||||
h, err = c.ObjectPut(CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if h["Etag"] != CONTENT_MD5 {
|
||||
t.Errorf("Bad Etag want %q got %q", CONTENT_MD5, h["Etag"])
|
||||
}
|
||||
|
||||
// Fetch object info and compare
|
||||
info, _, err := c.Object(CONTAINER, OBJECT)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if info.ContentType != "text/plain" {
|
||||
t.Error("Bad content type", info.ContentType)
|
||||
}
|
||||
if info.Bytes != CONTENT_SIZE {
|
||||
t.Error("Bad length")
|
||||
}
|
||||
if info.Hash != CONTENT_MD5 {
|
||||
t.Error("Bad length")
|
||||
}
|
||||
}
|
||||
|
||||
func TestObjectEmpty(t *testing.T) {
|
||||
err := c.ObjectPutString(CONTAINER, EMPTYOBJECT, "", "")
|
||||
if err != nil {
|
||||
|
@ -1493,6 +1534,14 @@ func TestTempUrl(t *testing.T) {
|
|||
if content, err := ioutil.ReadAll(resp.Body); err != nil || string(content) != CONTENTS {
|
||||
t.Error("Bad content", err)
|
||||
}
|
||||
|
||||
resp, err := http.Post(tempUrl, "image/jpeg", bytes.NewReader([]byte(CONTENTS)))
|
||||
if err != nil {
|
||||
t.Fatal("Failed to retrieve file from temporary url")
|
||||
}
|
||||
if resp.StatusCode != 401 {
|
||||
t.Fatal("Expecting server to forbid access to object")
|
||||
}
|
||||
}
|
||||
|
||||
resp.Body.Close()
|
||||
|
@ -1500,7 +1549,17 @@ func TestTempUrl(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryInfo(t *testing.T) {
|
||||
infos, err := c.QueryInfo()
|
||||
if err != nil {
|
||||
t.Log("Server doesn't support querying info")
|
||||
return
|
||||
}
|
||||
if _, ok := infos["swift"]; !ok {
|
||||
t.Fatal("No 'swift' section found in configuration")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerDelete(t *testing.T) {
|
||||
|
|
30
Godeps/_workspace/src/github.com/ncw/swift/swifttest/server.go
generated
vendored
30
Godeps/_workspace/src/github.com/ncw/swift/swifttest/server.go
generated
vendored
|
@ -443,7 +443,7 @@ func (objr objectResource) get(a *action) interface{} {
|
|||
if obj, ok := item.(*object); ok {
|
||||
length := len(obj.data)
|
||||
size += length
|
||||
sum.Write([]byte(components[0] + "/" + obj.name + "\n"))
|
||||
sum.Write([]byte(hex.EncodeToString(obj.checksum)))
|
||||
if start >= cursor+length {
|
||||
continue
|
||||
}
|
||||
|
@ -668,24 +668,42 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
panic(notAuthorized())
|
||||
}
|
||||
|
||||
if req.URL.String() == "/info" {
|
||||
jsonMarshal(w, &swift.SwiftInfo{
|
||||
"swift": map[string]interface{}{
|
||||
"version": "1.2",
|
||||
},
|
||||
"tempurl": map[string]interface{}{
|
||||
"methods": []string{"GET", "HEAD", "PUT"},
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r = s.resourceForURL(req.URL)
|
||||
|
||||
key := req.Header.Get("x-auth-token")
|
||||
if key == "" {
|
||||
secretKey := ""
|
||||
signature := req.URL.Query().Get("temp_url_sig")
|
||||
expires := req.URL.Query().Get("temp_url_expires")
|
||||
if key == "" && signature != "" && expires != "" {
|
||||
accountName, _, _, _ := s.parseURL(req.URL)
|
||||
secretKey := ""
|
||||
if account, ok := s.Accounts[accountName]; ok {
|
||||
secretKey = account.meta.Get("X-Account-Meta-Temp-Url-Key")
|
||||
}
|
||||
|
||||
get_hmac := func(method string) string {
|
||||
mac := hmac.New(sha1.New, []byte(secretKey))
|
||||
body := fmt.Sprintf("%s\n%s\n%s", req.Method, expires, req.URL.Path)
|
||||
body := fmt.Sprintf("%s\n%s\n%s", method, expires, req.URL.Path)
|
||||
mac.Write([]byte(body))
|
||||
expectedSignature := hex.EncodeToString(mac.Sum(nil))
|
||||
return hex.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
if signature != expectedSignature {
|
||||
if req.Method == "HEAD" {
|
||||
if signature != get_hmac("GET") && signature != get_hmac("POST") && signature != get_hmac("PUT") {
|
||||
panic(notAuthorized())
|
||||
}
|
||||
} else if signature != get_hmac(req.Method) {
|
||||
panic(notAuthorized())
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue