aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2018-02-10 10:49:58 +0100
committerStefan Majewsky <majewsky@gmx.net>2018-02-10 10:49:58 +0100
commit9a8ec45e50647e134e5a6e14c3738d6627298b97 (patch)
treeca5f8d6c45444d78e445889a341aeb81b71037a2
parent8dfe7249e015e1a03a911d441cab8c4bb0c7d4c9 (diff)
downloadgo-schwift-9a8ec45e50647e134e5a6e14c3738d6627298b97.tar.gz
sketch out the initial Object API
-rw-r--r--account.go2
-rw-r--r--container.go10
-rw-r--r--object.go181
-rw-r--r--request.go3
4 files changed, 191 insertions, 5 deletions
diff --git a/account.go b/account.go
index 0829eb2..8193cb6 100644
--- a/account.go
+++ b/account.go
@@ -83,6 +83,8 @@ func (a *Account) Client() *gophercloud.ServiceClient {
//Headers returns the AccountHeaders for this account. If the AccountHeaders
//has not been cached yet, a HEAD request is issued on the account.
+//
+//This operation fails with http.StatusNotFound if the account does not exist.
func (a *Account) Headers() (AccountHeaders, error) {
if a.headers != nil {
return *a.headers, nil
diff --git a/container.go b/container.go
index accae8e..7f5097f 100644
--- a/container.go
+++ b/container.go
@@ -63,8 +63,10 @@ func (c *Container) Exists() (bool, error) {
return true, nil
}
-//Headers returns the ContainerHeaders for this account. If the ContainerHeaders
-//has not been cached yet, a HEAD request is issued on the account.
+//Headers returns the ContainerHeaders for this container. If the ContainerHeaders
+//has not been cached yet, a HEAD request is issued on the container.
+//
+//This operation fails with http.StatusNotFound if the container does not exist.
func (c *Container) Headers() (ContainerHeaders, error) {
if c.headers != nil {
return *c.headers, nil
@@ -151,7 +153,7 @@ func (c *Container) Delete(headers ContainerHeaders, opts *RequestOptions) error
}
//Invalidate clears the internal cache of this Container instance. The next call
-//to Headers() on this instance will issue a HEAD request on the account.
+//to Headers() on this instance will issue a HEAD request on the container.
func (c *Container) Invalidate() {
c.headers = nil
}
@@ -171,5 +173,3 @@ func (c *Container) EnsureExists() (*Container, error) {
}.Do(c.a.client)
return c, err
}
-
-// TODO object listing
diff --git a/object.go b/object.go
new file mode 100644
index 0000000..c2f6986
--- /dev/null
+++ b/object.go
@@ -0,0 +1,181 @@
+/******************************************************************************
+*
+* Copyright 2018 Stefan Majewsky <majewsky@gmx.net>
+*
+* 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 schwift
+
+import (
+ "io"
+ "net/http"
+)
+
+//Object represents a Swift object.
+type Object struct {
+ c *Container
+ name string
+ //cache
+ headers *ObjectHeaders
+}
+
+//Object returns a handle to the object with the given name within this
+//container. This function does not issue any HTTP requests, and therefore cannot
+//ensure that the object exists. Use the Exists() function to check for the
+//container's existence.
+func (c *Container) Object(name string) *Object {
+ return &Object{c: c, name: name}
+}
+
+//Container returns a handle to the container this object is stored in.
+func (o *Object) Container() *Container {
+ return o.c
+}
+
+//Name returns the object name. This does not parse the name in any way; if you
+//want only the basename portion of the object name, use package path in
+//conjunction with this function. For example:
+//
+// obj := account.Container("docs").Object("2018-02-10/invoice.pdf")
+// obj.Name() //returns "2018-02-10/invoice.pdf"
+// path.Base(obj.Name()) //returns "invoice.pdf"
+func (o *Object) Name() string {
+ return o.name
+}
+
+//FullName returns the container name and object name joined together with a
+//slash. This identifier is used by Swift in several places (DLO manifests,
+//symlink targets, etc.) to refer to an object within an account. For example:
+//
+// obj := account.Container("docs").Object("2018-02-10/invoice.pdf")
+// obj.Name() //returns "2018-02-10/invoice.pdf"
+// obj.FullName() //returns "docs/2018-02-10/invoice.pdf"
+func (o *Object) FullName() string {
+ return o.c.name + "/" + o.name
+}
+
+//Exists checks if this object exists, potentially by issuing a HEAD request
+//if no Headers() have been cached yet.
+func (o *Object) Exists() (bool, error) {
+ _, err := o.Headers()
+ if Is(err, http.StatusNotFound) {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+//Headers returns the ObjectHeaders for this object. If the ObjectHeaders
+//has not been cached yet, a HEAD request is issued on the object.
+//
+//This operation fails with http.StatusNotFound if the object does not exist.
+func (o *Object) Headers() (ObjectHeaders, error) {
+ if o.headers != nil {
+ return *o.headers, nil
+ }
+
+ resp, err := Request{
+ Method: "HEAD",
+ ContainerName: o.c.name,
+ ObjectName: o.name,
+ ExpectStatusCodes: []int{204},
+ }.Do(o.c.a.client)
+ if err != nil {
+ return ObjectHeaders{}, err
+ }
+
+ headers := ObjectHeaders(headersFromHTTP(resp.Header))
+ err = headers.Validate()
+ if err != nil {
+ return headers, err
+ }
+ o.headers = &headers
+ return *o.headers, nil
+}
+
+//Update updates the object's headers using a POST request. To add URL
+//parameters, pass a non-nil *RequestOptions.
+//
+//If you are not sure whether the container exists, use Create() instead.
+//
+//A successful POST request implies Invalidate() since it may change metadata.
+func (o *Object) Update(headers ObjectHeaders, opts *RequestOptions) error {
+ _, err := Request{
+ Method: "POST",
+ ContainerName: o.c.name,
+ ObjectName: o.name,
+ Headers: headersToHTTP(headers),
+ Options: opts,
+ ExpectStatusCodes: []int{204},
+ }.Do(o.c.a.client)
+ if err == nil {
+ o.Invalidate()
+ }
+ return err
+}
+
+//Upload creates the object using a PUT request. To add URL parameters, pass
+//a non-nil *RequestOptions.
+//
+//This function can be used regardless of whether the object exists or not.
+//
+//A successful PUT request implies Invalidate() since it may change metadata.
+func (o *Object) Upload(content io.Reader, headers ObjectHeaders, opts *RequestOptions) error {
+ //TODO check hash
+ _, err := Request{
+ Method: "PUT",
+ ContainerName: o.c.name,
+ ObjectName: o.name,
+ Headers: headersToHTTP(headers),
+ Options: opts,
+ Body: content,
+ ExpectStatusCodes: []int{201},
+ }.Do(o.c.a.client)
+ if err == nil {
+ o.Invalidate()
+ }
+ return err
+}
+
+//Delete deletes the object using a DELETE request. To add URL parameters,
+//pass a non-nil *RequestOptions.
+//
+//This operation fails with http.StatusNotFound if the object does not exist.
+//
+//A successful DELETE request implies Invalidate().
+func (o *Object) Delete(headers ObjectHeaders, opts *RequestOptions) error {
+ _, err := Request{
+ Method: "DELETE",
+ ContainerName: o.c.name,
+ ObjectName: o.name,
+ Headers: headersToHTTP(headers),
+ Options: opts,
+ ExpectStatusCodes: []int{204},
+ }.Do(o.c.a.client)
+ if err == nil {
+ o.c.Invalidate()
+ }
+ return err
+}
+
+//Invalidate clears the internal cache of this Object instance. The next call
+//to Headers() on this instance will issue a HEAD request on the object.
+func (o *Object) Invalidate() {
+ o.headers = nil
+}
+
+//TODO Object.Copy(), Object.Move(), Object.Download()
+//TODO does Object.Upload() have the right API?
diff --git a/request.go b/request.go
index 2834b3a..1128a00 100644
--- a/request.go
+++ b/request.go
@@ -128,6 +128,9 @@ func (r Request) do(client *gophercloud.ServiceClient, afterReauth bool) (*http.
for key, value := range provider.AuthenticatedHeaders() {
req.Header.Set(key, value)
}
+ if r.Body != nil {
+ req.Header.Set("Expect", "100-continue")
+ }
resp, err := provider.HTTPClient.Do(req)
if err != nil {