diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..266d8f5
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+github: [ncw]
+patreon: njcw
+liberapay: ncw
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..5c1b7bf
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,108 @@
+---
+# Github Actions build for swift
+# -*- compile-command: "yamllint -f parsable build.yml" -*-
+
+name: build
+
+# Trigger the workflow on push or pull request
+on:
+  push:
+    branches:
+      - '*'
+    tags:
+      - '*'
+  pull_request:
+  workflow_dispatch:
+    inputs:
+      manual:
+        required: true
+        default: true
+
+jobs:
+  build:
+    if: ${{ github.repository == 'ncw/swift' || github.event.inputs.manual }}
+    timeout-minutes: 60
+    strategy:
+      fail-fast: false
+      matrix:
+        job_name: ['go1.17', 'go1.16', 'go1.15']
+
+        include:
+          - job_name: go1.17
+            os: ubuntu-latest
+            go: '1.17.x'
+            gotests: true
+            integrationtest: true
+            check: true
+
+          - job_name: go1.16
+            os: ubuntu-latest
+            go: '1.16.x'
+            gotests: true
+            integrationtest: true
+            check: false
+
+          - job_name: go1.15
+            os: ubuntu-latest
+            go: '1.15.x'
+            gotests: true
+            integrationtest: true
+            check: false
+
+    name: ${{ matrix.job_name }}
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Install Go
+        uses: actions/setup-go@v2
+        with:
+          stable: 'false'
+          go-version: ${{ matrix.go }}
+
+      - name: Print Go version and environment
+        shell: bash
+        run: |
+          printf "Using go at: $(which go)\n"
+          printf "Go version: $(go version)\n"
+          printf "\n\nGo environment:\n\n"
+          go env
+          printf "\n\nSystem environment:\n\n"
+          env
+
+      - name: Go module cache
+        uses: actions/cache@v2
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-go-
+
+      - name: Build
+        shell: bash
+        run: |
+          go build ./...
+
+      - name: Unit tests
+        shell: bash
+        run: |
+          go test -v
+        if: matrix.gotests
+
+      - name: Integration tests
+        shell: bash
+        run: |
+          ./integration_test.sh
+        if: matrix.integrationtest
+
+      - name: Code quality test
+        uses: golangci/golangci-lint-action@v2
+        with:
+          # Version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
+          version: latest
+        if: matrix.check
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..a477186
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,24 @@
+# golangci-lint configuration options
+
+linters:
+  enable:
+    - deadcode
+    - errcheck
+    - goimports
+    # - revive
+    - ineffassign
+    - structcheck
+    - varcheck
+    - govet
+    - unconvert
+  disable-all: true
+
+issues:
+  # Enable some lints excluded by default
+  exclude-use-default: false
+
+  # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
+  max-per-linter: 0
+
+  # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
+  max-same-issues: 0
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d43ba94..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-language: go
-sudo: false
-
-go:
-  - 1.2.x
-  - 1.3.x
-  - 1.4.x
-  - 1.5.x
-  - 1.6.x
-  - 1.7.x
-  - 1.8.x
-  - 1.9.x
-  - 1.10.x
-  - 1.11.x
-  - 1.12.x
-  - 1.13.x
-  - 1.14.x
-  - master
-
-matrix:
-  include:
-  - go: 1.14.x
-    env: TEST_REAL_SERVER=rackspace
-  - go: 1.14.x
-    env: TEST_REAL_SERVER=memset
-  allow_failures:
-  - go: 1.14.x
-    env: TEST_REAL_SERVER=rackspace
-  - go: 1.14.x
-    env: TEST_REAL_SERVER=memset
-install: go test -i ./...
-script:
-  - test -z "$(go fmt ./...)"
-  - go test
-  - ./travis_realserver.sh
diff --git a/README.md b/README.md
index 1965f73..daa6412 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,43 @@
 Swift
 =====
 
-This package provides an easy to use library for interfacing with
-Swift / Openstack Object Storage / Rackspace cloud files from the Go
-Language
+This package provides an easy to use library for interfacing with Swift / Openstack Object Storage / Rackspace cloud
+files from the Go Language
 
