Use a ReadSeeker for upload content and rewind the offset on retries
diff --git a/openstack/objectstorage/v1/objects/requests.go b/openstack/objectstorage/v1/objects/requests.go
index 7eedde2..62c006a 100644
--- a/openstack/objectstorage/v1/objects/requests.go
+++ b/openstack/objectstorage/v1/objects/requests.go
@@ -188,7 +188,7 @@
 }
 
 // Create is a function that creates a new object or replaces an existing object.
-func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult {
+func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.ReadSeeker, opts CreateOptsBuilder) CreateResult {
 	var res CreateResult
 
 	url := createURL(c, containerName, objectName)
diff --git a/openstack/objectstorage/v1/objects/requests_test.go b/openstack/objectstorage/v1/objects/requests_test.go
index 6be3534..941e59e 100644
--- a/openstack/objectstorage/v1/objects/requests_test.go
+++ b/openstack/objectstorage/v1/objects/requests_test.go
@@ -3,6 +3,7 @@
 import (
 	"bytes"
 	"io"
+	"strings"
 	"testing"
 
 	"github.com/rackspace/gophercloud/pagination"
@@ -85,7 +86,7 @@
 	defer th.TeardownHTTP()
 	HandleCreateTextObjectSuccessfully(t)
 
-	content := bytes.NewBufferString("Did gyre and gimble in the wabe")
+	content := strings.NewReader("Did gyre and gimble in the wabe")
 	options := &CreateOpts{ContentType: "text/plain"}
 	res := Create(fake.ServiceClient(), "testContainer", "testObject", content, options)
 	th.AssertNoErr(t, res.Err)
@@ -96,7 +97,7 @@
 	defer th.TeardownHTTP()
 	HandleCreateTypelessObjectSuccessfully(t)
 
-	content := bytes.NewBufferString("The sky was the color of television, tuned to a dead channel.")
+	content := strings.NewReader("The sky was the color of television, tuned to a dead channel.")
 	res := Create(fake.ServiceClient(), "testContainer", "testObject", content, &CreateOpts{})
 	th.AssertNoErr(t, res.Err)
 }
diff --git a/provider_client.go b/provider_client.go
index 0dff2cf..e5b75b2 100644
--- a/provider_client.go
+++ b/provider_client.go
@@ -85,9 +85,9 @@
 	// content type of the request will default to "application/json" unless overridden by MoreHeaders.
 	// It's an error to specify both a JSONBody and a RawBody.
 	JSONBody interface{}
-	// RawBody contains an io.Reader that will be consumed by the request directly. No content-type
+	// RawBody contains an io.ReadSeeker that will be consumed by the request directly. No content-type
 	// will be set unless one is provided explicitly by MoreHeaders.
-	RawBody io.Reader
+	RawBody io.ReadSeeker
 
 	// JSONResponse, if provided, will be populated with the contents of the response body parsed as
 	// JSON.
@@ -124,11 +124,11 @@
 // Request performs an HTTP request using the ProviderClient's current HTTPClient. An authentication
 // header will automatically be provided.
 func (client *ProviderClient) Request(method, url string, options RequestOpts) (*http.Response, error) {
-	var body io.Reader
+	var body io.ReadSeeker
 	var contentType *string
 
 	// Derive the content body by either encoding an arbitrary object as JSON, or by taking a provided
-	// io.Reader as-is. Default the content-type to application/json.
+	// io.ReadSeeker as-is. Default the content-type to application/json.
 	if options.JSONBody != nil {
 		if options.RawBody != nil {
 			panic("Please provide only one of JSONBody or RawBody to gophercloud.Request().")
@@ -189,6 +189,7 @@
 			if err != nil {
 				return nil, fmt.Errorf("Error trying to re-authenticate: %s", err)
 			}
+			options.RawBody.Seek(0, 0)
 			resp, err = client.Request(method, url, options)
 			if err != nil {
 				return nil, fmt.Errorf("Successfully re-authenticated, but got error executing request: %s", err)
@@ -260,7 +261,7 @@
 		opts = &RequestOpts{}
 	}
 
-	if v, ok := (JSONBody).(io.Reader); ok {
+	if v, ok := (JSONBody).(io.ReadSeeker); ok {
 		opts.RawBody = v
 	} else if JSONBody != nil {
 		opts.JSONBody = JSONBody
@@ -278,7 +279,7 @@
 		opts = &RequestOpts{}
 	}
 
-	if v, ok := (JSONBody).(io.Reader); ok {
+	if v, ok := (JSONBody).(io.ReadSeeker); ok {
 		opts.RawBody = v
 	} else if JSONBody != nil {
 		opts.JSONBody = JSONBody
diff --git a/rackspace/objectstorage/v1/objects/delegate.go b/rackspace/objectstorage/v1/objects/delegate.go
index 028d66a..94c820b 100644
--- a/rackspace/objectstorage/v1/objects/delegate.go
+++ b/rackspace/objectstorage/v1/objects/delegate.go
@@ -33,7 +33,7 @@
 }
 
 // Create is a function that creates a new object or replaces an existing object.
-func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts os.CreateOptsBuilder) os.CreateResult {
+func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.ReadSeeker, opts os.CreateOptsBuilder) os.CreateResult {
 	return os.Create(c, containerName, objectName, content, opts)
 }
 
diff --git a/rackspace/objectstorage/v1/objects/delegate_test.go b/rackspace/objectstorage/v1/objects/delegate_test.go
index 8ab8029..3431056 100644
--- a/rackspace/objectstorage/v1/objects/delegate_test.go
+++ b/rackspace/objectstorage/v1/objects/delegate_test.go
@@ -1,7 +1,7 @@
 package objects
 
 import (
-	"bytes"
+	"strings"
 	"testing"
 
 	os "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects"
@@ -68,7 +68,7 @@
 	defer th.TeardownHTTP()
 	os.HandleCreateTextObjectSuccessfully(t)
 
-	content := bytes.NewBufferString("Did gyre and gimble in the wabe")
+	content := strings.NewReader("Did gyre and gimble in the wabe")
 	options := &os.CreateOpts{ContentType: "text/plain"}
 	res := Create(fake.ServiceClient(), "testContainer", "testObject", content, options)
 	th.AssertNoErr(t, res.Err)
@@ -79,7 +79,7 @@
 	defer th.TeardownHTTP()
 	os.HandleCreateTypelessObjectSuccessfully(t)
 
-	content := bytes.NewBufferString("The sky was the color of television, tuned to a dead channel.")
+	content := strings.NewReader("The sky was the color of television, tuned to a dead channel.")
 	res := Create(fake.ServiceClient(), "testContainer", "testObject", content, &os.CreateOpts{})
 	th.AssertNoErr(t, res.Err)
 }