-See here for package docs
-
-  http://godoc.org/github.com/ncw/swift
-
-[![Build Status](https://api.travis-ci.org/ncw/swift.svg?branch=master)](https://travis-ci.org/ncw/swift) [![GoDoc](https://godoc.org/github.com/ncw/swift?status.svg)](https://godoc.org/github.com/ncw/swift) 
+[![Build Status](https://github.com/ncw/swift/workflows/build/badge.svg?branch=master)](https://github.com/ncw/swift/actions)
+[![Go Reference](https://pkg.go.dev/badge/github.com/ncw/v2/swift.svg)](https://pkg.go.dev/github.com/ncw/swift/v2)
 
 Install
 -------
 
 Use go to install the library
 
-    go get github.com/ncw/swift
+    go get github.com/ncw/swift/v2
 
 Usage
 -----
 
 See here for full package docs
 
-- http://godoc.org/github.com/ncw/swift
+- https://pkg.go.dev/github.com/ncw/swift/v2
 
 Here is a short example from the docs
+
 ```go
-import "github.com/ncw/swift"
+import "github.com/ncw/swift/v2"
 
 // Create a connection
 c := swift.Connection{
-    UserName: "user",
-    ApiKey:   "key",
-    AuthUrl:  "auth_url",
-    Domain:   "domain",  // Name of the domain (v3 auth only)
-    Tenant:   "tenant",  // Name of the tenant (v2 auth only)
+UserName: "user",
+ApiKey:   "key",
+AuthUrl:  "auth_url",
+Domain:   "domain", // Name of the domain (v3 auth only)
+Tenant:   "tenant", // Name of the tenant (v2 auth only)
 }
 // Authenticate
 err := c.Authenticate()
 if err != nil {
-    panic(err)
+panic(err)
 }
 // List all the containers
 containers, err := c.ContainerNames(nil)
@@ -48,6 +45,14 @@ fmt.Println(containers)
 // etc...
 ```
 
+Migrating from `v1`
+-----
+The library has current major version v2. If you want to migrate from the first version of
+library `github.com/ncw/swift` you have to explicitly add the `/v2` suffix to the imports.
+
+Most of the exported functions were added a new `context.Context` parameter in the `v2`, which you will have to provide
+when migrating.
+
 Additions
 ---------
 
@@ -56,11 +61,10 @@ The `rs` sub project contains a wrapper for the Rackspace specific CDN Managemen
 Testing
 -------
 
-To run the tests you can either use an embedded fake Swift server
-either use a real Openstack Swift server or a Rackspace Cloud files account.
+To run the tests you can either use an embedded fake Swift server either use a real Openstack Swift server or a
+Rackspace Cloud files account.
 
-When using a real Swift server, you need to set these environment variables
-before running the tests
+When using a real Swift server, you need to set these environment variables before running the tests
 
     export SWIFT_API_USER='user'
     export SWIFT_API_KEY='key'
@@ -99,8 +103,7 @@ Then run the tests with `go test`
 License
 -------
 
-This is free software under the terms of MIT license (check COPYING file
-included in this package).
+This is free software under the terms of MIT license (check COPYING file included in this package).
 
 Contact and support
 -------------------
@@ -161,3 +164,8 @@ Contributors
 - Brandon WELSCH <dev@brandon-welsch.eu>
 - Damien Tournoud <damien@platform.sh>
 - Pedro Kiefer <pedro@kiefer.com.br>
+- Martin Chodur <m.chodur@seznam.cz>
+- Devendra <devendranath.thadi3@gmail.com>
+- timss <timsateroy@gmail.com>
+- Jos Houtman <jos@houtman.it>
+- Paul Collins <paul.collins@canonical.com>
diff --git a/auth.go b/auth.go
index 25654f4..ec56cc6 100644
--- a/auth.go
+++ b/auth.go
@@ -2,6 +2,7 @@ package swift
 
 import (
 	"bytes"
+	"context"
 	"encoding/json"
 	"net/http"
 	"net/url"
@@ -14,9 +15,9 @@ import (
 // This encapsulates the different authentication schemes in use
 type Authenticator interface {
 	// Request creates an http.Request for the auth - return nil if not needed
-	Request(*Connection) (*http.Request, error)
+	Request(context.Context, *Connection) (*http.Request, error)
 	// Response parses the http.Response
-	Response(resp *http.Response) error
+	Response(ctx context.Context, resp *http.Response) error
 	// The public storage URL - set Internal to true to read
 	// internal/service net URL
 	StorageUrl(Internal bool) string
@@ -88,8 +89,8 @@ type v1Auth struct {
 }
 
 // v1 Authentication - make request
-func (auth *v1Auth) Request(c *Connection) (*http.Request, error) {
-	req, err := http.NewRequest("GET", c.AuthUrl, nil)
+func (auth *v1Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
+	req, err := http.NewRequestWithContext(ctx, "GET", c.AuthUrl, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -100,7 +101,7 @@ func (auth *v1Auth) Request(c *Connection) (*http.Request, error) {
 }
 
 // v1 Authentication - read response
-func (auth *v1Auth) Response(resp *http.Response) error {
+func (auth *v1Auth) Response(_ context.Context, resp *http.Response) error {
 	auth.Headers = resp.Header
 	return nil
 }
@@ -141,7 +142,7 @@ type v2Auth struct {
 }
 
 // v2 Authentication - make request
-func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
+func (auth *v2Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
 	auth.Region = c.Region
 	// Toggle useApiKey if not first run and not OK yet
 	if auth.notFirst && !auth.useApiKeyOk {
@@ -176,7 +177,7 @@ func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
 		url += "/"
 	}
 	url += "tokens"
-	req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
+	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
 	if err != nil {
 		return nil, err
 	}
@@ -186,7 +187,7 @@ func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
 }
 
 // v2 Authentication - read response
-func (auth *v2Auth) Response(resp *http.Response) error {
+func (auth *v2Auth) Response(_ context.Context, resp *http.Response) error {
 	auth.Auth = new(v2AuthResponse)
 	err := readJson(resp, auth.Auth)
 	// If successfully read Auth then no need to toggle useApiKey any more
diff --git a/auth_v3.go b/auth_v3.go
index 1e34ad8..89840d7 100644
--- a/auth_v3.go
+++ b/auth_v3.go
@@ -2,6 +2,7 @@ package swift
 
 import (
 	"bytes"
+	"context"
 	"encoding/json"
 	"fmt"
 	"net/http"
@@ -13,7 +14,6 @@ const (
 	v3AuthMethodToken                 = "token"
 	v3AuthMethodPassword              = "password"
 	v3AuthMethodApplicationCredential = "application_credential"
-	v3CatalogTypeObjectStore          = "object-store"
 )
 
 // V3 Authentication request
@@ -122,7 +122,7 @@ type v3Auth struct {
 	Headers http.Header
 }
 
-func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
+func (auth *v3Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
 	auth.Region = c.Region
 
 	var v3i interface{}
@@ -242,7 +242,7 @@ func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
 		url += "/"
 	}
 	url += "auth/tokens"
-	req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
+	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
 	if err != nil {
 		return nil, err
 	}
@@ -251,7 +251,7 @@ func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
 	return req, nil
 }
 
-func (auth *v3Auth) Response(resp *http.Response) error {
+func (auth *v3Auth) Response(_ context.Context, resp *http.Response) error {
 	auth.Auth = &v3AuthResponse{}
 	auth.Headers = resp.Header
 	err := readJson(resp, auth.Auth)
diff --git a/bin/update-authors.py b/bin/update-authors.py
index 2e10312..5df3e05 100755
--- a/bin/update-authors.py
+++ b/bin/update-authors.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 """
 Update the README.md file with the authors from the git log
 """
@@ -23,16 +23,17 @@ def add_email(name, email):
     """
     adds the email passed in to the end of authors
     """
-    print "Adding %s <%s>" % (name, email)
+    print("Adding %s <%s>" % (name, email))
     with open(AUTHORS, "a+") as fd:
-        print >>fd, "- %s <%s>" % (name, email)
+        print("- %s <%s>" % (name, email), file=fd)
     subprocess.check_call(["git", "commit", "-m", "Add %s to contributors" % name, AUTHORS])
     
 def main():
     out = subprocess.check_output(["git", "log", '--reverse', '--format=%an|%ae', "master"])
 
     previous = load()
-    for line in out.split("\n"):
+    for line in out.split(b"\n"):
+        line = line.decode("utf-8")
         line = line.strip()
         if line == "":
             continue
diff --git a/compatibility_1_0.go b/compatibility_1_0.go
index 7b69a75..35709f6 100644
--- a/compatibility_1_0.go
+++ b/compatibility_1_0.go
@@ -1,5 +1,6 @@
 // Go 1.0 compatibility functions
 
+//go:build !go1.1
 // +build !go1.1
 
 package swift
diff --git a/compatibility_1_1.go b/compatibility_1_1.go
index a4f9c3a..76545b1 100644
--- a/compatibility_1_1.go
+++ b/compatibility_1_1.go
@@ -1,5 +1,6 @@
 // Go 1.1 and later compatibility functions
 //
+//go:build go1.1
 // +build go1.1
 
 package swift
diff --git a/compatibility_1_6.go b/compatibility_1_6.go
index b443d01..9a1bf96 100644
--- a/compatibility_1_6.go
+++ b/compatibility_1_6.go
@@ -1,3 +1,4 @@
+//go:build go1.6
 // +build go1.6
 
 package swift
diff --git a/compatibility_not_1_6.go b/compatibility_not_1_6.go
index aabb44e..2957655 100644
--- a/compatibility_not_1_6.go
+++ b/compatibility_not_1_6.go
@@ -1,3 +1,4 @@
+//go:build !go1.6
 // +build !go1.6
 
 package swift
diff --git a/debian/changelog b/debian/changelog
index 89d315b..0bd0779 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-golang-github-ncw-swift (1.0.52-2) UNRELEASED; urgency=medium
+golang-github-ncw-swift (2.0.1-1) UNRELEASED; urgency=medium
 
   [ Debian Janitor ]
   * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository,
@@ -8,7 +8,10 @@ golang-github-ncw-swift (1.0.52-2) UNRELEASED; urgency=medium
   [ Tianon Gravi ]
   * Remove self from Uploaders
 
- -- Debian Janitor <janitor@jelmer.uk>  Fri, 24 Sep 2021 04:34:36 -0000
+  [ Debian Janitor ]
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 10 Mar 2022 04:23:03 -0000
 
 golang-github-ncw-swift (1.0.52-1) unstable; urgency=medium
 
diff --git a/dlo.go b/dlo.go
index 05a1927..da0684a 100644
--- a/dlo.go
+++ b/dlo.go
@@ -1,6 +1,7 @@
 package swift
 
 import (
+	"context"
 	"os"
 	"strings"
 )
@@ -14,8 +15,8 @@ type DynamicLargeObjectCreateFile struct {
 // returning an object which satisfies io.Writer, io.Seeker, io.Closer
 // and io.ReaderFrom.  The flags are as passes to the
 // largeObjectCreate method.
-func (c *Connection) DynamicLargeObjectCreateFile(opts *LargeObjectOpts) (LargeObjectFile, error) {
-	lo, err := c.largeObjectCreate(opts)
+func (c *Connection) DynamicLargeObjectCreateFile(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
+	lo, err := c.largeObjectCreate(ctx, opts)
 	if err != nil {
 		return nil, err
 	}
@@ -28,29 +29,33 @@ func (c *Connection) DynamicLargeObjectCreateFile(opts *LargeObjectOpts) (LargeO
 // DynamicLargeObjectCreate creates or truncates an existing dynamic
 // large object returning a writeable object.  This sets opts.Flags to
 // an appropriate value before calling DynamicLargeObjectCreateFile
-func (c *Connection) DynamicLargeObjectCreate(opts *LargeObjectOpts) (LargeObjectFile, error) {
+func (c *Connection) DynamicLargeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
 	opts.Flags = os.O_TRUNC | os.O_CREATE
-	return c.DynamicLargeObjectCreateFile(opts)
+	return c.DynamicLargeObjectCreateFile(ctx, opts)
 }
 
 // DynamicLargeObjectDelete deletes a dynamic large object and all of its segments.
-func (c *Connection) DynamicLargeObjectDelete(container string, path string) error {
-	return c.LargeObjectDelete(container, path)
+func (c *Connection) DynamicLargeObjectDelete(ctx context.Context, container string, path string) error {
+	return c.LargeObjectDelete(ctx, container, path)
 }
 
 // DynamicLargeObjectMove moves a dynamic large object from srcContainer, srcObjectName to dstContainer, dstObjectName
-func (c *Connection) DynamicLargeObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
-	info, headers, err := c.Object(srcContainer, srcObjectName)
+func (c *Connection) DynamicLargeObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
+	info, headers, err := c.Object(ctx, srcContainer, srcObjectName)
 	if err != nil {
 		return err
 	}
 
-	segmentContainer, segmentPath := parseFullPath(headers["X-Object-Manifest"])
-	if err := c.createDLOManifest(dstContainer, dstObjectName, segmentContainer+"/"+segmentPath, info.ContentType, sanitizeLargeObjectMoveHeaders(headers)); err != nil {
+	segmentContainer, segmentPath, err := parseFullPath(headers["X-Object-Manifest"])
+	if err != nil {
+		return err
+	}
+
+	if err := c.createDLOManifest(ctx, dstContainer, dstObjectName, segmentContainer+"/"+segmentPath, info.ContentType, sanitizeLargeObjectMoveHeaders(headers)); err != nil {
 		return err
 	}
 
-	if err := c.ObjectDelete(srcContainer, srcObjectName); err != nil {
+	if err := c.ObjectDelete(ctx, srcContainer, srcObjectName); err != nil {
 		return err
 	}
 
@@ -68,12 +73,12 @@ func sanitizeLargeObjectMoveHeaders(headers Headers) Headers {
 }
 
 // createDLOManifest creates a dynamic large object manifest
-func (c *Connection) createDLOManifest(container string, objectName string, prefix string, contentType string, headers Headers) error {
+func (c *Connection) createDLOManifest(ctx context.Context, container string, objectName string, prefix string, contentType string, headers Headers) error {
 	if headers == nil {
 		headers = make(Headers)
 	}
 	headers["X-Object-Manifest"] = prefix
-	manifest, err := c.ObjectCreate(container, objectName, false, "", contentType, headers)
+	manifest, err := c.ObjectCreate(ctx, container, objectName, false, "", contentType, headers)
 	if err != nil {
 		return err
 	}
@@ -87,20 +92,24 @@ func (c *Connection) createDLOManifest(container string, objectName string, pref
 
 // Close satisfies the io.Closer interface
 func (file *DynamicLargeObjectCreateFile) Close() error {
-	return file.Flush()
+	return file.CloseWithContext(context.Background())
+}
+
+func (file *DynamicLargeObjectCreateFile) CloseWithContext(ctx context.Context) error {
+	return file.Flush(ctx)
 }
 
-func (file *DynamicLargeObjectCreateFile) Flush() error {
-	err := file.conn.createDLOManifest(file.container, file.objectName, file.segmentContainer+"/"+file.prefix, file.contentType, file.headers)
+func (file *DynamicLargeObjectCreateFile) Flush(ctx context.Context) error {
+	err := file.conn.createDLOManifest(ctx, file.container, file.objectName, file.segmentContainer+"/"+file.prefix, file.contentType, file.headers)
 	if err != nil {
 		return err
 	}
-	return file.conn.waitForSegmentsToShowUp(file.container, file.objectName, file.Size())
+	return file.conn.waitForSegmentsToShowUp(ctx, file.container, file.objectName, file.Size())
 }
 
-func (c *Connection) getAllDLOSegments(segmentContainer, segmentPath string) ([]Object, error) {
+func (c *Connection) getAllDLOSegments(ctx context.Context, segmentContainer, segmentPath string) ([]Object, error) {
 	//a simple container listing works 99.9% of the time
-	segments, err := c.ObjectsAll(segmentContainer, &ObjectsOpts{Prefix: segmentPath})
+	segments, err := c.ObjectsAll(ctx, segmentContainer, &ObjectsOpts{Prefix: segmentPath})
 	if err != nil {
 		return nil, err
 	}
@@ -126,7 +135,7 @@ func (c *Connection) getAllDLOSegments(segmentContainer, segmentPath string) ([]
 		//guaranteed to return the correct metadata, except for the pathological
 		//case of an outage of large parts of the Swift cluster or its network,
 		//since every segment is only written once.)
-		segment, _, err := c.Object(segmentContainer, segmentName)
+		segment, _, err := c.Object(ctx, segmentContainer, segmentName)
 		switch err {
 		case nil:
 			//found new segment -> add it in the correct position and keep
diff --git a/dlo_test.go b/dlo_test.go
index 55bbd51..1764a47 100644
--- a/dlo_test.go
+++ b/dlo_test.go
@@ -2,10 +2,12 @@ package swift
 
 import (
 	"bytes"
-	"github.com/ncw/swift/swifttest"
+	"context"
 	"net/http"
 	"testing"
 	"time"
+
+	"github.com/ncw/swift/v2/swifttest"
 )
 
 var srv *swifttest.SwiftServer
@@ -47,7 +49,7 @@ func initTestConnection(t *testing.T) (*Connection, error) {
 		Domain:         "Default",
 		AuthVersion:    1,
 	}
-	err = swiftCon.Authenticate()
+	err = swiftCon.Authenticate(context.Background())
 	return &swiftCon, err
 }
 func TestCases(t *testing.T) {
@@ -63,8 +65,9 @@ func TestCases(t *testing.T) {
 }
 
 func createContainers(containers []string, t *testing.T) {
+	ctx := context.Background()
 	for i := 0; i < len(containers); i++ {
-		err = con.ContainerCreate(containers[i], nil) // Create container
+		err = con.ContainerCreate(ctx, containers[i], nil) // Create container
 		if err != nil {
 			t.Errorf("Fail at create container %s", containers[i])
 		}
@@ -72,6 +75,7 @@ func createContainers(containers []string, t *testing.T) {
 }
 
 func createDynamicObject(container, object string, t *testing.T) {
+	ctx := context.Background()
 	metadata := map[string]string{}
 	metadata["Custom-Field"] = "SomeValue"
 	ops := LargeObjectOpts{
@@ -83,16 +87,23 @@ func createDynamicObject(container, object string, t *testing.T) {
 		SegmentContainer: segmentContainer,                   // Name of the container to place segments
 		SegmentPrefix:    "sg",                               // Prefix to use for the segments
 	}
-	bigfile, err := con.DynamicLargeObjectCreate(&ops)
+	bigfile, err := con.DynamicLargeObjectCreate(ctx, &ops)
 	if err != nil {
 		t.Errorf("Fail at dynamic create Large Object")
 	}
-	bigfile.Write(filecontent)
-	bigfile.Close()
+	_, err = bigfile.WriteWithContext(ctx, filecontent)
+	if err != nil {
+		t.Errorf("WriteWithContext failed: %v", err)
+	}
+	err = bigfile.CloseWithContext(ctx)
+	if err != nil {
+		t.Errorf("CloseWithContext failed: %v", err)
+	}
 	checkObject(container, object, t)
 }
 func checkObject(container, object string, t *testing.T) {
-	info, header, err := con.Object(container, object)
+	ctx := context.Background()
+	info, header, err := con.Object(ctx, container, object)
 	if err != nil {
 		t.Errorf("Fail at get Large Object metadata: %s", err.Error())
 	}
@@ -106,7 +117,7 @@ func checkObject(container, object string, t *testing.T) {
 		t.Errorf("Fail: lost custom metadata header")
 	}
 
-	content, err := con.ObjectGetBytes(container, object)
+	content, err := con.ObjectGetBytes(ctx, container, object)
 	if err != nil {
 		t.Errorf("Fail at read Large Object : %s", err.Error())
 	}
@@ -116,13 +127,13 @@ func checkObject(container, object string, t *testing.T) {
 
 }
 func checkNotExistObject(container, object string, t *testing.T) {
-	_, _, err = con.Object(container, object)
+	_, _, err = con.Object(context.Background(), container, object)
 	if err == nil || err.Error() != "Object Not Found" {
 		t.Errorf("Fail at checkNotExistObject object: %s", err)
 	}
 }
 func moveDynamicObject(sc, so, dc, do string, t *testing.T) {
-	err = con.DynamicLargeObjectMove(sc, so, dc, do)
+	err = con.DynamicLargeObjectMove(context.Background(), sc, so, dc, do)
 	if err != nil {
 		t.Errorf("Fail at dynamic move Large Object: %s", err.Error())
 	}
@@ -130,12 +141,13 @@ func moveDynamicObject(sc, so, dc, do string, t *testing.T) {
 	checkObject(dc, do, t)
 }
 func deleteDynamicObject(container, object string, t *testing.T) {
-	err = con.DynamicLargeObjectDelete(container, object)
+	ctx := context.Background()
+	err = con.DynamicLargeObjectDelete(ctx, container, object)
 	if err != nil {
 		t.Errorf("Fail at delte dynamic Large Object: %s", err.Error())
 	}
 	checkNotExistObject(container, object, t)
-	objs, err := con.ObjectsAll(segmentContainer, nil)
+	objs, err := con.ObjectsAll(ctx, segmentContainer, nil)
 	if err != nil {
 		t.Errorf("Fail at check delte dynamic Large Object: %s", err.Error())
 	}
@@ -144,6 +156,7 @@ func deleteDynamicObject(container, object string, t *testing.T) {
 	}
 }
 func createStaticObject(container, object string, t *testing.T) {
+	ctx := context.Background()
 	metadata := map[string]string{}
 	metadata["Custom-Field"] = "SomeValue"
 	ops := LargeObjectOpts{
@@ -155,16 +168,22 @@ func createStaticObject(container, object string, t *testing.T) {
 		SegmentContainer: segmentContainer,                   // Name of the container to place segments
 		SegmentPrefix:    "sg",                               // Prefix to use for the segments
 	}
-	bigfile, err := con.StaticLargeObjectCreate(&ops)
+	bigfile, err := con.StaticLargeObjectCreate(ctx, &ops)
 	if err != nil {
 		t.Errorf("Fail at static create Large Object")
 	}
-	bigfile.Write(filecontent)
-	bigfile.Close()
+	_, err = bigfile.WriteWithContext(ctx, filecontent)
+	if err != nil {
+		t.Errorf("WriteWithContext failed: %v", err)
+	}
+	err = bigfile.CloseWithContext(ctx)
+	if err != nil {
+		t.Errorf("CloseWithContext failed: %v", err)
+	}
 	checkObject(container, object, t)
 }
 func moveStaticObject(sc, so, dc, do string, t *testing.T) {
-	err = con.StaticLargeObjectMove(sc, so, dc, do)
+	err = con.StaticLargeObjectMove(context.Background(), sc, so, dc, do)
 	if err != nil {
 		t.Errorf("Fail at static move Large Object: %s", err.Error())
 	}
@@ -172,12 +191,13 @@ func moveStaticObject(sc, so, dc, do string, t *testing.T) {
 	checkObject(dc, do, t)
 }
 func deleteStaticObject(container, object string, t *testing.T) {
-	err = con.StaticLargeObjectDelete(container, object)
+	ctx := context.Background()
+	err = con.StaticLargeObjectDelete(ctx, container, object)
 	if err != nil {
 		t.Errorf("Fail at delte dynamic Large Object: %s", err.Error())
 	}
 	checkNotExistObject(container, object, t)
-	objs, err := con.ObjectsAll(segmentContainer, nil)
+	objs, err := con.ObjectsAll(ctx, segmentContainer, nil)
 	if err != nil {
 		t.Errorf("Fail at check delte dynamic Large Object: %s", err.Error())
 	}
diff --git a/example_test.go b/example_test.go
index 95ec965..42d2f0b 100644
--- a/example_test.go
+++ b/example_test.go
@@ -4,12 +4,14 @@
 package swift_test
 
 import (
+	"context"
 	"fmt"
 
-	"github.com/ncw/swift"
+	"github.com/ncw/swift/v2"
 )
 
 func ExampleConnection() {
+	ctx := context.Background()
 	// Create a v1 auth connection
 	c := &swift.Connection{
 		// This should be your username
@@ -24,12 +26,15 @@ func ExampleConnection() {
 	}
 
 	// Authenticate
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		panic(err)
 	}
 	// List all the containers
-	containers, err := c.ContainerNames(nil)
+	containers, err := c.ContainerNames(ctx, nil)
+	if err != nil {
+		panic(err)
+	}
 	fmt.Println(containers)
 	// etc...
 
@@ -61,8 +66,8 @@ func ExampleConnection_ObjectsWalk() {
 	defer rollback()
 
 	objects := make([]string, 0)
-	err := c.ObjectsWalk(container, nil, func(opts *swift.ObjectsOpts) (interface{}, error) {
-		newObjects, err := c.ObjectNames(container, opts)
+	err := c.ObjectsWalk(context.Background(), container, nil, func(ctx context.Context, opts *swift.ObjectsOpts) (interface{}, error) {
+		newObjects, err := c.ObjectNames(ctx, container, opts)
 		if err == nil {
 			objects = append(objects, newObjects...)
 		}
@@ -76,23 +81,24 @@ func ExampleConnection_VersionContainerCreate() {
 	defer rollback()
 
 	// Use the helper method to create the current and versions container.
-	if err := c.VersionContainerCreate("cds", "cd-versions"); err != nil {
+	if err := c.VersionContainerCreate(context.Background(), "cds", "cd-versions"); err != nil {
 		fmt.Print(err.Error())
 	}
 }
 
 func ExampleConnection_VersionEnable() {
+	ctx := context.Background()
 	c, rollback := makeConnection(nil)
 	defer rollback()
 
 	// Build the containers manually and enable them.
-	if err := c.ContainerCreate("movie-versions", nil); err != nil {
+	if err := c.ContainerCreate(ctx, "movie-versions", nil); err != nil {
 		fmt.Print(err.Error())
 	}
-	if err := c.ContainerCreate("movies", nil); err != nil {
+	if err := c.ContainerCreate(ctx, "movies", nil); err != nil {
 		fmt.Print(err.Error())
 	}
-	if err := c.VersionEnable("movies", "movie-versions"); err != nil {
+	if err := c.VersionEnable(ctx, "movies", "movie-versions"); err != nil {
 		fmt.Print(err.Error())
 	}
 
@@ -105,5 +111,8 @@ func ExampleConnection_VersionDisable() {
 	defer rollback()
 
 	// Disable versioning on a container.  Note that this does not delete the versioning container.
-	c.VersionDisable("movies")
+	err := c.VersionDisable(context.Background(), "movies")
+	if err != nil {
+		panic(err)
+	}
 }
diff --git a/go.mod b/go.mod
index 29f6ee2..501c1ba 100644
--- a/go.mod
+++ b/go.mod
@@ -1 +1,3 @@
-module github.com/ncw/swift
+module github.com/ncw/swift/v2
+
+go 1.15
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/integration_test.sh b/integration_test.sh
new file mode 100755
index 0000000..6bcb988
--- /dev/null
+++ b/integration_test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Run the swift tests against an openstack server from a swift all in
+# one docker image
+
+set -e
+
+NAME=swift-aio
+HOST=127.0.0.1
+PORT=8294
+AUTH=v1
+
+case $AUTH in
+    v1)
+        export SWIFT_AUTH_URL="http://${HOST}:${PORT}/auth/v1.0"
+        export SWIFT_API_USER='test:tester'
+        export SWIFT_API_KEY='testing'
+        ;;
+    v2)
+        # NB v2 auth doesn't work for unknown reasons!
+        export SWIFT_AUTH_URL="http://${HOST}:${PORT}/auth/v2.0"
+        export SWIFT_TENANT='tester'
+        export SWIFT_API_USER='test'
+        export SWIFT_API_KEY='testing'
+        ;;
+    *)
+        echo "Bad AUTH %AUTH"
+        exit 1
+        ;;
+esac
+
+
+echo "Starting test server"
+docker run --rm -d --name ${NAME} -p ${HOST}:${PORT}:8080 bouncestorage/swift-aio
+
+function cleanup {
+    echo "Killing test server"
+    docker kill ${NAME}
+}
+
+trap cleanup EXIT
+
+echo -n "Waiting for test server to startup"
+tries=30
+while [[ $tries -gt 0 ]]; do
+    echo -n "."
+    STATUS_RECEIVED=$(curl -s -o /dev/null -L -w ''%{http_code}'' ${SWIFT_AUTH_URL} || true)
+    if [[ ${STATUS_RECEIVED} -ge 200 ]]; then
+        break
+    fi
+    let tries-=1
+    sleep 1
+done
+echo "OK"
+
+echo "Running tests"
+go test -v
+
diff --git a/largeobjects.go b/largeobjects.go
index 038bef8..369ada7 100644
--- a/largeobjects.go
+++ b/largeobjects.go
@@ -3,12 +3,14 @@ package swift
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/rand"
 	"crypto/sha1"
 	"encoding/hex"
 	"errors"
 	"fmt"
 	"io"
+	"net/url"
 	"os"
 	gopath "path"
 	"strconv"
@@ -56,13 +58,17 @@ func getSegment(segmentPath string, partNumber int) string {
 	return fmt.Sprintf("%s/%016d", segmentPath, partNumber)
 }
 
-func parseFullPath(manifest string) (container string, prefix string) {
+func parseFullPath(manifest string) (container string, prefix string, err error) {
+	manifest, err = url.PathUnescape(manifest)
+	if err != nil {
+		return
+	}
 	components := strings.SplitN(manifest, "/", 2)
 	container = components[0]
 	if len(components) > 1 {
 		prefix = components[1]
 	}
-	return container, prefix
+	return container, prefix, nil
 }
 
 func (headers Headers) IsLargeObjectDLO() bool {
@@ -79,14 +85,17 @@ func (headers Headers) IsLargeObject() bool {
 	return headers.IsLargeObjectSLO() || headers.IsLargeObjectDLO()
 }
 
-func (c *Connection) getAllSegments(container string, path string, headers Headers) (string, []Object, error) {
+func (c *Connection) getAllSegments(ctx context.Context, container string, path string, headers Headers) (string, []Object, error) {
 	if manifest, isDLO := headers["X-Object-Manifest"]; isDLO {
-		segmentContainer, segmentPath := parseFullPath(manifest)
-		segments, err := c.getAllDLOSegments(segmentContainer, segmentPath)
+		segmentContainer, segmentPath, err := parseFullPath(manifest)
+		if err != nil {
+			return segmentContainer, nil, err
+		}
+		segments, err := c.getAllDLOSegments(ctx, segmentContainer, segmentPath)
 		return segmentContainer, segments, err
 	}
 	if headers.IsLargeObjectSLO() {
-		return c.getAllSLOSegments(container, path)
+		return c.getAllSLOSegments(ctx, container, path)
 	}
 	return "", nil, NotLargeObject
 }
@@ -108,11 +117,14 @@ type LargeObjectOpts struct {
 }
 
 type LargeObjectFile interface {
-	io.Writer
 	io.Seeker
+	io.Writer
 	io.Closer
+
+	WriteWithContext(ctx context.Context, p []byte) (n int, err error)
+	CloseWithContext(ctx context.Context) error
 	Size() int64
-	Flush() error
+	Flush(ctx context.Context) error
 }
 
 // largeObjectCreate creates a large object at opts.Container, opts.ObjectName.
@@ -120,7 +132,7 @@ type LargeObjectFile interface {
 // opts.Flags can have the following bits set
 //   os.TRUNC  - remove the contents of the large object if it exists
 //   os.APPEND - write at the end of the large object
-func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreateFile, error) {
+func (c *Connection) largeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (*largeObjectCreateFile, error) {
 	var (
 		segmentPath      string
 		segmentContainer string
@@ -135,13 +147,16 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
 		return nil, err
 	}
 
-	if info, headers, err := c.Object(opts.Container, opts.ObjectName); err == nil {
+	if info, headers, err := c.Object(ctx, opts.Container, opts.ObjectName); err == nil {
 		if opts.Flags&os.O_TRUNC != 0 {
-			c.LargeObjectDelete(opts.Container, opts.ObjectName)
+			err := c.LargeObjectDelete(ctx, opts.Container, opts.ObjectName)
+			if err != nil {
+				return nil, err
+			}
 		} else {
 			currentLength = info.Bytes
 			if headers.IsLargeObject() {
-				segmentContainer, segments, err = c.getAllSegments(opts.Container, opts.ObjectName, headers)
+				segmentContainer, segments, err = c.getAllSegments(ctx, opts.Container, opts.ObjectName, headers)
 				if err != nil {
 					return nil, err
 				}
@@ -149,7 +164,7 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
 					segmentPath = gopath.Dir(segments[0].Name)
 				}
 			} else {
-				if err = c.ObjectMove(opts.Container, opts.ObjectName, opts.Container, getSegment(segmentPath, 1)); err != nil {
+				if err = c.ObjectMove(ctx, opts.Container, opts.ObjectName, opts.Container, getSegment(segmentPath, 1)); err != nil {
 					return nil, err
 				}
 				segments = append(segments, info)
@@ -198,15 +213,15 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
 }
 
 // LargeObjectDelete deletes the large object named by container, path
-func (c *Connection) LargeObjectDelete(container string, objectName string) error {
-	_, headers, err := c.Object(container, objectName)
+func (c *Connection) LargeObjectDelete(ctx context.Context, container string, objectName string) error {
+	_, headers, err := c.Object(ctx, container, objectName)
 	if err != nil {
 		return err
 	}
 
 	var objects [][]string
 	if headers.IsLargeObject() {
-		segmentContainer, segments, err := c.getAllSegments(container, objectName, headers)
+		segmentContainer, segments, err := c.getAllSegments(ctx, container, objectName, headers)
 		if err != nil {
 			return err
 		}
@@ -216,13 +231,13 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
 	}
 	objects = append(objects, []string{container, objectName})
 
-	info, err := c.cachedQueryInfo()
+	info, err := c.cachedQueryInfo(ctx)
 	if err == nil && info.SupportsBulkDelete() && len(objects) > 0 {
 		filenames := make([]string, len(objects))
 		for i, obj := range objects {
 			filenames[i] = obj[0] + "/" + obj[1]
 		}
-		_, err = c.doBulkDelete(filenames, nil)
+		_, err = c.doBulkDelete(ctx, filenames, nil)
 		// Don't fail on ObjectNotFound because eventual consistency
 		// makes this situation normal.
 		if err != nil && err != Forbidden && err != ObjectNotFound {
@@ -230,7 +245,7 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
 		}
 	} else {
 		for _, obj := range objects {
-			if err := c.ObjectDelete(obj[0], obj[1]); err != nil {
+			if err := c.ObjectDelete(ctx, obj[0], obj[1]); err != nil {
 				return err
 			}
 		}
@@ -244,13 +259,13 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
 // that have the prefix as indicated by the manifest.
 // If the object is a Static Large Object (SLO), it retrieves the JSON content
 // of the manifest and return all the segments of it.
-func (c *Connection) LargeObjectGetSegments(container string, path string) (string, []Object, error) {
-	_, headers, err := c.Object(container, path)
+func (c *Connection) LargeObjectGetSegments(ctx context.Context, container string, path string) (string, []Object, error) {
+	_, headers, err := c.Object(ctx, container, path)
 	if err != nil {
 		return "", nil, err
 	}
 
-	return c.getAllSegments(container, path, headers)
+	return c.getAllSegments(ctx, container, path, headers)
 }
 
 // Seek sets the offset for the next write operation
@@ -301,11 +316,11 @@ func withLORetry(expectedSize int64, fn func() (Headers, int64, error)) (err err
 	}
 }
 
-func (c *Connection) waitForSegmentsToShowUp(container, objectName string, expectedSize int64) (err error) {
+func (c *Connection) waitForSegmentsToShowUp(ctx context.Context, container, objectName string, expectedSize int64) (err error) {
 	err = withLORetry(expectedSize, func() (Headers, int64, error) {
 		var info Object
 		var headers Headers
-		info, headers, err = c.objectBase(container, objectName)
+		info, headers, err = c.objectBase(ctx, container, objectName)
 		if err != nil {
 			return headers, 0, err
 		}
@@ -314,8 +329,11 @@ func (c *Connection) waitForSegmentsToShowUp(container, objectName string, expec
 	return
 }
 
-// Write satisfies the io.Writer interface
 func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
+	return file.WriteWithContext(context.Background(), buf)
+}
+
+func (file *largeObjectCreateFile) WriteWithContext(ctx context.Context, buf []byte) (int, error) {
 	var sz int64
 	var relativeFilePos int
 	writeSegmentIdx := 0
@@ -329,7 +347,7 @@ func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
 	}
 	sizeToWrite := len(buf)
 	for offset := 0; offset < sizeToWrite; {
-		newSegment, n, err := file.writeSegment(buf[offset:], writeSegmentIdx, relativeFilePos)
+		newSegment, n, err := file.writeSegment(ctx, buf[offset:], writeSegmentIdx, relativeFilePos)
 		if err != nil {
 			return 0, err
 		}
@@ -350,7 +368,7 @@ func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
 	return sizeToWrite, nil
 }
 
-func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int, relativeFilePos int) (*Object, int, error) {
+func (file *largeObjectCreateFile) writeSegment(ctx context.Context, buf []byte, writeSegmentIdx int, relativeFilePos int) (obj *Object, n int, err error) {
 	var (
 		readers         []io.Reader
 		existingSegment *Object
@@ -366,11 +384,16 @@ func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int,
 		if relativeFilePos > 0 {
 			headers := make(Headers)
 			headers["Range"] = "bytes=0-" + strconv.FormatInt(int64(relativeFilePos-1), 10)
-			existingSegmentReader, _, err := file.conn.ObjectOpen(file.segmentContainer, segmentName, true, headers)
+			existingSegmentReader, _, err := file.conn.ObjectOpen(ctx, file.segmentContainer, segmentName, true, headers)
 			if err != nil {
 				return nil, 0, err
 			}
-			defer existingSegmentReader.Close()
+			defer func() {
+				closeErr := existingSegmentReader.Close()
+				if closeErr != nil {
+					err = closeErr
+				}
+			}()
 			sizeToRead -= relativeFilePos
 			segmentSize += relativeFilePos
 			readers = []io.Reader{existingSegmentReader}
@@ -384,16 +407,21 @@ func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int,
 	if existingSegment != nil && segmentSize < int(existingSegment.Bytes) {
 		headers := make(Headers)
 		headers["Range"] = "bytes=" + strconv.FormatInt(int64(segmentSize), 10) + "-"
-		tailSegmentReader, _, err := file.conn.ObjectOpen(file.segmentContainer, segmentName, true, headers)
+		tailSegmentReader, _, err := file.conn.ObjectOpen(ctx, file.segmentContainer, segmentName, true, headers)
 		if err != nil {
 			return nil, 0, err
 		}
-		defer tailSegmentReader.Close()
+		defer func() {
+			closeErr := tailSegmentReader.Close()
+			if closeErr != nil {
+				err = closeErr
+			}
+		}()
 		segmentSize = int(existingSegment.Bytes)
 		readers = append(readers, tailSegmentReader)
 	}
 	segmentReader := io.MultiReader(readers...)
-	headers, err := file.conn.ObjectPut(file.segmentContainer, segmentName, segmentReader, true, "", file.contentType, nil)
+	headers, err := file.conn.ObjectPut(ctx, file.segmentContainer, segmentName, segmentReader, true, "", file.contentType, nil)
 	if err != nil {
 		return nil, 0, err
 	}
@@ -416,11 +444,19 @@ type bufferedLargeObjectFile struct {
 }
 
 func (blo *bufferedLargeObjectFile) Close() error {
+	return blo.CloseWithContext(context.Background())
+}
+
+func (blo *bufferedLargeObjectFile) CloseWithContext(ctx context.Context) error {
 	err := blo.bw.Flush()
 	if err != nil {
 		return err
 	}
-	return blo.LargeObjectFile.Close()
+	return blo.LargeObjectFile.CloseWithContext(ctx)
+}
+
+func (blo *bufferedLargeObjectFile) WriteWithContext(_ context.Context, p []byte) (n int, err error) {
+	return blo.Write(p)
 }
 
 func (blo *bufferedLargeObjectFile) Write(p []byte) (n int, err error) {
@@ -439,10 +475,10 @@ func (blo *bufferedLargeObjectFile) Size() int64 {
 	return blo.LargeObjectFile.Size() + int64(blo.bw.Buffered())
 }
 
-func (blo *bufferedLargeObjectFile) Flush() error {
+func (blo *bufferedLargeObjectFile) Flush(ctx context.Context) error {
 	err := blo.bw.Flush()
 	if err != nil {
 		return err
 	}
-	return blo.LargeObjectFile.Flush()
+	return blo.LargeObjectFile.Flush(ctx)
 }
diff --git a/rs/rs.go b/rs/rs.go
index 34ee15a..ae9e5ac 100644
--- a/rs/rs.go
+++ b/rs/rs.go
@@ -1,11 +1,12 @@
 package rs
 
 import (
+	"context"
 	"errors"
 	"net/http"
 	"strconv"
 
-	"github.com/ncw/swift"
+	"github.com/ncw/swift/v2"
 )
 
 // RsConnection is a RackSpace specific wrapper to the core swift library which
@@ -16,7 +17,7 @@ type RsConnection struct {
 }
 
 // manage is similar to the swift storage method, but uses the CDN Management URL for CDN specific calls.
-func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers swift.Headers, err error) {
+func (c *RsConnection) manage(ctx context.Context, p swift.RequestOpts) (resp *http.Response, headers swift.Headers, err error) {
 	p.OnReAuth = func() (string, error) {
 		if c.cdnUrl == "" {
 			c.cdnUrl = c.Auth.CdnUrl()
@@ -32,7 +33,7 @@ func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers
 			return nil, nil, err
 		}
 	}
-	return c.Connection.Call(c.cdnUrl, p)
+	return c.Connection.Call(ctx, c.cdnUrl, p)
 }
 
 // ContainerCDNEnable enables a container for public CDN usage.
@@ -40,13 +41,13 @@ func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers
 // Change the default TTL of 259200 seconds (72 hours) by passing in an integer value.
 //
 // This method can be called again to change the TTL.
-func (c *RsConnection) ContainerCDNEnable(container string, ttl int) (swift.Headers, error) {
+func (c *RsConnection) ContainerCDNEnable(ctx context.Context, container string, ttl int) (swift.Headers, error) {
 	h := swift.Headers{"X-CDN-Enabled": "true"}
 	if ttl > 0 {
 		h["X-TTL"] = strconv.Itoa(ttl)
 	}
 
-	_, headers, err := c.manage(swift.RequestOpts{
+	_, headers, err := c.manage(ctx, swift.RequestOpts{
 		Container:  container,
 		Operation:  "PUT",
 		ErrorMap:   swift.ContainerErrorMap,
@@ -57,10 +58,10 @@ func (c *RsConnection) ContainerCDNEnable(container string, ttl int) (swift.Head
 }
 
 // ContainerCDNDisable disables CDN access to a container.
-func (c *RsConnection) ContainerCDNDisable(container string) error {
+func (c *RsConnection) ContainerCDNDisable(ctx context.Context, container string) error {
 	h := swift.Headers{"X-CDN-Enabled": "false"}
 
-	_, _, err := c.manage(swift.RequestOpts{
+	_, _, err := c.manage(ctx, swift.RequestOpts{
 		Container:  container,
 		Operation:  "PUT",
 		ErrorMap:   swift.ContainerErrorMap,
@@ -71,8 +72,8 @@ func (c *RsConnection) ContainerCDNDisable(container string) error {
 }
 
 // ContainerCDNMeta returns the CDN metadata for a container.
-func (c *RsConnection) ContainerCDNMeta(container string) (swift.Headers, error) {
-	_, headers, err := c.manage(swift.RequestOpts{
+func (c *RsConnection) ContainerCDNMeta(ctx context.Context, container string) (swift.Headers, error) {
+	_, headers, err := c.manage(ctx, swift.RequestOpts{
 		Container:  container,
 		Operation:  "HEAD",
 		ErrorMap:   swift.ContainerErrorMap,
diff --git a/rs/rs_test.go b/rs/rs_test.go
index 7420515..9667ee3 100644
--- a/rs/rs_test.go
+++ b/rs/rs_test.go
@@ -2,10 +2,11 @@
 package rs_test
 
 import (
+	"context"
 	"os"
 	"testing"
 
-	"github.com/ncw/swift/rs"
+	"github.com/ncw/swift/v2/rs"
 )
 
 var (
@@ -32,7 +33,7 @@ func TestAuthenticate(t *testing.T) {
 	c.UserName = UserName
 	c.ApiKey = ApiKey
 	c.AuthUrl = AuthUrl
-	err := c.Authenticate()
+	err := c.Authenticate(context.Background())
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -43,14 +44,14 @@ func TestAuthenticate(t *testing.T) {
 
 // Setup
 func TestContainerCreate(t *testing.T) {
-	err := c.ContainerCreate(CONTAINER, nil)
+	err := c.ContainerCreate(context.Background(), CONTAINER, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestCDNEnable(t *testing.T) {
-	headers, err := c.ContainerCDNEnable(CONTAINER, 0)
+	headers, err := c.ContainerCDNEnable(context.Background(), CONTAINER, 0)
 	if err != nil {
 		t.Error(err)
 	}
@@ -64,14 +65,14 @@ func TestOnReAuth(t *testing.T) {
 	c2.UserName = c.UserName
 	c2.ApiKey = c.ApiKey
 	c2.AuthUrl = c.AuthUrl
-	_, err := c2.ContainerCDNEnable(CONTAINER, 0)
+	_, err := c2.ContainerCDNEnable(context.Background(), CONTAINER, 0)
 	if err != nil {
 		t.Fatalf("Failed to reauthenticate: %v", err)
 	}
 }
 
 func TestCDNMeta(t *testing.T) {
-	headers, err := c.ContainerCDNMeta(CONTAINER)
+	headers, err := c.ContainerCDNMeta(context.Background(), CONTAINER)
 	if err != nil {
 		t.Error(err)
 	}
@@ -81,7 +82,7 @@ func TestCDNMeta(t *testing.T) {
 }
 
 func TestCDNDisable(t *testing.T) {
-	err := c.ContainerCDNDisable(CONTAINER) // files stick in CDN until TTL expires
+	err := c.ContainerCDNDisable(context.Background(), CONTAINER) // files stick in CDN until TTL expires
 	if err != nil {
 		t.Error(err)
 	}
@@ -89,7 +90,7 @@ func TestCDNDisable(t *testing.T) {
 
 // Teardown
 func TestContainerDelete(t *testing.T) {
-	err := c.ContainerDelete(CONTAINER)
+	err := c.ContainerDelete(context.Background(), CONTAINER)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/slo.go b/slo.go
index 6a10ddf..acbf5b1 100644
--- a/slo.go
+++ b/slo.go
@@ -2,6 +2,7 @@ package swift
 
 import (
 	"bytes"
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -37,8 +38,8 @@ type swiftSegment struct {
 // an object which satisfies io.Writer, io.Seeker, io.Closer and
 // io.ReaderFrom.  The flags are as passed to the largeObjectCreate
 // method.
-func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeObjectFile, error) {
-	info, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectCreateFile(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
+	info, err := c.cachedQueryInfo(ctx)
 	if err != nil || !info.SupportsSLO() {
 		return nil, SLONotSupported
 	}
@@ -46,7 +47,7 @@ func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeOb
 	if realMinChunkSize > opts.MinChunkSize {
 		opts.MinChunkSize = realMinChunkSize
 	}
-	lo, err := c.largeObjectCreate(opts)
+	lo, err := c.largeObjectCreate(ctx, opts)
 	if err != nil {
 		return nil, err
 	}
@@ -58,32 +59,32 @@ func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeOb
 // StaticLargeObjectCreate creates or truncates an existing static
 // large object returning a writeable object. This sets opts.Flags to
 // an appropriate value before calling StaticLargeObjectCreateFile
-func (c *Connection) StaticLargeObjectCreate(opts *LargeObjectOpts) (LargeObjectFile, error) {
+func (c *Connection) StaticLargeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
 	opts.Flags = os.O_TRUNC | os.O_CREATE
-	return c.StaticLargeObjectCreateFile(opts)
+	return c.StaticLargeObjectCreateFile(ctx, opts)
 }
 
 // StaticLargeObjectDelete deletes a static large object and all of its segments.
-func (c *Connection) StaticLargeObjectDelete(container string, path string) error {
-	info, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectDelete(ctx context.Context, container string, path string) error {
+	info, err := c.cachedQueryInfo(ctx)
 	if err != nil || !info.SupportsSLO() {
 		return SLONotSupported
 	}
-	return c.LargeObjectDelete(container, path)
+	return c.LargeObjectDelete(ctx, container, path)
 }
 
 // StaticLargeObjectMove moves a static large object from srcContainer, srcObjectName to dstContainer, dstObjectName
-func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
-	swiftInfo, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
+	swiftInfo, err := c.cachedQueryInfo(ctx)
 	if err != nil || !swiftInfo.SupportsSLO() {
 		return SLONotSupported
 	}
-	info, headers, err := c.Object(srcContainer, srcObjectName)
+	info, headers, err := c.Object(ctx, srcContainer, srcObjectName)
 	if err != nil {
 		return err
 	}
 
-	container, segments, err := c.getAllSegments(srcContainer, srcObjectName, headers)
+	container, segments, err := c.getAllSegments(ctx, srcContainer, srcObjectName, headers)
 	if err != nil {
 		return err
 	}
@@ -91,11 +92,11 @@ func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName st
 	//copy only metadata during move (other headers might not be safe for copying)
 	headers = headers.ObjectMetadata().ObjectHeaders()
 
-	if err := c.createSLOManifest(dstContainer, dstObjectName, info.ContentType, container, segments, headers); err != nil {
+	if err := c.createSLOManifest(ctx, dstContainer, dstObjectName, info.ContentType, container, segments, headers); err != nil {
 		return err
 	}
 
-	if err := c.ObjectDelete(srcContainer, srcObjectName); err != nil {
+	if err := c.ObjectDelete(ctx, srcContainer, srcObjectName); err != nil {
 		return err
 	}
 
@@ -103,7 +104,7 @@ func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName st
 }
 
 // createSLOManifest creates a static large object manifest
-func (c *Connection) createSLOManifest(container string, path string, contentType string, segmentContainer string, segments []Object, h Headers) error {
+func (c *Connection) createSLOManifest(ctx context.Context, container string, path string, contentType string, segmentContainer string, segments []Object, h Headers) error {
 	sloSegments := make([]swiftSegment, len(segments))
 	for i, segment := range segments {
 		sloSegments[i].Path = fmt.Sprintf("%s/%s", segmentContainer, segment.Name)
@@ -118,7 +119,7 @@ func (c *Connection) createSLOManifest(container string, path string, contentTyp
 
 	values := url.Values{}
 	values.Set("multipart-manifest", "put")
-	if _, err := c.objectPut(container, path, bytes.NewBuffer(content), false, "", contentType, h, values); err != nil {
+	if _, err := c.objectPut(ctx, container, path, bytes.NewBuffer(content), false, "", contentType, h, values); err != nil {
 		return err
 	}
 
@@ -126,17 +127,21 @@ func (c *Connection) createSLOManifest(container string, path string, contentTyp
 }
 
 func (file *StaticLargeObjectCreateFile) Close() error {
-	return file.Flush()
+	return file.CloseWithContext(context.Background())
 }
 
-func (file *StaticLargeObjectCreateFile) Flush() error {
-	if err := file.conn.createSLOManifest(file.container, file.objectName, file.contentType, file.segmentContainer, file.segments, file.headers); err != nil {
+func (file *StaticLargeObjectCreateFile) CloseWithContext(ctx context.Context) error {
+	return file.Flush(ctx)
+}
+
+func (file *StaticLargeObjectCreateFile) Flush(ctx context.Context) error {
+	if err := file.conn.createSLOManifest(ctx, file.container, file.objectName, file.contentType, file.segmentContainer, file.segments, file.headers); err != nil {
 		return err
 	}
-	return file.conn.waitForSegmentsToShowUp(file.container, file.objectName, file.Size())
+	return file.conn.waitForSegmentsToShowUp(ctx, file.container, file.objectName, file.Size())
 }
 
-func (c *Connection) getAllSLOSegments(container, path string) (string, []Object, error) {
+func (c *Connection) getAllSLOSegments(ctx context.Context, container, path string) (string, []Object, error) {
 	var (
 		segmentList      []swiftSegment
 		segments         []Object
@@ -147,7 +152,7 @@ func (c *Connection) getAllSLOSegments(container, path string) (string, []Object
 	values := url.Values{}
 	values.Set("multipart-manifest", "get")
 
-	file, _, err := c.objectOpen(container, path, true, nil, values)
+	file, _, err := c.objectOpen(ctx, container, path, true, nil, values)
 	if err != nil {
 		return "", nil, err
 	}
@@ -157,9 +162,15 @@ func (c *Connection) getAllSLOSegments(container, path string) (string, []Object
 		return "", nil, err
 	}
 
-	json.Unmarshal(content, &segmentList)
+	err = json.Unmarshal(content, &segmentList)
+	if err != nil {
+		return "", nil, err
+	}
 	for _, segment := range segmentList {
-		segmentContainer, segPath = parseFullPath(segment.Name[1:])
+		segmentContainer, segPath, err = parseFullPath(segment.Name[1:])
+		if err != nil {
+			return "", nil, err
+		}
 		segments = append(segments, Object{
 			Name:  segPath,
 			Bytes: segment.Bytes,
diff --git a/swift.go b/swift.go
index 59b68ce..c9357ee 100644
--- a/swift.go
+++ b/swift.go
@@ -3,6 +3,7 @@ package swift
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/hmac"
 	"crypto/md5"
 	"crypto/sha1"
@@ -31,8 +32,7 @@ const (
 	UploadTarGzip       = "tar.gz"              // Data format specifier for Connection.BulkUpload().
 	UploadTarBzip2      = "tar.bz2"             // Data format specifier for Connection.BulkUpload().
 	allContainersLimit  = 10000                 // Number of containers to fetch at once
-	allObjectsLimit     = 10000                 // Number objects to fetch at once
-	allObjectsChanLimit = 1000                  // ...when fetching to a channel
+	allObjectsChanLimit = 1000                  // Number objects to fetch when fetching to a channel
 )
 
 // ObjectType is the type of the swift object, regular, static large,
@@ -72,7 +72,7 @@ const (
 //	import (
 //		"appengine/urlfetch"
 //		"fmt"
-//		"github.com/ncw/swift"
+//		"github.com/ncw/swift/v2"
 //	)
 //
 //	func handler(w http.ResponseWriter, r *http.Request) {
@@ -125,9 +125,12 @@ type Connection struct {
 	Expires    time.Time // time the token expires, may be Zero if unknown
 	client     *http.Client
 	Auth       Authenticator `json:"-" xml:"-"` // the current authenticator
-	authLock   *sync.Mutex   // lock when R/W StorageUrl, AuthToken, Auth
+	authLock   sync.Mutex    // lock when R/W StorageUrl, AuthToken, Auth
 	// swiftInfo is filled after QueryInfo is called
 	swiftInfo SwiftInfo
+	// Workarounds for non-compliant servers that don't always return opts.Limit items per page
+	FetchUntilEmptyPage       bool // Always fetch unless we received an empty page
+	PartialPageFetchThreshold int  // Fetch if the current page is this percentage of opts.Limit
 }
 
 // setFromEnv reads the value that param points to (it must be a
@@ -386,7 +389,13 @@ func (c *Connection) parseHeaders(resp *http.Response, errorMap errorMap) error
 func readHeaders(resp *http.Response) Headers {
 	headers := Headers{}
 	for key, values := range resp.Header {
-		headers[key] = values[0]
+		// ETag header may be double quoted if following RFC 7232
+		// https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+		if key == "Etag" {
+			headers[key] = strings.Trim(values[0], "\"")
+		} else {
+			headers[key] = values[0]
+		}
 	}
 	return headers
 }
@@ -415,7 +424,6 @@ func (c *Connection) doTimeoutRequest(timer *time.Timer, req *http.Request) (*ht
 		cancelRequest(c.Transport, req)
 		return nil, TimeoutError
 	}
-	panic("unreachable") // For Go 1.0
 }
 
 // Set defaults for any unset values
@@ -457,19 +465,16 @@ func (c *Connection) setDefaults() {
 //
 // If you don't call it before calling one of the connection methods
 // then it will be called for you on the first access.
-func (c *Connection) Authenticate() (err error) {
-	if c.authLock == nil {
-		c.authLock = &sync.Mutex{}
-	}
+func (c *Connection) Authenticate(ctx context.Context) (err error) {
 	c.authLock.Lock()
 	defer c.authLock.Unlock()
-	return c.authenticate()
+	return c.authenticate(ctx)
 }
 
 // Internal implementation of Authenticate
 //
 // Call with authLock held
-func (c *Connection) authenticate() (err error) {
+func (c *Connection) authenticate(ctx context.Context) (err error) {
 	c.setDefaults()
 
 	// Flush the keepalives connection - if we are
@@ -486,7 +491,7 @@ func (c *Connection) authenticate() (err error) {
 	retries := 1
 again:
 	var req *http.Request
-	req, err = c.Auth.Request(c)
+	req, err = c.Auth.Request(ctx, c)
 	if err != nil {
 		return
 	}
@@ -514,7 +519,7 @@ again:
 			}
 			return
 		}
-		err = c.Auth.Response(resp)
+		err = c.Auth.Response(ctx, resp)
 		if err != nil {
 			return
 		}
@@ -541,12 +546,12 @@ again:
 // Get an authToken and url
 //
 // The Url may be updated if it needed to authenticate using the OnReAuth function
-func (c *Connection) getUrlAndAuthToken(targetUrlIn string, OnReAuth func() (string, error)) (targetUrlOut, authToken string, err error) {
+func (c *Connection) getUrlAndAuthToken(ctx context.Context, targetUrlIn string, OnReAuth func() (string, error)) (targetUrlOut, authToken string, err error) {
 	c.authLock.Lock()
 	defer c.authLock.Unlock()
 	targetUrlOut = targetUrlIn
 	if !c.authenticated() {
-		err = c.authenticate()
+		err = c.authenticate(ctx)
 		if err != nil {
 			return
 		}
@@ -583,9 +588,6 @@ func (c *Connection) UnAuthenticate() {
 //
 // Doesn't actually check the credentials against the server.
 func (c *Connection) Authenticated() bool {
-	if c.authLock == nil {
-		c.authLock = &sync.Mutex{}
-	}
 	c.authLock.Lock()
 	defer c.authLock.Unlock()
 	return c.authenticated()
@@ -629,13 +631,21 @@ func (i SwiftInfo) SLOMinSegmentSize() int64 {
 }
 
 // Discover Swift configuration by doing a request against /info
-func (c *Connection) QueryInfo() (infos SwiftInfo, err error) {
-	infoUrl, err := url.Parse(c.StorageUrl)
+func (c *Connection) QueryInfo(ctx context.Context) (infos SwiftInfo, err error) {
+	storageUrl, err := c.GetStorageUrl(ctx)
+	if err != nil {
+		return nil, err
+	}
+	infoUrl, err := url.Parse(storageUrl)
 	if err != nil {
 		return nil, err
 	}
 	infoUrl.Path = path.Join(infoUrl.Path, "..", "..", "info")
-	resp, err := c.client.Get(infoUrl.String())
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, infoUrl.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+	resp, err := c.client.Do(req)
 	if err == nil {
 		if resp.StatusCode != http.StatusOK {
 			drainAndClose(resp.Body, nil)
@@ -652,12 +662,12 @@ func (c *Connection) QueryInfo() (infos SwiftInfo, err error) {
 	return nil, err
 }
 
-func (c *Connection) cachedQueryInfo() (infos SwiftInfo, err error) {
+func (c *Connection) cachedQueryInfo(ctx context.Context) (infos SwiftInfo, err error) {
 	c.authLock.Lock()
 	infos = c.swiftInfo
 	c.authLock.Unlock()
 	if infos == nil {
-		infos, err = c.QueryInfo()
+		infos, err = c.QueryInfo(ctx)
 		if err != nil {
 			return
 		}
@@ -700,7 +710,7 @@ type RequestOpts struct {
 // receives a 401 error which means the token has expired
 //
 // This method is exported so extensions can call it.
-func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response, headers Headers, err error) {
+func (c *Connection) Call(ctx context.Context, targetUrl string, p RequestOpts) (resp *http.Response, headers Headers, err error) {
 	c.authLock.Lock()
 	c.setDefaults()
 	c.authLock.Unlock()
@@ -711,7 +721,7 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
 	var req *http.Request
 	for {
 		var authToken string
-		if targetUrl, authToken, err = c.getUrlAndAuthToken(targetUrl, p.OnReAuth); err != nil {
+		if targetUrl, authToken, err = c.getUrlAndAuthToken(ctx, targetUrl, p.OnReAuth); err != nil {
 			return //authentication failure
 		}
 		var URL *url.URL
@@ -734,7 +744,7 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
 		if reader != nil {
 			reader = newWatchdogReader(reader, c.Timeout, timer)
 		}
-		req, err = http.NewRequest(p.Operation, URL.String(), reader)
+		req, err = http.NewRequestWithContext(ctx, p.Operation, URL.String(), reader)
 		if err != nil {
 			return
 		}
@@ -809,14 +819,14 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
 //
 // This will Authenticate if necessary, and re-authenticate if it
 // receives a 401 error which means the token has expired
-func (c *Connection) storage(p RequestOpts) (resp *http.Response, headers Headers, err error) {
+func (c *Connection) storage(ctx context.Context, p RequestOpts) (resp *http.Response, headers Headers, err error) {
 	p.OnReAuth = func() (string, error) {
 		return c.StorageUrl, nil
 	}
 	c.authLock.Lock()
 	url := c.StorageUrl
 	c.authLock.Unlock()
-	return c.Call(url, p)
+	return c.Call(ctx, url, p)
 }
 
 // readLines reads the response into an array of strings.
@@ -887,9 +897,9 @@ func (opts *ContainersOpts) parse() (url.Values, Headers) {
 }
 
 // ContainerNames returns a slice of names of containers in this account.
-func (c *Connection) ContainerNames(opts *ContainersOpts) ([]string, error) {
+func (c *Connection) ContainerNames(ctx context.Context, opts *ContainersOpts) ([]string, error) {
 	v, h := opts.parse()
-	resp, _, err := c.storage(RequestOpts{
+	resp, _, err := c.storage(ctx, RequestOpts{
 		Operation:  "GET",
 		Parameters: v,
 		ErrorMap:   ContainerErrorMap,
@@ -911,10 +921,10 @@ type Container struct {
 
 // Containers returns a slice of structures with full information as
 // described in Container.
-func (c *Connection) Containers(opts *ContainersOpts) ([]Container, error) {
+func (c *Connection) Containers(ctx context.Context, opts *ContainersOpts) ([]Container, error) {
 	v, h := opts.parse()
 	v.Set("format", "json")
-	resp, _, err := c.storage(RequestOpts{
+	resp, _, err := c.storage(ctx, RequestOpts{
 		Operation:  "GET",
 		Parameters: v,
 		ErrorMap:   ContainerErrorMap,
@@ -942,21 +952,36 @@ func containersAllOpts(opts *ContainersOpts) *ContainersOpts {
 	return &newOpts
 }
 
+func (c *Connection) isLastPage(length int, limit int) bool {
+	if c.FetchUntilEmptyPage && length > 0 {
+		return false
+	}
+	if c.PartialPageFetchThreshold > 0 && limit > 0 {
+		if length*100/limit >= c.PartialPageFetchThreshold {
+			return false
+		}
+	}
+	if length < limit {
+		return true
+	}
+	return false
+}
+
 // ContainersAll is like Containers but it returns all the Containers
 //
 // It calls Containers multiple times using the Marker parameter
 //
 // It has a default Limit parameter but you may pass in your own
-func (c *Connection) ContainersAll(opts *ContainersOpts) ([]Container, error) {
+func (c *Connection) ContainersAll(ctx context.Context, opts *ContainersOpts) ([]Container, error) {
 	opts = containersAllOpts(opts)
 	containers := make([]Container, 0)
 	for {
-		newContainers, err := c.Containers(opts)
+		newContainers, err := c.Containers(ctx, opts)
 		if err != nil {
 			return nil, err
 		}
 		containers = append(containers, newContainers...)
-		if len(newContainers) < opts.Limit {
+		if c.isLastPage(len(newContainers), opts.Limit) {
 			break
 		}
 		opts.Marker = newContainers[len(newContainers)-1].Name
@@ -969,16 +994,16 @@ func (c *Connection) ContainersAll(opts *ContainersOpts) ([]Container, error) {
 // It calls ContainerNames multiple times using the Marker parameter
 //
 // It has a default Limit parameter but you may pass in your own
-func (c *Connection) ContainerNamesAll(opts *ContainersOpts) ([]string, error) {
+func (c *Connection) ContainerNamesAll(ctx context.Context, opts *ContainersOpts) ([]string, error) {
 	opts = containersAllOpts(opts)
 	containers := make([]string, 0)
 	for {
-		newContainers, err := c.ContainerNames(opts)
+		newContainers, err := c.ContainerNames(ctx, opts)
 		if err != nil {
 			return nil, err
 		}
 		containers = append(containers, newContainers...)
-		if len(newContainers) < opts.Limit {
+		if c.isLastPage(len(newContainers), opts.Limit) {
 			break
 		}
 		opts.Marker = newContainers[len(newContainers)-1]
@@ -1029,9 +1054,9 @@ func (opts *ObjectsOpts) parse() (url.Values, Headers) {
 }
 
 // ObjectNames returns a slice of names of objects in a given container.
-func (c *Connection) ObjectNames(container string, opts *ObjectsOpts) ([]string, error) {
+func (c *Connection) ObjectNames(ctx context.Context, container string, opts *ObjectsOpts) ([]string, error) {
 	v, h := opts.parse()
-	resp, _, err := c.storage(RequestOpts{
+	resp, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "GET",
 		Parameters: v,
@@ -1065,10 +1090,10 @@ type Object struct {
 // with ContentType 'application/directory'.  These are not real
 // objects but represent directories of objects which haven't had an
 // object created for them.
-func (c *Connection) Objects(container string, opts *ObjectsOpts) ([]Object, error) {
+func (c *Connection) Objects(ctx context.Context, container string, opts *ObjectsOpts) ([]Object, error) {
 	v, h := opts.parse()
 	v.Set("format", "json")
-	resp, _, err := c.storage(RequestOpts{
+	resp, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "GET",
 		Parameters: v,
@@ -1130,10 +1155,10 @@ func objectsAllOpts(opts *ObjectsOpts, Limit int) *ObjectsOpts {
 
 // A closure defined by the caller to iterate through all objects
 //
-// Call Objects or ObjectNames from here with the *ObjectOpts passed in
+// Call Objects or ObjectNames from here with the context.Context and *ObjectOpts passed in
 //
 // Do whatever is required with the results then return them
-type ObjectsWalkFn func(*ObjectsOpts) (interface{}, error)
+type ObjectsWalkFn func(context.Context, *ObjectsOpts) (interface{}, error)
 
 // ObjectsWalk is uses to iterate through all the objects in chunks as
 // returned by Objects or ObjectNames using the Marker and Limit
@@ -1145,10 +1170,10 @@ type ObjectsWalkFn func(*ObjectsOpts) (interface{}, error)
 // Errors will be returned from this function
 //
 // It has a default Limit parameter but you may pass in your own
-func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn ObjectsWalkFn) error {
+func (c *Connection) ObjectsWalk(ctx context.Context, container string, opts *ObjectsOpts, walkFn ObjectsWalkFn) error {
 	opts = objectsAllOpts(opts, allObjectsChanLimit)
 	for {
-		objects, err := walkFn(opts)
+		objects, err := walkFn(ctx, opts)
 		if err != nil {
 			return err
 		}
@@ -1168,7 +1193,7 @@ func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn Obj
 		default:
 			panic("Unknown type returned to ObjectsWalk")
 		}
-		if n < opts.Limit {
+		if c.isLastPage(n, opts.Limit) {
 			break
 		}
 		opts.Marker = last
@@ -1179,10 +1204,10 @@ func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn Obj
 // ObjectsAll is like Objects but it returns an unlimited number of Objects in a slice
 //
 // It calls Objects multiple times using the Marker parameter
-func (c *Connection) ObjectsAll(container string, opts *ObjectsOpts) ([]Object, error) {
+func (c *Connection) ObjectsAll(ctx context.Context, container string, opts *ObjectsOpts) ([]Object, error) {
 	objects := make([]Object, 0)
-	err := c.ObjectsWalk(container, opts, func(opts *ObjectsOpts) (interface{}, error) {
-		newObjects, err := c.Objects(container, opts)
+	err := c.ObjectsWalk(ctx, container, opts, func(ctx context.Context, opts *ObjectsOpts) (interface{}, error) {
+		newObjects, err := c.Objects(ctx, container, opts)
 		if err == nil {
 			objects = append(objects, newObjects...)
 		}
@@ -1197,10 +1222,10 @@ func (c *Connection) ObjectsAll(container string, opts *ObjectsOpts) ([]Object,
 // reset unless KeepMarker is set
 //
 // It has a default Limit parameter but you may pass in your own
-func (c *Connection) ObjectNamesAll(container string, opts *ObjectsOpts) ([]string, error) {
+func (c *Connection) ObjectNamesAll(ctx context.Context, container string, opts *ObjectsOpts) ([]string, error) {
 	objects := make([]string, 0)
-	err := c.ObjectsWalk(container, opts, func(opts *ObjectsOpts) (interface{}, error) {
-		newObjects, err := c.ObjectNames(container, opts)
+	err := c.ObjectsWalk(ctx, container, opts, func(ctx context.Context, opts *ObjectsOpts) (interface{}, error) {
+		newObjects, err := c.ObjectNames(ctx, container, opts)
 		if err == nil {
 			objects = append(objects, newObjects...)
 		}
@@ -1227,9 +1252,9 @@ func getInt64FromHeader(resp *http.Response, header string) (result int64, err e
 }
 
 // Account returns info about the account in an Account struct.
-func (c *Connection) Account() (info Account, headers Headers, err error) {
+func (c *Connection) Account(ctx context.Context) (info Account, headers Headers, err error) {
 	var resp *http.Response
-	resp, headers, err = c.storage(RequestOpts{
+	resp, headers, err = c.storage(ctx, RequestOpts{
 		Operation:  "HEAD",
 		ErrorMap:   ContainerErrorMap,
 		NoResponse: true,
@@ -1262,8 +1287,8 @@ func (c *Connection) Account() (info Account, headers Headers, err error) {
 // Add or update keys by mentioning them in the Headers.
 //
 // Remove keys by setting them to an empty string.
-func (c *Connection) AccountUpdate(h Headers) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) AccountUpdate(ctx context.Context, h Headers) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Operation:  "POST",
 		ErrorMap:   ContainerErrorMap,
 		NoResponse: true,
@@ -1277,8 +1302,8 @@ func (c *Connection) AccountUpdate(h Headers) error {
 // If you don't want to add Headers just pass in nil
 //
 // No error is returned if it already exists but the metadata if any will be updated.
-func (c *Connection) ContainerCreate(container string, h Headers) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerCreate(ctx context.Context, container string, h Headers) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "PUT",
 		ErrorMap:   ContainerErrorMap,
@@ -1291,8 +1316,8 @@ func (c *Connection) ContainerCreate(container string, h Headers) error {
 // ContainerDelete deletes a container.
 //
 // May return ContainerDoesNotExist or ContainerNotEmpty
-func (c *Connection) ContainerDelete(container string) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerDelete(ctx context.Context, container string) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "DELETE",
 		ErrorMap:   ContainerErrorMap,
@@ -1303,9 +1328,9 @@ func (c *Connection) ContainerDelete(container string) error {
 
 // Container returns info about a single container including any
 // metadata in the headers.
-func (c *Connection) Container(container string) (info Container, headers Headers, err error) {
+func (c *Connection) Container(ctx context.Context, container string) (info Container, headers Headers, err error) {
 	var resp *http.Response
-	resp, headers, err = c.storage(RequestOpts{
+	resp, headers, err = c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "HEAD",
 		ErrorMap:   ContainerErrorMap,
@@ -1332,8 +1357,8 @@ func (c *Connection) Container(container string) (info Container, headers Header
 // Remove keys by setting them to an empty string.
 //
 // Container metadata can only be read with Container() not with Containers().
-func (c *Connection) ContainerUpdate(container string, h Headers) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerUpdate(ctx context.Context, container string, h Headers) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		Operation:  "POST",
 		ErrorMap:   ContainerErrorMap,
@@ -1469,7 +1494,7 @@ func objectPutHeaders(objectName string, checkHash *bool, Hash string, contentTy
 //
 // If contentType is set it will be used, otherwise one will be
 // guessed from objectName using mime.TypeByExtension
-func (c *Connection) ObjectCreate(container string, objectName string, checkHash bool, Hash string, contentType string, h Headers) (file *ObjectCreateFile, err error) {
+func (c *Connection) ObjectCreate(ctx context.Context, container string, objectName string, checkHash bool, Hash string, contentType string, h Headers) (file *ObjectCreateFile, err error) {
 	extraHeaders := objectPutHeaders(objectName, &checkHash, Hash, contentType, h)
 	pipeReader, pipeWriter := io.Pipe()
 	file = &ObjectCreateFile{
@@ -1490,15 +1515,15 @@ func (c *Connection) ObjectCreate(container string, objectName string, checkHash
 			NoResponse: true,
 			ErrorMap:   objectErrorMap,
 		}
-		file.resp, file.headers, file.err = c.storage(opts)
+		file.resp, file.headers, file.err = c.storage(ctx, opts)
 		// Signal finished
-		pipeReader.Close()
+		_ = pipeReader.Close()
 		close(file.done)
 	}()
 	return
 }
 
-func (c *Connection) ObjectSymlinkCreate(container string, symlink string, targetAccount string, targetContainer string, targetObject string, targetEtag string) (headers Headers, err error) {
+func (c *Connection) ObjectSymlinkCreate(ctx context.Context, container string, symlink string, targetAccount string, targetContainer string, targetObject string, targetEtag string) (headers Headers, err error) {
 
 	EMPTY_MD5 := "d41d8cd98f00b204e9800998ecf8427e"
 	symHeaders := Headers{}
@@ -1510,18 +1535,18 @@ func (c *Connection) ObjectSymlinkCreate(container string, symlink string, targe
 		symHeaders["X-Symlink-Target-Etag"] = targetEtag
 	}
 	symHeaders["X-Symlink-Target"] = fmt.Sprintf("%s/%s", targetContainer, targetObject)
-	_, err = c.ObjectPut(container, symlink, contents, true, EMPTY_MD5, "application/symlink", symHeaders)
+	_, err = c.ObjectPut(ctx, container, symlink, contents, true, EMPTY_MD5, "application/symlink", symHeaders)
 	return
 }
 
-func (c *Connection) objectPut(container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers, parameters url.Values) (headers Headers, err error) {
+func (c *Connection) objectPut(ctx context.Context, container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers, parameters url.Values) (headers Headers, err error) {
 	extraHeaders := objectPutHeaders(objectName, &checkHash, Hash, contentType, h)
 	hash := md5.New()
 	var body io.Reader = contents
 	if checkHash {
 		body = io.TeeReader(contents, hash)
 	}
-	_, headers, err = c.storage(RequestOpts{
+	_, headers, err = c.storage(ctx, RequestOpts{
 		Container:  container,
 		ObjectName: objectName,
 		Operation:  "PUT",
@@ -1566,27 +1591,31 @@ func (c *Connection) objectPut(container string, objectName string, contents io.
 //
 // If contentType is set it will be used, otherwise one will be
 // guessed from objectName using mime.TypeByExtension
-func (c *Connection) ObjectPut(container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers) (headers Headers, err error) {
-	return c.objectPut(container, objectName, contents, checkHash, Hash, contentType, h, nil)
+func (c *Connection) ObjectPut(ctx context.Context, container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers) (headers Headers, err error) {
+	return c.objectPut(ctx, container, objectName, contents, checkHash, Hash, contentType, h, nil)
 }
 
 // ObjectPutBytes creates an object from a []byte in a container.
 //
 // This is a simplified interface which checks the MD5.
-func (c *Connection) ObjectPutBytes(container string, objectName string, contents []byte, contentType string) (err error) {
+func (c *Connection) ObjectPutBytes(ctx context.Context, container string, objectName string, contents []byte, contentType string) (err error) {
 	buf := bytes.NewBuffer(contents)
 	h := Headers{"Content-Length": strconv.Itoa(len(contents))}
-	_, err = c.ObjectPut(container, objectName, buf, true, "", contentType, h)
+	hash := md5.Sum(contents)
+	hashStr := hex.EncodeToString(hash[:])
+	_, err = c.ObjectPut(ctx, container, objectName, buf, true, hashStr, contentType, h)
 	return
 }
 
 // ObjectPutString creates an object from a string in a container.
 //
 // This is a simplified interface which checks the MD5
-func (c *Connection) ObjectPutString(container string, objectName string, contents string, contentType string) (err error) {
+func (c *Connection) ObjectPutString(ctx context.Context, container string, objectName string, contents string, contentType string) (err error) {
 	buf := strings.NewReader(contents)
 	h := Headers{"Content-Length": strconv.Itoa(len(contents))}
-	_, err = c.ObjectPut(container, objectName, buf, true, "", contentType, h)
+	hash := md5.Sum([]byte(contents))
+	hashStr := hex.EncodeToString(hash[:])
+	_, err = c.ObjectPut(ctx, container, objectName, buf, true, hashStr, contentType, h)
 	return
 }
 
@@ -1636,7 +1665,7 @@ func (file *ObjectOpenFile) Read(p []byte) (n int, err error) {
 // unlike os.File
 //
 // Seek(0, 1) will return the current file pointer.
-func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err error) {
+func (file *ObjectOpenFile) Seek(ctx context.Context, offset int64, whence int) (newPos int64, err error) {
 	file.overSeeked = false
 	switch whence {
 	case 0: // relative to start
@@ -1674,7 +1703,7 @@ func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err er
 	} else {
 		delete(file.headers, "Range")
 	}
-	newFile, _, err := file.connection.ObjectOpen(file.container, file.objectName, false, file.headers)
+	newFile, _, err := file.connection.ObjectOpen(ctx, file.container, file.objectName, false, file.headers)
 	if err != nil {
 		return
 	}
@@ -1688,9 +1717,9 @@ func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err er
 
 // Length gets the objects content length either from a cached copy or
 // from the server.
-func (file *ObjectOpenFile) Length() (int64, error) {
+func (file *ObjectOpenFile) Length(ctx context.Context) (int64, error) {
 	if !file.lengthOk {
-		info, _, err := file.connection.Object(file.container, file.objectName)
+		info, _, err := file.connection.Object(ctx, file.container, file.objectName)
 		file.length = info.Bytes
 		file.lengthOk = (err == nil)
 		return file.length, err
@@ -1711,7 +1740,9 @@ func (file *ObjectOpenFile) Close() (err error) {
 
 	// Check the MD5 sum if requested
 	if file.checkHash {
-		receivedMd5 := strings.ToLower(file.resp.Header.Get("Etag"))
+		// ETag header may be double quoted if following RFC 7232
+		// https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+		receivedMd5 := strings.ToLower(strings.Trim(file.resp.Header.Get("Etag"), "\""))
 		calculatedMd5 := fmt.Sprintf("%x", file.hash.Sum(nil))
 		if receivedMd5 != calculatedMd5 {
 			err = ObjectCorrupted
@@ -1727,11 +1758,7 @@ func (file *ObjectOpenFile) Close() (err error) {
 	return
 }
 
-// Check it satisfies the interfaces
-var _ io.ReadCloser = &ObjectOpenFile{}
-var _ io.Seeker = &ObjectOpenFile{}
-
-func (c *Connection) objectOpenBase(container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
+func (c *Connection) objectOpenBase(ctx context.Context, container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
 	var resp *http.Response
 	opts := RequestOpts{
 		Container:  container,
@@ -1741,7 +1768,7 @@ func (c *Connection) objectOpenBase(container string, objectName string, checkHa
 		Headers:    h,
 		Parameters: parameters,
 	}
-	resp, headers, err = c.storage(opts)
+	resp, headers, err = c.storage(ctx, opts)
 	if err != nil {
 		return
 	}
@@ -1771,9 +1798,9 @@ func (c *Connection) objectOpenBase(container string, objectName string, checkHa
 	return
 }
 
-func (c *Connection) objectOpen(container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
+func (c *Connection) objectOpen(ctx context.Context, container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
 	err = withLORetry(0, func() (Headers, int64, error) {
-		file, headers, err = c.objectOpenBase(container, objectName, checkHash, h, parameters)
+		file, headers, err = c.objectOpenBase(ctx, container, objectName, checkHash, h, parameters)
 		if err != nil {
 			return headers, 0, err
 		}
@@ -1805,8 +1832,8 @@ func (c *Connection) objectOpen(container string, objectName string, checkHash b
 // you will need to download everything in the manifest separately.
 //
 // headers["Content-Type"] will give the content type if desired.
-func (c *Connection) ObjectOpen(container string, objectName string, checkHash bool, h Headers) (file *ObjectOpenFile, headers Headers, err error) {
-	return c.objectOpen(container, objectName, checkHash, h, nil)
+func (c *Connection) ObjectOpen(ctx context.Context, container string, objectName string, checkHash bool, h Headers) (file *ObjectOpenFile, headers Headers, err error) {
+	return c.objectOpen(ctx, container, objectName, checkHash, h, nil)
 }
 
 // ObjectGet gets the object into the io.Writer contents.
@@ -1818,8 +1845,8 @@ func (c *Connection) ObjectOpen(container string, objectName string, checkHash b
 // server.  If it is wrong then it will return ObjectCorrupted.
 //
 // headers["Content-Type"] will give the content type if desired.
-func (c *Connection) ObjectGet(container string, objectName string, contents io.Writer, checkHash bool, h Headers) (headers Headers, err error) {
-	file, headers, err := c.ObjectOpen(container, objectName, checkHash, h)
+func (c *Connection) ObjectGet(ctx context.Context, container string, objectName string, contents io.Writer, checkHash bool, h Headers) (headers Headers, err error) {
+	file, headers, err := c.ObjectOpen(ctx, container, objectName, checkHash, h)
 	if err != nil {
 		return
 	}
@@ -1831,9 +1858,9 @@ func (c *Connection) ObjectGet(container string, objectName string, contents io.
 // ObjectGetBytes returns an object as a []byte.
 //
 // This is a simplified interface which checks the MD5
-func (c *Connection) ObjectGetBytes(container string, objectName string) (contents []byte, err error) {
+func (c *Connection) ObjectGetBytes(ctx context.Context, container string, objectName string) (contents []byte, err error) {
 	var buf bytes.Buffer
-	_, err = c.ObjectGet(container, objectName, &buf, true, nil)
+	_, err = c.ObjectGet(ctx, container, objectName, &buf, true, nil)
 	contents = buf.Bytes()
 	return
 }
@@ -1841,9 +1868,9 @@ func (c *Connection) ObjectGetBytes(container string, objectName string) (conten
 // ObjectGetString returns an object as a string.
 //
 // This is a simplified interface which checks the MD5
-func (c *Connection) ObjectGetString(container string, objectName string) (contents string, err error) {
+func (c *Connection) ObjectGetString(ctx context.Context, container string, objectName string) (contents string, err error) {
 	var buf bytes.Buffer
-	_, err = c.ObjectGet(container, objectName, &buf, true, nil)
+	_, err = c.ObjectGet(ctx, container, objectName, &buf, true, nil)
 	contents = buf.String()
 	return
 }
@@ -1851,8 +1878,8 @@ func (c *Connection) ObjectGetString(container string, objectName string) (conte
 // ObjectDelete deletes the object.
 //
 // May return ObjectNotFound if the object isn't found
-func (c *Connection) ObjectDelete(container string, objectName string) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) ObjectDelete(ctx context.Context, container string, objectName string) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		ObjectName: objectName,
 		Operation:  "DELETE",
@@ -1863,8 +1890,15 @@ func (c *Connection) ObjectDelete(container string, objectName string) error {
 
 // ObjectTempUrl returns a temporary URL for an object
 func (c *Connection) ObjectTempUrl(container string, objectName string, secretKey string, method string, expires time.Time) string {
+	c.authLock.Lock()
+	storageUrl := c.StorageUrl
+	c.authLock.Unlock()
+	if storageUrl == "" {
+		return "" // Cannot do better without changing the interface
+	}
+
 	mac := hmac.New(sha1.New, []byte(secretKey))
-	prefix, _ := url.Parse(c.StorageUrl)
+	prefix, _ := url.Parse(storageUrl)
 	body := fmt.Sprintf("%s\n%d\n%s/%s/%s", method, expires.Unix(), prefix.Path, container, objectName)
 	mac.Write([]byte(body))
 	sig := hex.EncodeToString(mac.Sum(nil))
@@ -1909,7 +1943,7 @@ type BulkDeleteResult struct {
 	Headers        Headers          // Response HTTP headers.
 }
 
-func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDeleteResult, err error) {
+func (c *Connection) doBulkDelete(ctx context.Context, objects []string, h Headers) (result BulkDeleteResult, err error) {
 	var buffer bytes.Buffer
 	for _, s := range objects {
 		u := url.URL{Path: s}
@@ -1923,7 +1957,7 @@ func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDelet
 	for key, value := range h {
 		extraHeaders[key] = value
 	}
-	resp, headers, err := c.storage(RequestOpts{
+	resp, headers, err := c.storage(ctx, RequestOpts{
 		Operation:  "DELETE",
 		Parameters: url.Values{"bulk-delete": []string{"1"}},
 		Headers:    extraHeaders,
@@ -1967,8 +2001,8 @@ func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDelet
 // See also:
 // * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-bulk-delete.html
 // * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Bulk_Delete-d1e2338.html
-func (c *Connection) BulkDelete(container string, objectNames []string) (result BulkDeleteResult, err error) {
-	return c.BulkDeleteHeaders(container, objectNames, nil)
+func (c *Connection) BulkDelete(ctx context.Context, container string, objectNames []string) (result BulkDeleteResult, err error) {
+	return c.BulkDeleteHeaders(ctx, container, objectNames, nil)
 }
 
 // BulkDeleteHeaders deletes multiple objectNames from container in one operation.
@@ -1979,7 +2013,7 @@ func (c *Connection) BulkDelete(container string, objectNames []string) (result
 // See also:
 // * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-bulk-delete.html
 // * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Bulk_Delete-d1e2338.html
-func (c *Connection) BulkDeleteHeaders(container string, objectNames []string, h Headers) (result BulkDeleteResult, err error) {
+func (c *Connection) BulkDeleteHeaders(ctx context.Context, container string, objectNames []string, h Headers) (result BulkDeleteResult, err error) {
 	if len(objectNames) == 0 {
 		result.Errors = make(map[string]error)
 		return
@@ -1988,7 +2022,7 @@ func (c *Connection) BulkDeleteHeaders(container string, objectNames []string, h
 	for i, name := range objectNames {
 		fullPaths[i] = fmt.Sprintf("/%s/%s", container, name)
 	}
-	return c.doBulkDelete(fullPaths, h)
+	return c.doBulkDelete(ctx, fullPaths, h)
 }
 
 // BulkUploadResult stores results of BulkUpload().
@@ -2021,14 +2055,14 @@ type BulkUploadResult struct {
 // See also:
 // * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-extract-archive.html
 // * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html
-func (c *Connection) BulkUpload(uploadPath string, dataStream io.Reader, format string, h Headers) (result BulkUploadResult, err error) {
+func (c *Connection) BulkUpload(ctx context.Context, uploadPath string, dataStream io.Reader, format string, h Headers) (result BulkUploadResult, err error) {
 	extraHeaders := Headers{"Accept": "application/json"}
 	for key, value := range h {
 		extraHeaders[key] = value
 	}
 	// The following code abuses Container parameter intentionally.
 	// The best fix might be to rename Container to UploadPath.
-	resp, headers, err := c.storage(RequestOpts{
+	resp, headers, err := c.storage(ctx, RequestOpts{
 		Container:  uploadPath,
 		Operation:  "PUT",
 		Parameters: url.Values{"extract-archive": []string{format}},
@@ -2073,9 +2107,9 @@ func (c *Connection) BulkUpload(uploadPath string, dataStream io.Reader, format
 // May return ObjectNotFound.
 //
 // Use headers.ObjectMetadata() to read the metadata in the Headers.
-func (c *Connection) Object(container string, objectName string) (info Object, headers Headers, err error) {
+func (c *Connection) Object(ctx context.Context, container string, objectName string) (info Object, headers Headers, err error) {
 	err = withLORetry(0, func() (Headers, int64, error) {
-		info, headers, err = c.objectBase(container, objectName)
+		info, headers, err = c.objectBase(ctx, container, objectName)
 		if err != nil {
 			return headers, 0, err
 		}
@@ -2084,9 +2118,9 @@ func (c *Connection) Object(container string, objectName string) (info Object, h
 	return
 }
 
-func (c *Connection) objectBase(container string, objectName string) (info Object, headers Headers, err error) {
+func (c *Connection) objectBase(ctx context.Context, container string, objectName string) (info Object, headers Headers, err error) {
 	var resp *http.Response
-	resp, headers, err = c.storage(RequestOpts{
+	resp, headers, err = c.storage(ctx, RequestOpts{
 		Container:  container,
 		ObjectName: objectName,
 		Operation:  "HEAD",
@@ -2124,7 +2158,9 @@ func (c *Connection) objectBase(container string, objectName string) (info Objec
 		}
 	}
 
-	info.Hash = resp.Header.Get("Etag")
+	// ETag header may be double quoted if following RFC 7232
+	// https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+	info.Hash = strings.Trim(resp.Header.Get("Etag"), "\"")
 	if resp.Header.Get("X-Object-Manifest") != "" {
 		info.ObjectType = DynamicLargeObjectType
 	} else if resp.Header.Get("X-Static-Large-Object") != "" {
@@ -2156,8 +2192,8 @@ func (c *Connection) objectBase(container string, objectName string) (info Objec
 // other headers such as Content-Type or CORS headers.
 //
 // May return ObjectNotFound.
-func (c *Connection) ObjectUpdate(container string, objectName string, h Headers) error {
-	_, _, err := c.storage(RequestOpts{
+func (c *Connection) ObjectUpdate(ctx context.Context, container string, objectName string, h Headers) error {
+	_, _, err := c.storage(ctx, RequestOpts{
 		Container:  container,
 		ObjectName: objectName,
 		Operation:  "POST",
@@ -2186,7 +2222,7 @@ func urlPathEscape(in string) string {
 //
 // You can use this to copy an object to itself - this is the only way
 // to update the content type of an object.
-func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string, h Headers) (headers Headers, err error) {
+func (c *Connection) ObjectCopy(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string, h Headers) (headers Headers, err error) {
 	// Meta stuff
 	extraHeaders := map[string]string{
 		"Destination": urlPathEscape(dstContainer + "/" + dstObjectName),
@@ -2194,7 +2230,7 @@ func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstCo
 	for key, value := range h {
 		extraHeaders[key] = value
 	}
-	_, headers, err = c.storage(RequestOpts{
+	_, headers, err = c.storage(ctx, RequestOpts{
 		Container:  srcContainer,
 		ObjectName: srcObjectName,
 		Operation:  "COPY",
@@ -2212,12 +2248,12 @@ func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstCo
 // All metadata is preserved.
 //
 // The destination container must exist before the copy.
-func (c *Connection) ObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) (err error) {
-	_, err = c.ObjectCopy(srcContainer, srcObjectName, dstContainer, dstObjectName, nil)
+func (c *Connection) ObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) (err error) {
+	_, err = c.ObjectCopy(ctx, srcContainer, srcObjectName, dstContainer, dstObjectName, nil)
 	if err != nil {
 		return
 	}
-	return c.ObjectDelete(srcContainer, srcObjectName)
+	return c.ObjectDelete(ctx, srcContainer, srcObjectName)
 }
 
 // ObjectUpdateContentType updates the content type of an object
@@ -2225,9 +2261,9 @@ func (c *Connection) ObjectMove(srcContainer string, srcObjectName string, dstCo
 // This is a convenience method which calls ObjectCopy
 //
 // All other metadata is preserved.
-func (c *Connection) ObjectUpdateContentType(container string, objectName string, contentType string) (err error) {
+func (c *Connection) ObjectUpdateContentType(ctx context.Context, container string, objectName string, contentType string) (err error) {
 	h := Headers{"Content-Type": contentType}
-	_, err = c.ObjectCopy(container, objectName, container, objectName, h)
+	_, err = c.ObjectCopy(ctx, container, objectName, container, objectName, h)
 	return
 }
 
@@ -2239,14 +2275,14 @@ func (c *Connection) ObjectUpdateContentType(container string, objectName string
 //
 // If the server doesn't support versioning then it will return
 // Forbidden however it will have created both the containers at that point.
-func (c *Connection) VersionContainerCreate(current, version string) error {
-	if err := c.ContainerCreate(version, nil); err != nil {
+func (c *Connection) VersionContainerCreate(ctx context.Context, current, version string) error {
+	if err := c.ContainerCreate(ctx, version, nil); err != nil {
 		return err
 	}
-	if err := c.ContainerCreate(current, nil); err != nil {
+	if err := c.ContainerCreate(ctx, current, nil); err != nil {
 		return err
 	}
-	if err := c.VersionEnable(current, version); err != nil {
+	if err := c.VersionEnable(ctx, current, version); err != nil {
 		return err
 	}
 	return nil
@@ -2255,13 +2291,13 @@ func (c *Connection) VersionContainerCreate(current, version string) error {
 // VersionEnable enables versioning on the current container with version as the tracking container.
 //
 // May return Forbidden if this isn't supported by the server
-func (c *Connection) VersionEnable(current, version string) error {
+func (c *Connection) VersionEnable(ctx context.Context, current, version string) error {
 	h := Headers{"X-Versions-Location": version}
-	if err := c.ContainerUpdate(current, h); err != nil {
+	if err := c.ContainerUpdate(ctx, current, h); err != nil {
 		return err
 	}
 	// Check to see if the header was set properly
-	_, headers, err := c.Container(current)
+	_, headers, err := c.Container(ctx, current)
 	if err != nil {
 		return err
 	}
@@ -2273,9 +2309,9 @@ func (c *Connection) VersionEnable(current, version string) error {
 }
 
 // VersionDisable disables versioning on the current container.
-func (c *Connection) VersionDisable(current string) error {
+func (c *Connection) VersionDisable(ctx context.Context, current string) error {
 	h := Headers{"X-Versions-Location": ""}
-	if err := c.ContainerUpdate(current, h); err != nil {
+	if err := c.ContainerUpdate(ctx, current, h); err != nil {
 		return err
 	}
 	return nil
@@ -2284,10 +2320,25 @@ func (c *Connection) VersionDisable(current string) error {
 // VersionObjectList returns a list of older versions of the object.
 //
 // Objects are returned in the format <length><object_name>/<timestamp>
-func (c *Connection) VersionObjectList(version, object string) ([]string, error) {
+func (c *Connection) VersionObjectList(ctx context.Context, version, object string) ([]string, error) {
 	opts := &ObjectsOpts{
 		// <3-character zero-padded hexadecimal character length><object name>/
 		Prefix: fmt.Sprintf("%03x", len(object)) + object + "/",
 	}
-	return c.ObjectNames(version, opts)
+	return c.ObjectNames(ctx, version, opts)
+}
+
+// GetStorageUrl returns Swift storage URL.
+func (c *Connection) GetStorageUrl(ctx context.Context) (string, error) {
+	c.authLock.Lock()
+	defer c.authLock.Unlock()
+
+	// Return cached URL even if authentication has expired
+	if c.StorageUrl == "" {
+		err := c.authenticate(ctx)
+		if err != nil {
+			return "", err
+		}
+	}
+	return c.StorageUrl, nil
 }
diff --git a/swift_internal_test.go b/swift_internal_test.go
index 894fd8f..cddf739 100644
--- a/swift_internal_test.go
+++ b/swift_internal_test.go
@@ -6,6 +6,7 @@
 package swift
 
 import (
+	"context"
 	"fmt"
 	"io"
 	"net"
@@ -149,13 +150,15 @@ func handle(w http.ResponseWriter, r *http.Request) {
 func NewSwiftServer() *SwiftServer {
 	server := &SwiftServer{}
 	http.HandleFunc("/", handle)
-	go http.ListenAndServe(TEST_ADDRESS, nil)
+	go func() {
+		_ = http.ListenAndServe(TEST_ADDRESS, nil)
+	}()
 	fmt.Print("Waiting for server to start ")
 	for {
 		fmt.Print(".")
 		conn, err := net.Dial("tcp", TEST_ADDRESS)
 		if err == nil {
-			conn.Close()
+			_ = conn.Close()
 			fmt.Println(" Started")
 			break
 		}
@@ -316,7 +319,8 @@ func TestInternalAuthenticate(t *testing.T) {
 	}).Url("/v1.0")
 	defer server.Finished()
 
-	err := c.Authenticate()
+	ctx := context.Background()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -336,7 +340,7 @@ func TestInternalAuthenticateDenied(t *testing.T) {
 	server.AddCheck(t).Error(401, "DENIED")
 	defer server.Finished()
 	c.UnAuthenticate()
-	err := c.Authenticate()
+	err := c.Authenticate(context.Background())
 	if err != AuthorizationFailed {
 		t.Fatal("Expecting AuthorizationFailed", err)
 	}
@@ -351,7 +355,8 @@ func TestInternalAuthenticateBad(t *testing.T) {
 		"X-Storage-Url": PROXY_URL,
 	})
 	defer server.Finished()
-	err := c.Authenticate()
+	ctx := context.Background()
+	err := c.Authenticate(ctx)
 	checkError(t, err, 0, "Response didn't have storage url and auth token")
 	if c.Authenticated() {
 		t.Fatal("Expecting not authenticated")
@@ -360,14 +365,14 @@ func TestInternalAuthenticateBad(t *testing.T) {
 	server.AddCheck(t).Out(Headers{
 		"X-Auth-Token": AUTH_TOKEN,
 	})
-	err = c.Authenticate()
+	err = c.Authenticate(ctx)
 	checkError(t, err, 0, "Response didn't have storage url and auth token")
 	if c.Authenticated() {
 		t.Fatal("Expecting not authenticated")
 	}
 
 	server.AddCheck(t)
-	err = c.Authenticate()
+	err = c.Authenticate(ctx)
 	checkError(t, err, 0, "Response didn't have storage url and auth token")
 	if c.Authenticated() {
 		t.Fatal("Expecting not authenticated")
@@ -377,7 +382,7 @@ func TestInternalAuthenticateBad(t *testing.T) {
 		"X-Storage-Url": PROXY_URL,
 		"X-Auth-Token":  AUTH_TOKEN,
 	})
-	err = c.Authenticate()
+	err = c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -391,7 +396,7 @@ func testContainerNames(t *testing.T, rx string, expected []string) {
 		"User-Agent":   DefaultUserAgent,
 		"X-Auth-Token": AUTH_TOKEN,
 	}).Tx(rx).Url("/proxy")
-	containers, err := c.ContainerNames(nil)
+	containers, err := c.ContainerNames(context.Background(), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -420,7 +425,10 @@ func TestInternalObjectPutBytes(t *testing.T) {
 		"Content-Type":   "text/plain",
 	}).Rx("12345")
 	defer server.Finished()
-	c.ObjectPutBytes("container", "object", []byte{'1', '2', '3', '4', '5'}, "text/plain")
+	err := c.ObjectPutBytes(context.Background(), "container", "object", []byte{'1', '2', '3', '4', '5'}, "text/plain")
+	if err != nil {
+		t.Fatal("ObjectPutBytes", err)
+	}
 }
 
 func TestInternalObjectPutString(t *testing.T) {
@@ -431,20 +439,23 @@ func TestInternalObjectPutString(t *testing.T) {
 		"Content-Type":   "text/plain",
 	}).Rx("12345")
 	defer server.Finished()
-	c.ObjectPutString("container", "object", "12345", "text/plain")
+	err := c.ObjectPutString(context.Background(), "container", "object", "12345", "text/plain")
+	if err != nil {
+		t.Fatal(err)
+	}
 }
 
 func TestSetFromEnv(t *testing.T) {
 	// String
 	s := ""
 
-	os.Setenv("POTATO", "")
+	_ = os.Setenv("POTATO", "")
 	err := setFromEnv(&s, "POTATO")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	os.Setenv("POTATO", "this is a test")
+	_ = os.Setenv("POTATO", "this is a test")
 	err = setFromEnv(&s, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -453,7 +464,7 @@ func TestSetFromEnv(t *testing.T) {
 		t.Fatal("incorrect", s)
 	}
 
-	os.Setenv("POTATO", "new")
+	_ = os.Setenv("POTATO", "new")
 	err = setFromEnv(&s, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -465,7 +476,7 @@ func TestSetFromEnv(t *testing.T) {
 	// Integer
 	i := 0
 
-	os.Setenv("POTATO", "42")
+	_ = os.Setenv("POTATO", "42")
 	err = setFromEnv(&i, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -474,7 +485,7 @@ func TestSetFromEnv(t *testing.T) {
 		t.Fatal("incorrect", i)
 	}
 
-	os.Setenv("POTATO", "43")
+	_ = os.Setenv("POTATO", "43")
 	err = setFromEnv(&i, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -484,7 +495,7 @@ func TestSetFromEnv(t *testing.T) {
 	}
 
 	i = 0
-	os.Setenv("POTATO", "not a number")
+	_ = os.Setenv("POTATO", "not a number")
 	err = setFromEnv(&i, "POTATO")
 	if err == nil {
 		t.Fatal("expecting error but didn't get one")
@@ -492,7 +503,7 @@ func TestSetFromEnv(t *testing.T) {
 
 	// bool
 	var b bool
-	os.Setenv("POTATO", "1")
+	_ = os.Setenv("POTATO", "1")
 	err = setFromEnv(&b, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -503,7 +514,7 @@ func TestSetFromEnv(t *testing.T) {
 
 	// time.Duration
 	var dt time.Duration
-	os.Setenv("POTATO", "5s")
+	_ = os.Setenv("POTATO", "5s")
 	err = setFromEnv(&dt, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -514,7 +525,7 @@ func TestSetFromEnv(t *testing.T) {
 
 	// EndpointType
 	var e EndpointType
-	os.Setenv("POTATO", "internal")
+	_ = os.Setenv("POTATO", "internal")
 	err = setFromEnv(&e, "POTATO")
 	if err != nil {
 		t.Fatal(err)
@@ -530,13 +541,13 @@ func TestSetFromEnv(t *testing.T) {
 		t.Fatal("expecting error")
 	}
 
-	os.Setenv("POTATO", "")
+	_ = os.Setenv("POTATO", "")
 }
 
 func TestApplyEnvironment(t *testing.T) {
 	// We've tested all the setting logic above, so just do a quick test here
 	c := new(Connection)
-	os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "100s")
+	_ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "100s")
 	err := c.ApplyEnvironment()
 	if err != nil {
 		t.Fatal(err)
@@ -546,7 +557,7 @@ func TestApplyEnvironment(t *testing.T) {
 	}
 
 	c.ConnectTimeout = 0
-	os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "parse error")
+	_ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "parse error")
 	err = c.ApplyEnvironment()
 	if err == nil {
 		t.Fatal("expecting error")
@@ -555,7 +566,7 @@ func TestApplyEnvironment(t *testing.T) {
 		t.Fatal("timeout incorrect", c.ConnectTimeout)
 	}
 
-	os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "")
+	_ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "")
 }
 
 func TestApplyEnvironmentAll(t *testing.T) {
@@ -605,7 +616,7 @@ func TestApplyEnvironmentAll(t *testing.T) {
 			item := &items[i]
 			if item.phase == phase {
 				item.oldValue = os.Getenv(item.name) // save old value
-				os.Setenv(item.name, item.value)     // set new value
+				_ = os.Setenv(item.name, item.value) // set new value
 			}
 		}
 
@@ -621,9 +632,140 @@ func TestApplyEnvironmentAll(t *testing.T) {
 				if !reflect.DeepEqual(item.want, got) {
 					t.Errorf("%s: %v != %v", item.name, item.want, got)
 				}
-				os.Setenv(item.name, item.oldValue) // restore old value
+				_ = os.Setenv(item.name, item.oldValue) // restore old value
 			}
 		}
 	}
 
 }
+
+func TestIsLastPage(t *testing.T) {
+	conn := &Connection{}
+	testPaging(t, conn, []pagingTest{
+		{
+			length:   0,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   850,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   950,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   1000,
+			limit:    1000,
+			expected: false,
+		},
+		// For completeness
+		{
+			length:   0,
+			limit:    0,
+			expected: false,
+		},
+		{
+			length:   2000,
+			limit:    1000,
+			expected: false,
+		},
+	})
+
+}
+
+func TestFetchUntilEmptyPageWorkaround(t *testing.T) {
+	conn := &Connection{
+		FetchUntilEmptyPage: true,
+	}
+	testPaging(t, conn, []pagingTest{
+		{
+			length:   0,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   850,
+			limit:    1000,
+			expected: false,
+		},
+		{
+			length:   950,
+			limit:    1000,
+			expected: false,
+		},
+		{
+			length:   1000,
+			limit:    1000,
+			expected: false,
+		},
+		// For completeness
+		{
+			length:   0,
+			limit:    0,
+			expected: false,
+		},
+		{
+			length:   2000,
+			limit:    1000,
+			expected: false,
+		},
+	})
+}
+
+func TestPartialPageFetchThreshold(t *testing.T) {
+	conn := &Connection{
+		PartialPageFetchThreshold: 90,
+	}
+	testPaging(t, conn, []pagingTest{
+		{
+			length:   0,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   850,
+			limit:    1000,
+			expected: true,
+		},
+		{
+			length:   950,
+			limit:    1000,
+			expected: false,
+		},
+		{
+			length:   1000,
+			limit:    1000,
+			expected: false,
+		},
+		// For completeness
+		{
+			length:   0,
+			limit:    0,
+			expected: false,
+		},
+		{
+			length:   2000,
+			limit:    1000,
+			expected: false,
+		},
+	})
+
+}
+
+type pagingTest struct {
+	length   int
+	limit    int
+	expected bool
+}
+
+func testPaging(t *testing.T, conn *Connection, testCases []pagingTest) {
+	for _, tCase := range testCases {
+		if actual := conn.isLastPage(tCase.length, tCase.limit); actual != tCase.expected {
+			t.Fatalf("isLastPage(%d, %d) returned %t, expected %t", tCase.length, tCase.limit, actual, tCase.expected)
+		}
+	}
+}
diff --git a/swift_test.go b/swift_test.go
index 6c10935..f75ad8e 100644
--- a/swift_test.go
+++ b/swift_test.go
@@ -15,6 +15,7 @@ package swift_test
 import (
 	"archive/tar"
 	"bytes"
+	"context"
 	"crypto/md5"
 	"crypto/rand"
 	"crypto/tls"
@@ -33,8 +34,8 @@ import (
 	"testing"
 	"time"
 
-	"github.com/ncw/swift"
-	"github.com/ncw/swift/swifttest"
+	"github.com/ncw/swift/v2"
+	"github.com/ncw/swift/v2/swifttest"
 )
 
 var (
@@ -144,8 +145,9 @@ func makeConnection(t *testing.T) (*swift.Connection, func()) {
 }
 
 func makeConnectionAuth(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnection(t)
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -153,32 +155,35 @@ func makeConnectionAuth(t *testing.T) (*swift.Connection, func()) {
 }
 
 func makeConnectionWithContainer(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
-	err := c.ContainerCreate(CONTAINER, m1.ContainerHeaders())
+	err := c.ContainerCreate(ctx, CONTAINER, m1.ContainerHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
 	return c, func() {
-		c.ContainerDelete(CONTAINER)
+		_ = c.ContainerDelete(ctx, CONTAINER)
 		rollback()
 	}
 }
 
 func makeConnectionWithObject(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
-	err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+	err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	return c, func() {
-		c.ObjectDelete(CONTAINER, OBJECT)
+		_ = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		rollback()
 	}
 }
 
 func makeConnectionWithObjectHeaders(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
-	err := c.ObjectUpdate(CONTAINER, OBJECT, m1.ObjectHeaders())
+	err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m1.ObjectHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -186,11 +191,12 @@ func makeConnectionWithObjectHeaders(t *testing.T) (*swift.Connection, func()) {
 }
 
 func makeConnectionWithVersionsContainer(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
-	err := c.VersionContainerCreate(CURRENT_CONTAINER, VERSIONS_CONTAINER)
+	err := c.VersionContainerCreate(ctx, CURRENT_CONTAINER, VERSIONS_CONTAINER)
 	newRollback := func() {
-		c.ContainerDelete(CURRENT_CONTAINER)
-		c.ContainerDelete(VERSIONS_CONTAINER)
+		_ = c.ContainerDelete(ctx, CURRENT_CONTAINER)
+		_ = c.ContainerDelete(ctx, VERSIONS_CONTAINER)
 		rollback()
 	}
 	if err != nil {
@@ -204,34 +210,36 @@ func makeConnectionWithVersionsContainer(t *testing.T) (*swift.Connection, func(
 }
 
 func makeConnectionWithVersionsObject(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithVersionsContainer(t)
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
 		t.Fatal(err)
 	}
 	// Version 2
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
 		t.Fatal(err)
 	}
 	// Version 3
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
 		t.Fatal(err)
 	}
 	return c, func() {
 		for i := 0; i < 3; i++ {
-			c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+			_ = c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
 		}
 		rollback()
 	}
 }
 
 func makeConnectionWithSegmentsContainer(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
-	err := c.ContainerCreate(SEGMENTS_CONTAINER, swift.Headers{})
+	err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, swift.Headers{})
 	if err != nil {
 		t.Fatal(err)
 	}
 	return c, func() {
-		err = c.ContainerDelete(SEGMENTS_CONTAINER)
+		err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -240,13 +248,14 @@ func makeConnectionWithSegmentsContainer(t *testing.T) (*swift.Connection, func(
 }
 
 func makeConnectionWithDLO(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	opts := swift.LargeObjectOpts{
 		Container:   CONTAINER,
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreate(&opts)
+	out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -256,24 +265,25 @@ func makeConnectionWithDLO(t *testing.T) (*swift.Connection, func()) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	return c, func() {
-		c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+		_ = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		rollback()
 	}
 }
 
 func makeConnectionWithSLO(t *testing.T) (*swift.Connection, func()) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	opts := swift.LargeObjectOpts{
 		Container:   CONTAINER,
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.StaticLargeObjectCreate(&opts)
+	out, err := c.StaticLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		if err == swift.SLONotSupported {
 			t.Skip("SLO not supported")
@@ -287,12 +297,12 @@ func makeConnectionWithSLO(t *testing.T) (*swift.Connection, func()) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	return c, func() {
-		c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+		_ = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		rollback()
 	}
 }
@@ -303,12 +313,14 @@ func isV3Api() bool {
 }
 
 func getSwinftInfo(t *testing.T) (info swift.SwiftInfo, err error) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	return c.QueryInfo()
+	return c.QueryInfo(ctx)
 }
 
 func TestTransport(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnection(t)
 	defer rollback()
 
@@ -326,7 +338,7 @@ func TestTransport(t *testing.T) {
 
 	c.Transport = tr
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -337,13 +349,14 @@ func TestTransport(t *testing.T) {
 
 // The following Test functions are run in order - this one must come before the others!
 func TestV1V2Authenticate(t *testing.T) {
+	ctx := context.Background()
 	if isV3Api() {
 		return
 	}
 	c, rollback := makeConnection(t)
 	defer rollback()
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -353,6 +366,7 @@ func TestV1V2Authenticate(t *testing.T) {
 }
 
 func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
+	ctx := context.Background()
 	if !isV3Api() {
 		return
 	}
@@ -365,7 +379,7 @@ func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
 	c.TenantId = os.Getenv("SWIFT_TENANT_ID")
 	c.DomainId = ""
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -375,6 +389,7 @@ func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
 }
 
 func TestV3TrustWithTrustId(t *testing.T) {
+	ctx := context.Background()
 	if !isV3Api() {
 		return
 	}
@@ -384,7 +399,7 @@ func TestV3TrustWithTrustId(t *testing.T) {
 
 	c.TrustId = os.Getenv("SWIFT_TRUST_ID")
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -394,6 +409,7 @@ func TestV3TrustWithTrustId(t *testing.T) {
 }
 
 func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
+	ctx := context.Background()
 	if !isV3Api() {
 		return
 	}
@@ -406,7 +422,7 @@ func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
 	c.TenantId = os.Getenv("SWIFT_TENANT_ID")
 	c.DomainId = os.Getenv("SWIFT_API_DOMAIN_ID")
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -416,6 +432,7 @@ func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
 }
 
 func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
+	ctx := context.Background()
 	if !isV3Api() {
 		return
 	}
@@ -428,7 +445,7 @@ func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
 	c.TenantId = ""
 	c.DomainId = ""
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -438,6 +455,7 @@ func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
 }
 
 func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
+	ctx := context.Background()
 	if !isV3Api() {
 		return
 	}
@@ -450,7 +468,7 @@ func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
 	c.TenantId = ""
 	c.DomainId = os.Getenv("SWIFT_API_DOMAIN_ID")
 
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("Auth failed", err)
 	}
@@ -463,6 +481,7 @@ func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
 //
 // Run with -race to test
 func TestAuthenticateRace(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnection(t)
 	defer rollback()
 	var wg sync.WaitGroup
@@ -470,12 +489,12 @@ func TestAuthenticateRace(t *testing.T) {
 		wg.Add(1)
 		go func() {
 			defer wg.Done()
-			err := c.Authenticate()
+			err := c.Authenticate(ctx)
 			if err != nil {
-				t.Fatal("Auth failed", err)
+				t.Error("Auth failed", err)
 			}
 			if !c.Authenticated() {
-				t.Fatal("Not authenticated")
+				t.Error("Not authenticated")
 			}
 		}()
 	}
@@ -484,6 +503,7 @@ func TestAuthenticateRace(t *testing.T) {
 
 // Test a connection can be serialized and unserialized with JSON
 func TestSerializeConnectionJson(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
 	serializedConnection, err := json.Marshal(c)
@@ -498,7 +518,7 @@ func TestSerializeConnectionJson(t *testing.T) {
 	if !c2.Authenticated() {
 		t.Fatal("Should be authenticated")
 	}
-	_, _, err = c2.Account()
+	_, _, err = c2.Account(ctx)
 	if err != nil {
 		t.Fatalf("Failed to use unserialized connection: %v", err)
 	}
@@ -506,6 +526,7 @@ func TestSerializeConnectionJson(t *testing.T) {
 
 // Test a connection can be serialized and unserialized with XML
 func TestSerializeConnectionXml(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
 	serializedConnection, err := xml.Marshal(c)
@@ -520,7 +541,7 @@ func TestSerializeConnectionXml(t *testing.T) {
 	if !c2.Authenticated() {
 		t.Fatal("Should be authenticated")
 	}
-	_, _, err = c2.Account()
+	_, _, err = c2.Account(ctx)
 	if err != nil {
 		t.Fatalf("Failed to use unserialized connection: %v", err)
 	}
@@ -528,19 +549,21 @@ func TestSerializeConnectionXml(t *testing.T) {
 
 // Test the reauthentication logic
 func TestOnReAuth(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
 	c.UnAuthenticate()
-	_, _, err := c.Account()
+	_, _, err := c.Account(ctx)
 	if err != nil {
 		t.Fatalf("Failed to reauthenticate: %v", err)
 	}
 }
 
 func TestAccount(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	info, headers, err := c.Account()
+	info, headers, err := c.Account(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -572,14 +595,15 @@ func compareMaps(t *testing.T, a, b map[string]string) {
 }
 
 func TestAccountUpdate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	err := c.AccountUpdate(m1.AccountHeaders())
+	err := c.AccountUpdate(ctx, m1.AccountHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	_, headers, err := c.Account()
+	_, headers, err := c.Account(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -587,12 +611,12 @@ func TestAccountUpdate(t *testing.T) {
 	delete(m, "temp-url-key") // remove X-Account-Meta-Temp-URL-Key if set
 	compareMaps(t, m, map[string]string{"hello": "1", "potato-salad": "2"})
 
-	err = c.AccountUpdate(m2.AccountHeaders())
+	err = c.AccountUpdate(ctx, m2.AccountHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	_, headers, err = c.Account()
+	_, headers, err = c.Account(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -602,22 +626,24 @@ func TestAccountUpdate(t *testing.T) {
 }
 
 func TestContainerCreate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	err := c.ContainerCreate(CONTAINER, m1.ContainerHeaders())
+	err := c.ContainerCreate(ctx, CONTAINER, m1.ContainerHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = c.ContainerDelete(CONTAINER)
+	err = c.ContainerDelete(ctx, CONTAINER)
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestContainer(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	info, headers, err := c.Container(CONTAINER)
+	info, headers, err := c.Container(ctx, CONTAINER)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -634,13 +660,14 @@ func TestContainer(t *testing.T) {
 }
 
 func TestContainersAll(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	containers1, err := c.ContainersAll(nil)
+	containers1, err := c.ContainersAll(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	containers2, err := c.Containers(nil)
+	containers2, err := c.Containers(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -655,13 +682,14 @@ func TestContainersAll(t *testing.T) {
 }
 
 func TestContainersAllWithLimit(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	containers1, err := c.ContainersAll(&swift.ContainersOpts{Limit: 1})
+	containers1, err := c.ContainersAll(ctx, &swift.ContainersOpts{Limit: 1})
 	if err != nil {
 		t.Fatal(err)
 	}
-	containers2, err := c.Containers(nil)
+	containers2, err := c.Containers(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -676,13 +704,14 @@ func TestContainersAllWithLimit(t *testing.T) {
 }
 
 func TestContainerUpdate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ContainerUpdate(CONTAINER, m2.ContainerHeaders())
+	err := c.ContainerUpdate(ctx, CONTAINER, m2.ContainerHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
-	_, headers, err := c.Container(CONTAINER)
+	_, headers, err := c.Container(ctx, CONTAINER)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -690,9 +719,10 @@ func TestContainerUpdate(t *testing.T) {
 }
 
 func TestContainerNames(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	containers, err := c.ContainerNames(nil)
+	containers, err := c.ContainerNames(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -709,13 +739,14 @@ func TestContainerNames(t *testing.T) {
 }
 
 func TestContainerNamesAll(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	containers1, err := c.ContainerNamesAll(nil)
+	containers1, err := c.ContainerNamesAll(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	containers2, err := c.ContainerNames(nil)
+	containers2, err := c.ContainerNames(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -730,13 +761,14 @@ func TestContainerNamesAll(t *testing.T) {
 }
 
 func TestContainerNamesAllWithLimit(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	containers1, err := c.ContainerNamesAll(&swift.ContainersOpts{Limit: 1})
+	containers1, err := c.ContainerNamesAll(ctx, &swift.ContainersOpts{Limit: 1})
 	if err != nil {
 		t.Fatal(err)
 	}
-	containers2, err := c.ContainerNames(nil)
+	containers2, err := c.ContainerNames(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -751,20 +783,21 @@ func TestContainerNamesAllWithLimit(t *testing.T) {
 }
 
 func TestObjectPutString(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+	err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
 
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -780,6 +813,7 @@ func TestObjectPutString(t *testing.T) {
 }
 
 func TestObjectPut(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 
@@ -788,7 +822,7 @@ func TestObjectPut(t *testing.T) {
 	// 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)
+	_, err := c.ObjectPut(ctx, CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
 	if err == nil {
 		t.Fatal("Expecting error but didn't get one")
 	}
@@ -796,12 +830,12 @@ func TestObjectPut(t *testing.T) {
 	// 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)
+	h, err := c.ObjectPut(ctx, CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -812,7 +846,7 @@ func TestObjectPut(t *testing.T) {
 	}
 
 	// Fetch object info and compare
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -828,6 +862,7 @@ func TestObjectPut(t *testing.T) {
 }
 
 func TestObjectPutWithReauth(t *testing.T) {
+	ctx := context.Background()
 	if !swift.IS_AT_LEAST_GO_16 {
 		return
 	}
@@ -838,12 +873,12 @@ func TestObjectPutWithReauth(t *testing.T) {
 	c.AuthToken = "expiredtoken"
 
 	r := strings.NewReader(CONTENTS)
-	_, err := c.ObjectPut(CONTAINER, OBJECT, r, true, "", "text/plain", nil)
+	_, err := c.ObjectPut(ctx, CONTAINER, OBJECT, r, true, "", "text/plain", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -859,6 +894,7 @@ func TestObjectPutWithReauth(t *testing.T) {
 }
 
 func TestObjectPutStringWithReauth(t *testing.T) {
+	ctx := context.Background()
 	if !swift.IS_AT_LEAST_GO_16 {
 		return
 	}
@@ -868,12 +904,12 @@ func TestObjectPutStringWithReauth(t *testing.T) {
 	// Simulate that our auth token expired
 	c.AuthToken = "expiredtoken"
 
-	err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+	err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -889,20 +925,21 @@ func TestObjectPutStringWithReauth(t *testing.T) {
 }
 
 func TestObjectEmpty(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ObjectPutString(CONTAINER, EMPTYOBJECT, "", "")
+	err := c.ObjectPutString(ctx, CONTAINER, EMPTYOBJECT, "", "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, EMPTYOBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, EMPTYOBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
-	info, _, err := c.Object(CONTAINER, EMPTYOBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, EMPTYOBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -918,6 +955,7 @@ func TestObjectEmpty(t *testing.T) {
 }
 
 func TestSymlinkObject(t *testing.T) {
+	ctx := context.Background()
 	info, err := getSwinftInfo(t)
 	if err != nil {
 		t.Fatal(err)
@@ -931,30 +969,30 @@ func TestSymlinkObject(t *testing.T) {
 	defer rollback()
 
 	// write target objects
-	err = c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "text/potato")
+	err = c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "text/potato")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
 	// test dynamic link
-	_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT, "", CONTAINER, OBJECT, "")
+	_, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT, "", CONTAINER, OBJECT, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, SYMLINK_OBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
-	md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT)
+	md, _, err := c.Object(ctx, CONTAINER, SYMLINK_OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -971,6 +1009,7 @@ func TestSymlinkObject(t *testing.T) {
 }
 
 func TestStaticSymlinkObject(t *testing.T) {
+	ctx := context.Background()
 	info, err := getSwinftInfo(t)
 	if err != nil {
 		t.Fatal(err)
@@ -989,12 +1028,12 @@ func TestStaticSymlinkObject(t *testing.T) {
 	defer rollback()
 
 	// write target objects
-	err = c.ObjectPutBytes(CONTAINER, OBJECT2, []byte(CONTENTS2), "text/tomato")
+	err = c.ObjectPutBytes(ctx, CONTAINER, OBJECT2, []byte(CONTENTS2), "text/tomato")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT2)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Error(err)
 		}
@@ -1002,23 +1041,23 @@ func TestStaticSymlinkObject(t *testing.T) {
 
 	// test static link
 	// first with the wrong target etag
-	_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT_MD5)
+	_, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT_MD5)
 	if err == nil {
 		t.Error("Symlink with wrong target etag should have failed")
 	}
 
-	_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT2_MD5)
+	_, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT2_MD5)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT2)
+		err = c.ObjectDelete(ctx, CONTAINER, SYMLINK_OBJECT2)
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
-	md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT2)
+	md, _, err := c.Object(ctx, CONTAINER, SYMLINK_OBJECT2)
 	if err != nil {
 		t.Error(err)
 	}
@@ -1034,20 +1073,21 @@ func TestStaticSymlinkObject(t *testing.T) {
 }
 
 func TestObjectPutBytes(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "")
+	err := c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -1063,20 +1103,21 @@ func TestObjectPutBytes(t *testing.T) {
 }
 
 func TestObjectPutMimeType(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ObjectPutString(CONTAINER, "test.jpg", CONTENTS, "")
+	err := c.ObjectPutString(ctx, CONTAINER, "test.jpg", CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, "test.jpg")
+		err = c.ObjectDelete(ctx, CONTAINER, "test.jpg")
 		if err != nil {
 			t.Error(err)
 		}
 	}()
 
-	info, _, err := c.Object(CONTAINER, "test.jpg")
+	info, _, err := c.Object(ctx, CONTAINER, "test.jpg")
 	if err != nil {
 		t.Error(err)
 	}
@@ -1086,14 +1127,15 @@ func TestObjectPutMimeType(t *testing.T) {
 }
 
 func TestObjectCreate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	out, err := c.ObjectCreate(CONTAINER, OBJECT2, true, "", "", nil)
+	out, err := c.ObjectCreate(ctx, CONTAINER, OBJECT2, true, "", "", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT2)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Error(err)
 		}
@@ -1102,7 +1144,7 @@ func TestObjectCreate(t *testing.T) {
 	hash := md5.New()
 	out2 := io.MultiWriter(out, buf, hash)
 	for i := 0; i < 100; i++ {
-		fmt.Fprintf(out2, "%d %s\n", i, CONTENTS)
+		_, _ = fmt.Fprintf(out2, "%d %s\n", i, CONTENTS)
 	}
 	// Ensure Headers fails if called prematurely
 	_, err = out.Headers()
@@ -1114,7 +1156,7 @@ func TestObjectCreate(t *testing.T) {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT2)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Error(err)
 	}
@@ -1138,7 +1180,7 @@ func TestObjectCreate(t *testing.T) {
 	}
 
 	// Now with hash instead
-	out, err = c.ObjectCreate(CONTAINER, OBJECT2, false, fmt.Sprintf("%x", hash.Sum(nil)), "", nil)
+	out, err = c.ObjectCreate(ctx, CONTAINER, OBJECT2, false, fmt.Sprintf("%x", hash.Sum(nil)), "", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1150,7 +1192,7 @@ func TestObjectCreate(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	contents, err = c.ObjectGetString(CONTAINER, OBJECT2)
+	contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Error(err)
 	}
@@ -1159,12 +1201,12 @@ func TestObjectCreate(t *testing.T) {
 	}
 
 	// Now with bad hash
-	out, err = c.ObjectCreate(CONTAINER, OBJECT2, false, CONTENT_MD5, "", nil)
+	out, err = c.ObjectCreate(ctx, CONTAINER, OBJECT2, false, CONTENT_MD5, "", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	// FIXME: work around bug which produces 503 not 422 for empty corrupted files
-	fmt.Fprintf(out, "Sausage")
+	_, _ = fmt.Fprintf(out, "Sausage")
 	err = out.Close()
 	if err != swift.ObjectCorrupted {
 		t.Error("Expecting object corrupted not", err)
@@ -1172,15 +1214,16 @@ func TestObjectCreate(t *testing.T) {
 }
 
 func TestObjectCreateAbort(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 
-	out, err := c.ObjectCreate(CONTAINER, OBJECT2, true, "", "", nil)
+	out, err := c.ObjectCreate(ctx, CONTAINER, OBJECT2, true, "", "", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		_ = c.ObjectDelete(CONTAINER, OBJECT2) // Ignore error
+		_ = c.ObjectDelete(ctx, CONTAINER, OBJECT2) // Ignore error
 	}()
 
 	expectedContents := "foo"
@@ -1195,16 +1238,17 @@ func TestObjectCreateAbort(t *testing.T) {
 		t.Errorf("Unexpected error %#v", err)
 	}
 
-	_, err = c.ObjectGetString(CONTAINER, OBJECT2)
+	_, err = c.ObjectGetString(ctx, CONTAINER, OBJECT2)
 	if err != swift.ObjectNotFound {
 		t.Errorf("Unexpected error: %#v", err)
 	}
 }
 
 func TestObjectGetString(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1214,9 +1258,10 @@ func TestObjectGetString(t *testing.T) {
 }
 
 func TestObjectGetBytes(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	contents, err := c.ObjectGetBytes(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetBytes(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1226,9 +1271,10 @@ func TestObjectGetBytes(t *testing.T) {
 }
 
 func TestObjectOpen(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+	file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1250,9 +1296,10 @@ func TestObjectOpen(t *testing.T) {
 }
 
 func TestObjectOpenPartial(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+	file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1274,14 +1321,15 @@ func TestObjectOpenPartial(t *testing.T) {
 }
 
 func TestObjectOpenLength(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+	file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	// FIXME ideally this would check both branches of the Length() code
-	n, err := file.Length()
+	n, err := file.Length(ctx)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1295,9 +1343,10 @@ func TestObjectOpenLength(t *testing.T) {
 }
 
 func TestObjectOpenNotModified(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	_, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, swift.Headers{
+	_, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, swift.Headers{
 		"If-None-Match": CONTENT_MD5,
 	})
 	if err != swift.NotModified {
@@ -1306,6 +1355,7 @@ func TestObjectOpenNotModified(t *testing.T) {
 }
 
 func TestObjectOpenSeek(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
 
@@ -1331,7 +1381,7 @@ func TestObjectOpenSeek(t *testing.T) {
 		{2, -4, 1},
 	}
 
-	file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+	file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1339,7 +1389,7 @@ func TestObjectOpenSeek(t *testing.T) {
 	for _, p := range plan {
 		if p.whence >= 0 {
 			var result int64
-			result, err = file.Seek(p.offset, p.whence)
+			result, err = file.Seek(ctx, p.offset, p.whence)
 			if err != nil {
 				t.Fatal(err, p)
 			}
@@ -1372,13 +1422,14 @@ func TestObjectOpenSeek(t *testing.T) {
 
 // Test seeking to the end to find the file size
 func TestObjectOpenSeekEnd(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+	file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	n, err := file.Seek(0, 2) // seek to end
+	n, err := file.Seek(ctx, 0, 2) // seek to end
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1397,7 +1448,7 @@ func TestObjectOpenSeekEnd(t *testing.T) {
 	}
 
 	// Now seek back to start and check we can read the file
-	n, err = file.Seek(0, 0) // seek to start
+	n, err = file.Seek(ctx, 0, 0) // seek to start
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1416,9 +1467,10 @@ func TestObjectOpenSeekEnd(t *testing.T) {
 }
 
 func TestObjectUpdate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	err := c.ObjectUpdate(CONTAINER, OBJECT, m1.ObjectHeaders())
+	err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m1.ObjectHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1432,9 +1484,10 @@ func checkTime(t *testing.T, when time.Time, low, high int) {
 }
 
 func TestObject(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	object, headers, err := c.Object(CONTAINER, OBJECT)
+	object, headers, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1446,13 +1499,14 @@ func TestObject(t *testing.T) {
 }
 
 func TestObjectUpdate2(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	err := c.ObjectUpdate(CONTAINER, OBJECT, m2.ObjectHeaders())
+	err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m2.ObjectHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
-	_, headers, err := c.Object(CONTAINER, OBJECT)
+	_, headers, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1460,9 +1514,10 @@ func TestObjectUpdate2(t *testing.T) {
 }
 
 func TestContainers(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	containers, err := c.Containers(nil)
+	containers, err := c.Containers(ctx, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1488,9 +1543,10 @@ func TestContainers(t *testing.T) {
 }
 
 func TestObjectNames(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectNames(CONTAINER, nil)
+	objects, err := c.ObjectNames(ctx, CONTAINER, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1500,9 +1556,10 @@ func TestObjectNames(t *testing.T) {
 }
 
 func TestObjectNamesAll(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectNamesAll(CONTAINER, nil)
+	objects, err := c.ObjectNamesAll(ctx, CONTAINER, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1512,9 +1569,10 @@ func TestObjectNamesAll(t *testing.T) {
 }
 
 func TestObjectNamesAllWithLimit(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectNamesAll(CONTAINER, &swift.ObjectsOpts{Limit: 1})
+	objects, err := c.ObjectNamesAll(ctx, CONTAINER, &swift.ObjectsOpts{Limit: 1})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1524,11 +1582,12 @@ func TestObjectNamesAllWithLimit(t *testing.T) {
 }
 
 func TestObjectsWalk(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
 	objects := make([]string, 0)
-	err := c.ObjectsWalk(container, nil, func(opts *swift.ObjectsOpts) (interface{}, error) {
-		newObjects, err := c.ObjectNames(CONTAINER, opts)
+	err := c.ObjectsWalk(ctx, container, nil, func(ctx context.Context, opts *swift.ObjectsOpts) (interface{}, error) {
+		newObjects, err := c.ObjectNames(ctx, CONTAINER, opts)
 		if err == nil {
 			objects = append(objects, newObjects...)
 		}
@@ -1543,9 +1602,10 @@ func TestObjectsWalk(t *testing.T) {
 }
 
 func TestObjects(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+	objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1560,17 +1620,20 @@ func TestObjects(t *testing.T) {
 }
 
 func TestObjectsDirectory(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	err := c.ObjectPutString(CONTAINER, "directory", "", "application/directory")
+	err := c.ObjectPutString(ctx, CONTAINER, "directory", "", "application/directory")
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer c.ObjectDelete(CONTAINER, "directory")
+	defer func() {
+		_ = c.ObjectDelete(ctx, CONTAINER, "directory")
+	}()
 
 	// Look for the directory object and check we aren't confusing
 	// it with a pseudo directory object
-	objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+	objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1594,16 +1657,19 @@ func TestObjectsDirectory(t *testing.T) {
 }
 
 func TestObjectsPseudoDirectory(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	err := c.ObjectPutString(CONTAINER, "directory/puppy.jpg", "cute puppy", "")
+	err := c.ObjectPutString(ctx, CONTAINER, "directory/puppy.jpg", "cute puppy", "")
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer c.ObjectDelete(CONTAINER, "directory/puppy.jpg")
+	defer func() {
+		_ = c.ObjectDelete(ctx, CONTAINER, "directory/puppy.jpg")
+	}()
 
 	// Look for the pseudo directory
-	objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+	objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1625,7 +1691,7 @@ func TestObjectsPseudoDirectory(t *testing.T) {
 	}
 
 	// Look in the pseudo directory now
-	objects, err = c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "directory/"})
+	objects, err = c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "directory/"})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1640,9 +1706,10 @@ func TestObjectsPseudoDirectory(t *testing.T) {
 }
 
 func TestObjectsAll(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectsAll(CONTAINER, nil)
+	objects, err := c.ObjectsAll(ctx, CONTAINER, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1652,9 +1719,10 @@ func TestObjectsAll(t *testing.T) {
 }
 
 func TestObjectsAllWithLimit(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectsAll(CONTAINER, &swift.ObjectsOpts{Limit: 1})
+	objects, err := c.ObjectsAll(ctx, CONTAINER, &swift.ObjectsOpts{Limit: 1})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1664,9 +1732,10 @@ func TestObjectsAllWithLimit(t *testing.T) {
 }
 
 func TestObjectNamesWithPath(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	objects, err := c.ObjectNames(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: ""})
+	objects, err := c.ObjectNames(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: ""})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1674,7 +1743,7 @@ func TestObjectNamesWithPath(t *testing.T) {
 		t.Error("Bad listing with path", objects)
 	}
 	// fmt.Println(objects)
-	objects, err = c.ObjectNames(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "Downloads/"})
+	objects, err = c.ObjectNames(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "Downloads/"})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1684,33 +1753,36 @@ func TestObjectNamesWithPath(t *testing.T) {
 }
 
 func TestObjectCopy(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	_, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, OBJECT2, nil)
+	_, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = c.ObjectDelete(CONTAINER, OBJECT2)
+	err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestObjectCopyDifficultName(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
 	const dest = OBJECT + "?param %30%31%32 £100"
-	_, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, dest, nil)
+	_, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, dest, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = c.ObjectDelete(CONTAINER, dest)
+	err = c.ObjectDelete(ctx, CONTAINER, dest)
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestObjectCopyWithMetadata(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
 	m := swift.Metadata{}
@@ -1718,18 +1790,18 @@ func TestObjectCopyWithMetadata(t *testing.T) {
 	m["hello"] = "9"
 	h := m.ObjectHeaders()
 	h["Content-Type"] = "image/jpeg"
-	_, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, OBJECT2, h)
+	_, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2, h)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT2)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
 	// Re-read the metadata to see if it is correct
-	_, headers, err := c.Object(CONTAINER, OBJECT2)
+	_, headers, err := c.Object(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1740,24 +1812,25 @@ func TestObjectCopyWithMetadata(t *testing.T) {
 }
 
 func TestObjectMove(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	err := c.ObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+	err := c.ObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
 	testExistenceAfterDelete(t, c, CONTAINER, OBJECT)
-	_, _, err = c.Object(CONTAINER, OBJECT2)
+	_, _, err = c.Object(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	err = c.ObjectMove(CONTAINER, OBJECT2, CONTAINER, OBJECT)
+	err = c.ObjectMove(ctx, CONTAINER, OBJECT2, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
 	testExistenceAfterDelete(t, c, CONTAINER, OBJECT2)
-	_, headers, err := c.Object(CONTAINER, OBJECT)
+	_, headers, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1765,14 +1838,15 @@ func TestObjectMove(t *testing.T) {
 }
 
 func TestObjectUpdateContentType(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObjectHeaders(t)
 	defer rollback()
-	err := c.ObjectUpdateContentType(CONTAINER, OBJECT, "text/potato")
+	err := c.ObjectUpdateContentType(ctx, CONTAINER, OBJECT, "text/potato")
 	if err != nil {
 		t.Fatal(err)
 	}
 	// Re-read the metadata to see if it is correct
-	_, headers, err := c.Object(CONTAINER, OBJECT)
+	_, headers, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1783,12 +1857,13 @@ func TestObjectUpdateContentType(t *testing.T) {
 }
 
 func TestVersionContainerCreate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	err := c.VersionContainerCreate(CURRENT_CONTAINER, VERSIONS_CONTAINER)
+	err := c.VersionContainerCreate(ctx, CURRENT_CONTAINER, VERSIONS_CONTAINER)
 	defer func() {
-		c.ContainerDelete(CURRENT_CONTAINER)
-		c.ContainerDelete(VERSIONS_CONTAINER)
+		_ = c.ContainerDelete(ctx, CURRENT_CONTAINER)
+		_ = c.ContainerDelete(ctx, VERSIONS_CONTAINER)
 	}()
 	if err != nil {
 		if err == swift.Forbidden {
@@ -1800,6 +1875,7 @@ func TestVersionContainerCreate(t *testing.T) {
 }
 
 func TestVersionObjectAdd(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithVersionsContainer(t)
 	defer rollback()
 	if skipVersionTests {
@@ -1807,43 +1883,43 @@ func TestVersionObjectAdd(t *testing.T) {
 		return
 	}
 	// Version 1
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+		err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
-	if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+	if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	} else if contents != CONTENTS {
 		t.Error("Contents wrong")
 	}
 
 	// Version 2
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+		err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
-	if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+	if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	} else if contents != CONTENTS2 {
 		t.Error("Contents wrong")
 	}
 
 	// Version 3
-	if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+	if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+		err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -1851,13 +1927,14 @@ func TestVersionObjectAdd(t *testing.T) {
 }
 
 func TestVersionObjectList(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithVersionsObject(t)
 	defer rollback()
 	if skipVersionTests {
 		t.Log("Server doesn't support Versions - skipping test")
 		return
 	}
-	list, err := c.VersionObjectList(VERSIONS_CONTAINER, OBJECT)
+	list, err := c.VersionObjectList(ctx, VERSIONS_CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1868,6 +1945,7 @@ func TestVersionObjectList(t *testing.T) {
 }
 
 func TestVersionObjectDelete(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithVersionsObject(t)
 	defer rollback()
 	if skipVersionTests {
@@ -1875,17 +1953,17 @@ func TestVersionObjectDelete(t *testing.T) {
 		return
 	}
 	// Delete Version 3
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	}
 
 	// Delete Version 2
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	}
 
 	// Contents should be reverted to Version 1
-	if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+	if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	} else if contents != CONTENTS {
 		t.Error("Contents wrong")
@@ -1893,6 +1971,7 @@ func TestVersionObjectDelete(t *testing.T) {
 }
 
 func TestVersionDeleteContent(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithVersionsObject(t)
 	defer rollback()
 	if skipVersionTests {
@@ -1900,18 +1979,18 @@ func TestVersionDeleteContent(t *testing.T) {
 		return
 	}
 	// Delete Version 3
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	}
 	// Delete Version 2
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	}
 	// Delete Version 1
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
 		t.Fatal(err)
 	}
-	if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != swift.ObjectNotFound {
+	if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != swift.ObjectNotFound {
 		t.Fatalf("Expecting Object not found error, got: %v", err)
 	}
 }
@@ -1919,8 +1998,9 @@ func TestVersionDeleteContent(t *testing.T) {
 // Check for non existence after delete
 // May have to do it a few times to wait for swift to be consistent.
 func testExistenceAfterDelete(t *testing.T, c *swift.Connection, container, object string) {
+	ctx := context.Background()
 	for i := 10; i <= 0; i-- {
-		_, _, err := c.Object(container, object)
+		_, _, err := c.Object(ctx, container, object)
 		if err == swift.ObjectNotFound {
 			break
 		}
@@ -1932,23 +2012,25 @@ func testExistenceAfterDelete(t *testing.T, c *swift.Connection, container, obje
 }
 
 func TestObjectDelete(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithObject(t)
 	defer rollback()
-	err := c.ObjectDelete(CONTAINER, OBJECT)
+	err := c.ObjectDelete(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
 	testExistenceAfterDelete(t, c, CONTAINER, OBJECT)
-	err = c.ObjectDelete(CONTAINER, OBJECT)
+	err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 	if err != swift.ObjectNotFound {
 		t.Fatal("Expecting Object not found", err)
 	}
 }
 
 func TestBulkDelete(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	result, err := c.BulkDelete(CONTAINER, []string{OBJECT})
+	result, err := c.BulkDelete(ctx, CONTAINER, []string{OBJECT})
 	if err == swift.Forbidden {
 		t.Log("Server doesn't support BulkDelete - skipping test")
 		return
@@ -1962,11 +2044,11 @@ func TestBulkDelete(t *testing.T) {
 	if result.NumberDeleted != 0 {
 		t.Error("Expected 0, actual:", result.NumberDeleted)
 	}
-	err = c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+	err = c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
-	result, err = c.BulkDelete(CONTAINER, []string{OBJECT2, OBJECT})
+	result, err = c.BulkDelete(ctx, CONTAINER, []string{OBJECT2, OBJECT})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1980,6 +2062,7 @@ func TestBulkDelete(t *testing.T) {
 }
 
 func TestBulkUpload(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 	buffer := new(bytes.Buffer)
@@ -2004,7 +2087,7 @@ func TestBulkUpload(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	result, err := c.BulkUpload(CONTAINER, buffer, swift.UploadTar, nil)
+	result, err := c.BulkUpload(ctx, CONTAINER, buffer, swift.UploadTar, nil)
 	if err == swift.Forbidden {
 		t.Log("Server doesn't support BulkUpload - skipping test")
 		return
@@ -2013,11 +2096,11 @@ func TestBulkUpload(t *testing.T) {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
-		err = c.ObjectDelete(CONTAINER, OBJECT2)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2027,31 +2110,32 @@ func TestBulkUpload(t *testing.T) {
 	}
 	t.Log("Errors:", result.Errors)
 
-	_, _, err = c.Object(CONTAINER, OBJECT)
+	_, _, err = c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error("Expecting object to be found")
 	}
-	_, _, err = c.Object(CONTAINER, OBJECT2)
+	_, _, err = c.Object(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Error("Expecting object to be found")
 	}
 }
 
 func TestObjectDifficultName(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 	const name = `hello? sausage/êé/Hello, 世界/ " ' @ < > & ?/`
-	err := c.ObjectPutString(CONTAINER, name, CONTENTS, "")
+	err := c.ObjectPutString(ctx, CONTAINER, name, CONTENTS, "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, name)
+		err = c.ObjectDelete(ctx, CONTAINER, name)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
-	objects, err := c.ObjectNamesAll(CONTAINER, nil)
+	objects, err := c.ObjectNamesAll(ctx, CONTAINER, nil)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2068,14 +2152,15 @@ func TestObjectDifficultName(t *testing.T) {
 }
 
 func TestTempUrl(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "")
+	err := c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ObjectDelete(CONTAINER, OBJECT)
+		err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2083,7 +2168,7 @@ func TestTempUrl(t *testing.T) {
 
 	m := swift.Metadata{}
 	m["temp-url-key"] = SECRET_KEY
-	err = c.AccountUpdate(m.AccountHeaders())
+	err = c.AccountUpdate(ctx, m.AccountHeaders())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2094,7 +2179,12 @@ func TestTempUrl(t *testing.T) {
 	if err != nil {
 		t.Fatal("Failed to retrieve file from temporary url")
 	}
-	defer resp.Body.Close()
+	defer func() {
+		err := resp.Body.Close()
+		if err != nil {
+			t.Error("Close failed", err)
+		}
+	}()
 	if resp.StatusCode == 401 {
 		t.Log("Server doesn't support tempurl")
 	} else if resp.StatusCode != 200 {
@@ -2109,7 +2199,12 @@ func TestTempUrl(t *testing.T) {
 		if err != nil {
 			t.Fatal("Failed to retrieve file from temporary url")
 		}
-		defer resp.Body.Close()
+		defer func() {
+			err := resp.Body.Close()
+			if err != nil {
+				t.Error("Close failed", err)
+			}
+		}()
 		if resp.StatusCode != 401 {
 			t.Fatal("Expecting server to forbid access to object")
 		}
@@ -2117,9 +2212,10 @@ func TestTempUrl(t *testing.T) {
 }
 
 func TestQueryInfo(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
-	infos, err := c.QueryInfo()
+	infos, err := c.QueryInfo(ctx)
 	if err != nil {
 		t.Log("Server doesn't support querying info")
 		return
@@ -2130,6 +2226,7 @@ func TestQueryInfo(t *testing.T) {
 }
 
 func TestDLOCreate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 
@@ -2138,12 +2235,12 @@ func TestDLOCreate(t *testing.T) {
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreate(&opts)
+	out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+		err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2157,19 +2254,19 @@ func TestDLOCreate(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
 	if contents != expected {
 		t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
 	}
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2182,6 +2279,7 @@ func TestDLOCreate(t *testing.T) {
 }
 
 func TestDLOInsert(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithDLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2190,7 +2288,7 @@ func TestDLOInsert(t *testing.T) {
 		CheckHash:   true,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreateFile(&opts)
+	out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2201,13 +2299,13 @@ func TestDLOInsert(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
-	err = out.Close()
+	_, _ = fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2217,6 +2315,7 @@ func TestDLOInsert(t *testing.T) {
 }
 
 func TestDLOAppend(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithDLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2226,12 +2325,15 @@ func TestDLOAppend(t *testing.T) {
 		CheckHash:   true,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreateFile(&opts)
+	out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
+	if err != nil {
+		t.Fatal(err)
+	}
 	buf := bytes.NewBuffer([]byte(contents))
 	multi := io.MultiWriter(buf, out)
 	for i := 0; i < 2; i++ {
@@ -2240,12 +2342,12 @@ func TestDLOAppend(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err = c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2255,6 +2357,7 @@ func TestDLOAppend(t *testing.T) {
 }
 
 func TestDLOTruncate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithDLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2264,7 +2367,7 @@ func TestDLOTruncate(t *testing.T) {
 		CheckHash:   true,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreateFile(&opts)
+	out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2275,12 +2378,12 @@ func TestDLOTruncate(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2290,25 +2393,26 @@ func TestDLOTruncate(t *testing.T) {
 }
 
 func TestDLOMove(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithDLO(t)
 	defer rollback()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	err = c.DynamicLargeObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+	err = c.DynamicLargeObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT2)
+		err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
 
-	contents2, err := c.ObjectGetString(CONTAINER, OBJECT2)
+	contents2, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2319,6 +2423,7 @@ func TestDLOMove(t *testing.T) {
 }
 
 func TestDLONoSegmentContainer(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithDLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2327,7 +2432,7 @@ func TestDLONoSegmentContainer(t *testing.T) {
 		ContentType:      "image/jpeg",
 		SegmentContainer: CONTAINER,
 	}
-	out, err := c.DynamicLargeObjectCreate(&opts)
+	out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2340,12 +2445,12 @@ func TestDLONoSegmentContainer(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2355,6 +2460,7 @@ func TestDLONoSegmentContainer(t *testing.T) {
 }
 
 func TestDLOCreateMissingSegmentsInList(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 
@@ -2369,17 +2475,17 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
 			w.Header().Set(k, v[0])
 		}
 		w.WriteHeader(recorder.Code)
-		w.Write([]byte("null\n"))
+		_, _ = w.Write([]byte("null\n"))
 	})
 	defer srv.UnsetOverride(listURL)
 
 	headers := swift.Headers{}
-	err := c.ContainerCreate(SEGMENTS_CONTAINER, headers)
+	err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, headers)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ContainerDelete(SEGMENTS_CONTAINER)
+		err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2390,12 +2496,12 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreate(&opts)
+	out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+		err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2409,12 +2515,12 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2424,6 +2530,7 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
 }
 
 func TestDLOCreateIncorrectSize(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
 
@@ -2446,17 +2553,17 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
 			}
 		}
 		w.WriteHeader(recorder.Code)
-		w.Write(recorder.Body.Bytes())
+		_, _ = w.Write(recorder.Body.Bytes())
 	})
 	defer srv.UnsetOverride(listURL)
 
 	headers := swift.Headers{}
-	err := c.ContainerCreate(SEGMENTS_CONTAINER, headers)
+	err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, headers)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.ContainerDelete(SEGMENTS_CONTAINER)
+		err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2467,12 +2574,12 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.DynamicLargeObjectCreate(&opts)
+	out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+		err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2485,7 +2592,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2493,7 +2600,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
 		t.Errorf("Unexpected HEAD requests count, expected %d, got: %d", expectedHeadCount, headCount)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2503,6 +2610,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
 }
 
 func TestDLOConcurrentWrite(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 
@@ -2517,12 +2625,12 @@ func TestDLOConcurrentWrite(t *testing.T) {
 			ObjectName:  objName,
 			ContentType: "image/jpeg",
 		}
-		out, err := c.DynamicLargeObjectCreate(&opts)
+		out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			t.Fatal(err)
 		}
 		defer func() {
-			err = c.DynamicLargeObjectDelete(CONTAINER, objName)
+			err = c.DynamicLargeObjectDelete(ctx, CONTAINER, objName)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -2544,12 +2652,12 @@ func TestDLOConcurrentWrite(t *testing.T) {
 				t.Fatalf("expected to write %d, got: %d", chunkSize, n)
 			}
 		}
-		err = out.Close()
+		err = out.CloseWithContext(ctx)
 		if err != nil {
 			t.Error(err)
 		}
 		expected := buf.String()
-		contents, err := c.ObjectGetString(CONTAINER, objName)
+		contents, err := c.ObjectGetString(ctx, CONTAINER, objName)
 		if err != nil {
 			t.Error(err)
 		}
@@ -2570,6 +2678,7 @@ func TestDLOConcurrentWrite(t *testing.T) {
 }
 
 func TestDLOSegmentation(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 
@@ -2582,7 +2691,7 @@ func TestDLOSegmentation(t *testing.T) {
 	}
 
 	testSegmentation(t, c, func() swift.LargeObjectFile {
-		out, err := c.DynamicLargeObjectCreate(&opts)
+		out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2625,6 +2734,7 @@ func TestDLOSegmentation(t *testing.T) {
 }
 
 func TestDLOSegmentationBuffered(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 
@@ -2636,7 +2746,7 @@ func TestDLOSegmentationBuffered(t *testing.T) {
 	}
 
 	testSegmentation(t, c, func() swift.LargeObjectFile {
-		out, err := c.DynamicLargeObjectCreate(&opts)
+		out, err := c.DynamicLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2679,6 +2789,7 @@ func TestDLOSegmentationBuffered(t *testing.T) {
 }
 
 func TestSLOCreate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 
@@ -2687,7 +2798,7 @@ func TestSLOCreate(t *testing.T) {
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.StaticLargeObjectCreate(&opts)
+	out, err := c.StaticLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		if err == swift.SLONotSupported {
 			t.Skip("SLO not supported")
@@ -2696,7 +2807,7 @@ func TestSLOCreate(t *testing.T) {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+		err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2710,19 +2821,19 @@ func TestSLOCreate(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
 	if contents != expected {
 		t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
 	}
-	info, _, err := c.Object(CONTAINER, OBJECT)
+	info, _, err := c.Object(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2735,6 +2846,7 @@ func TestSLOCreate(t *testing.T) {
 }
 
 func TestSLOInsert(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2742,7 +2854,7 @@ func TestSLOInsert(t *testing.T) {
 		ObjectName:  OBJECT,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.StaticLargeObjectCreateFile(&opts)
+	out, err := c.StaticLargeObjectCreateFile(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2753,13 +2865,13 @@ func TestSLOInsert(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
-	err = out.Close()
+	_, _ = fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2769,6 +2881,7 @@ func TestSLOInsert(t *testing.T) {
 }
 
 func TestSLOAppend(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSLO(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2778,12 +2891,15 @@ func TestSLOAppend(t *testing.T) {
 		CheckHash:   true,
 		ContentType: "image/jpeg",
 	}
-	out, err := c.StaticLargeObjectCreateFile(&opts)
+	out, err := c.StaticLargeObjectCreateFile(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
+	if err != nil {
+		t.Fatal(err)
+	}
 	buf := bytes.NewBuffer([]byte(contents))
 	multi := io.MultiWriter(buf, out)
 	for i := 0; i < 2; i++ {
@@ -2792,12 +2908,12 @@ func TestSLOAppend(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err = c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2807,25 +2923,26 @@ func TestSLOAppend(t *testing.T) {
 }
 
 func TestSLOMove(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSLO(t)
 	defer rollback()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	err = c.StaticLargeObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+	err = c.StaticLargeObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer func() {
-		err = c.StaticLargeObjectDelete(CONTAINER, OBJECT2)
+		err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT2)
 		if err != nil {
 			t.Fatal(err)
 		}
 	}()
 
-	contents2, err := c.ObjectGetString(CONTAINER, OBJECT2)
+	contents2, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2836,6 +2953,7 @@ func TestSLOMove(t *testing.T) {
 }
 
 func TestSLONoSegmentContainer(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSLO(t)
 	defer rollback()
 
@@ -2845,7 +2963,7 @@ func TestSLONoSegmentContainer(t *testing.T) {
 		ContentType:      "image/jpeg",
 		SegmentContainer: CONTAINER,
 	}
-	out, err := c.StaticLargeObjectCreate(&opts)
+	out, err := c.StaticLargeObjectCreate(ctx, &opts)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2858,12 +2976,12 @@ func TestSLONoSegmentContainer(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
-	err = out.Close()
+	err = out.CloseWithContext(ctx)
 	if err != nil {
 		t.Error(err)
 	}
 	expected := buf.String()
-	contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+	contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Error(err)
 	}
@@ -2871,13 +2989,14 @@ func TestSLONoSegmentContainer(t *testing.T) {
 		t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
 	}
 
-	err = c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+	err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestSLOMinChunkSize(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 	if srv == nil {
@@ -2886,10 +3005,10 @@ func TestSLOMinChunkSize(t *testing.T) {
 	}
 
 	srv.SetOverride("/info", func(w http.ResponseWriter, r *http.Request, recorder *httptest.ResponseRecorder) {
-		w.Write([]byte(`{"slo": {"min_segment_size": 4}}`))
+		_, _ = w.Write([]byte(`{"slo": {"min_segment_size": 4}}`))
 	})
 	defer srv.UnsetOverride("/info")
-	c.QueryInfo()
+	_, _ = c.QueryInfo(ctx)
 
 	opts := swift.LargeObjectOpts{
 		Container:    CONTAINER,
@@ -2901,7 +3020,7 @@ func TestSLOMinChunkSize(t *testing.T) {
 	}
 
 	testSLOSegmentation(t, c, func() swift.LargeObjectFile {
-		out, err := c.StaticLargeObjectCreate(&opts)
+		out, err := c.StaticLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -2910,6 +3029,7 @@ func TestSLOMinChunkSize(t *testing.T) {
 }
 
 func TestSLOSegmentation(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2921,7 +3041,7 @@ func TestSLOSegmentation(t *testing.T) {
 		NoBuffer:     true,
 	}
 	testSLOSegmentation(t, c, func() swift.LargeObjectFile {
-		out, err := c.StaticLargeObjectCreate(&opts)
+		out, err := c.StaticLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			if err == swift.SLONotSupported {
 				t.Skip("SLO not supported")
@@ -2933,6 +3053,7 @@ func TestSLOSegmentation(t *testing.T) {
 }
 
 func TestSLOSegmentationBuffered(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithSegmentsContainer(t)
 	defer rollback()
 	opts := swift.LargeObjectOpts{
@@ -2943,7 +3064,7 @@ func TestSLOSegmentationBuffered(t *testing.T) {
 		MinChunkSize: 4,
 	}
 	testSegmentation(t, c, func() swift.LargeObjectFile {
-		out, err := c.StaticLargeObjectCreate(&opts)
+		out, err := c.StaticLargeObjectCreate(ctx, &opts)
 		if err != nil {
 			if err == swift.SLONotSupported {
 				t.Skip("SLO not supported")
@@ -3035,11 +3156,12 @@ type segmentTest struct {
 }
 
 func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.LargeObjectFile, testCases []segmentTest) {
+	ctx := context.Background()
 	var err error
 	runTestCase := func(tCase segmentTest) {
 		out := createObj()
 		defer func() {
-			err = c.LargeObjectDelete(CONTAINER, OBJECT)
+			err = c.LargeObjectDelete(ctx, CONTAINER, OBJECT)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -3056,31 +3178,31 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
 				}
 			}
 		}
-		err = out.Close()
+		err = out.CloseWithContext(ctx)
 		if err != nil {
 			t.Error(err)
 		}
-		contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+		contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 		if contents != tCase.expectedValue {
 			t.Errorf("Contents wrong, expected %q, got: %q", tCase.expectedValue, contents)
 		}
-		container, objects, err := c.LargeObjectGetSegments(CONTAINER, OBJECT)
+		container, objects, err := c.LargeObjectGetSegments(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Error(err)
 		}
 		if container != SEGMENTS_CONTAINER {
 			t.Errorf("Segments container wrong, expected %q, got: %q", SEGMENTS_CONTAINER, container)
 		}
-		_, headers, err := c.Object(CONTAINER, OBJECT)
+		_, headers, err := c.Object(ctx, CONTAINER, OBJECT)
 		if err != nil {
 			t.Fatal(err)
 		}
 		if headers.IsLargeObjectSLO() {
 			var info swift.SwiftInfo
-			info, err = c.QueryInfo()
+			info, err = c.QueryInfo(ctx)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -3092,7 +3214,7 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
 		var segContents []string
 		for _, obj := range objects {
 			var value string
-			value, err = c.ObjectGetString(SEGMENTS_CONTAINER, obj.Name)
+			value, err = c.ObjectGetString(ctx, SEGMENTS_CONTAINER, obj.Name)
 			if err != nil {
 				t.Error(err)
 			}
@@ -3108,23 +3230,25 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
 }
 
 func TestContainerDelete(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionWithContainer(t)
 	defer rollback()
-	err := c.ContainerDelete(CONTAINER)
+	err := c.ContainerDelete(ctx, CONTAINER)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = c.ContainerDelete(CONTAINER)
+	err = c.ContainerDelete(ctx, CONTAINER)
 	if err != swift.ContainerNotFound {
 		t.Fatal("Expecting container not found", err)
 	}
-	_, _, err = c.Container(CONTAINER)
+	_, _, err = c.Container(ctx, CONTAINER)
 	if err != swift.ContainerNotFound {
 		t.Fatal("Expecting container not found", err)
 	}
 }
 
 func TestUnAuthenticate(t *testing.T) {
+	ctx := context.Background()
 	c, rollback := makeConnectionAuth(t)
 	defer rollback()
 	c.UnAuthenticate()
@@ -3132,7 +3256,7 @@ func TestUnAuthenticate(t *testing.T) {
 		t.Fatal("Shouldn't be authenticated")
 	}
 	// Test re-authenticate
-	err := c.Authenticate()
+	err := c.Authenticate(ctx)
 	if err != nil {
 		t.Fatal("ReAuth failed", err)
 	}
diff --git a/swifttest/server.go b/swifttest/server.go
index d7dd748..a6bd6b5 100644
--- a/swifttest/server.go
+++ b/swifttest/server.go
@@ -34,7 +34,6 @@ import (
 	"strings"
 	"sync"
 	"sync/atomic"
-	"testing"
 	"time"
 )
 
@@ -51,8 +50,6 @@ type SwiftServer struct {
 	// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG for more details.
 	reqId int64
 	sync.RWMutex
-	t        *testing.T
-	mu       sync.Mutex
 	Listener net.Listener
 	AuthURL  string
 	URL      string
@@ -145,7 +142,6 @@ type container struct {
 	sync.RWMutex
 	metadata
 	name    string
-	ctime   time.Time
 	objects map[string]*object
 }
 
@@ -188,15 +184,6 @@ type containerResource struct {
 	container *container // non-nil if the container already exists.
 }
 
-var responseParams = map[string]bool{
-	"content-type":        true,
-	"content-language":    true,
-	"expires":             true,
-	"cache-control":       true,
-	"content-disposition": true,
-	"content-encoding":    true,
-}
-
 func fatalf(code int, codeStr string, errf string, a ...interface{}) {
 	panic(&swiftError{
 		statusCode: code,
@@ -319,9 +306,15 @@ func (r containerResource) get(a *action) interface{} {
 	} else {
 		for _, item := range objects {
 			if obj, ok := item.(*object); ok {
-				a.w.Write([]byte(obj.name + "\n"))
+				_, err := a.w.Write([]byte(obj.name + "\n"))
+				if err != nil {
+					fatalf(500, "WriteFailed", "Write failed")
+				}
 			} else if subdir, ok := item.(Subdir); ok {
-				a.w.Write([]byte(subdir.Subdir + "\n"))
+				_, err := a.w.Write([]byte(subdir.Subdir + "\n"))
+				if err != nil {
+					fatalf(500, "WriteFailed", "Write failed")
+				}
 			}
 		}
 		return nil
@@ -398,7 +391,12 @@ func (r containerResource) put(a *action) interface{} {
 			if err != nil {
 				fatalf(400, "TODO", "Invalid tar.gz")
 			}
-			defer gzr.Close()
+			defer func() {
+				err := gzr.Close()
+				if err != nil {
+					fatalf(400, "CloseFailed", "Close failed")
+				}
+			}()
 			reader = tar.NewReader(gzr)
 		case "tar.bz2":
 			bzr := bzip2.NewReader(dataReader)
@@ -660,7 +658,10 @@ func (objr objectResource) get(a *action) interface{} {
 	} else if value, ok := obj.meta["X-Static-Large-Object"]; ok && value[0] == "True" && a.req.URL.Query().Get("multipart-manifest") != "get" {
 		var segments []io.Reader
 		var segmentList []segment
-		json.Unmarshal(obj.data, &segmentList)
+		err := json.Unmarshal(obj.data, &segmentList)
+		if err != nil {
+			fatalf(400, "BadParameters", "Unmarshal failed.")
+		}
 		cursor := 0
 		size := 0
 		sum := md5.New()
@@ -769,7 +770,10 @@ func (objr objectResource) put(a *action) interface{} {
 		a.req.Header.Set("X-Static-Large-Object", "True")
 
 		var segments []segment
-		json.Unmarshal(data, &segments)
+		err := json.Unmarshal(data, &segments)
+		if err != nil {
+			fatalf(400, "BadParameters", "Unmarshal failed.")
+		}
 		for i := range segments {
 			segments[i].Name = "/" + segments[i].Path
 			segments[i].Path = ""
@@ -901,7 +905,10 @@ func (objr objectResource) copy(a *action) interface{} {
 
 func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
 	// ignore error from ParseForm as it's usually spurious.
-	req.ParseForm()
+	err := req.ParseForm()
+	if err != nil {
+		fatalf(400, "BadParameters", "Parse form failed.")
+	}
 
 	if fn := s.override[req.URL.Path]; fn != nil {
 		originalRW := w
@@ -954,8 +961,8 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
 				_, _ = rand.Read(r)
 				id := fmt.Sprintf("%X", r)
 				w.Header().Set("X-Storage-Url", s.URL+"/AUTH_"+username)
-				w.Header().Set("X-Auth-Token", "AUTH_tk"+string(id))
-				w.Header().Set("X-Storage-Token", "AUTH_tk"+string(id))
+				w.Header().Set("X-Auth-Token", "AUTH_tk"+id)
+				w.Header().Set("X-Storage-Token", "AUTH_tk"+id)
 				s.Sessions[id] = &session{
 					username: username,
 				}
@@ -1016,7 +1023,6 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
 		if !ok {
 			s.RUnlock()
 			panic(notAuthorized())
-			return
 		}
 
 		a.user = s.Accounts[session.username]
@@ -1046,9 +1052,15 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
 		} else {
 			switch r := resp.(type) {
 			case string:
-				w.Write([]byte(r))
+				_, err := w.Write([]byte(r))
+				if err != nil {
+					fatalf(500, "WriteFailed", "Write failed.")
+				}
 			default:
-				w.Write(resp.([]byte))
+				_, err := w.Write(resp.([]byte))
+				if err != nil {
+					fatalf(500, "WriteFailed", "Write failed.")
+				}
 			}
 		}
 	}
@@ -1195,7 +1207,10 @@ func (rootResource) get(a *action) interface{} {
 				Name:  container.name,
 			})
 		} else {
-			a.w.Write([]byte(container.name + "\n"))
+			_, err := a.w.Write([]byte(container.name + "\n"))
+			if err != nil {
+				fatalf(500, "WriteFailed", "Write failed.")
+			}
 		}
 	}
 
@@ -1275,7 +1290,10 @@ func (r rootResource) delete(a *action) interface{} {
 		}
 
 		resp := fmt.Sprintf("Number Deleted: %d\nNumber Not Found: %d\nErrors: \nResponse Status: 200 OK\n", nb, notFound)
-		a.w.Write([]byte(resp))
+		_, err = a.w.Write([]byte(resp))
+		if err != nil {
+			fatalf(500, "WriteFailed", "Write failed.")
+		}
 		return nil
 	}
 
@@ -1310,13 +1328,15 @@ func NewSwiftServer(address string) (*SwiftServer, error) {
 		Containers: make(map[string]*container),
 	}
 
-	go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
-		server.serveHTTP(w, req)
-	}))
+	go func() {
+		_ = http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+			server.serveHTTP(w, req)
+		}))
+	}()
 
 	return server, nil
 }
 
 func (srv *SwiftServer) Close() {
-	srv.Listener.Close()
+	_ = srv.Listener.Close()
 }
diff --git a/timeout_reader.go b/timeout_reader.go
index 88ae733..7715902 100644
--- a/timeout_reader.go
+++ b/timeout_reader.go
@@ -47,7 +47,6 @@ func (t *timeoutReader) Read(p []byte) (int, error) {
 		t.cancel()
 		return 0, TimeoutError
 	}
-	panic("unreachable") // for Go 1.0
 }
 
 // Close the channel
diff --git a/timeout_reader_test.go b/timeout_reader_test.go
index 2348617..5eba093 100644
--- a/timeout_reader_test.go
+++ b/timeout_reader_test.go
@@ -67,7 +67,7 @@ func TestTimeoutReaderNoTimeout(t *testing.T) {
 	if test.closed {
 		t.Fatal("Shouldn't be closed")
 	}
-	tr.Close()
+	_ = tr.Close()
 	if !test.closed {
 		t.Fatal("Should be closed")
 	}
@@ -100,7 +100,7 @@ func TestTimeoutReaderTimeout(t *testing.T) {
 	if test.closed {
 		t.Fatal("Shouldn't be closed")
 	}
-	tr.Close()
+	_ = tr.Close()
 	if !test.closed {
 		t.Fatal("Should be closed")
 	}