@@ -48,25 +48,47 @@ const (
48
48
// Rackspace v2 https://identity.api.rackspacecloud.com/v2.0
49
49
// Memset Memstore UK https://auth.storage.memset.com/v1.0
50
50
// Memstore v2 https://auth.storage.memset.com/v2.0
51
+ //
52
+ // When using Google Appengine you must provide the Connection with an appengine-specific Transport:
53
+ //
54
+ // import (
55
+ // "appengine/urlfetch"
56
+ // "fmt"
57
+ // "github.com/ncw/swift"
58
+ // )
59
+ //
60
+ // func handler(w http.ResponseWriter, r *http.Request) {
61
+ // ctx := appengine.NewContext(r)
62
+ // tr := urlfetch.Transport{Context: ctx}
63
+ // c := swift.Connection{
64
+ // UserName: "user",
65
+ // ApiKey: "key",
66
+ // AuthUrl: "auth_url",
67
+ // Transport: tr,
68
+ // }
69
+ // _ := c.Authenticate()
70
+ // containers, _ := c.ContainerNames(nil)
71
+ // fmt.Fprintf(w, "containers: %q", containers)
72
+ // }
51
73
type Connection struct {
52
74
// Parameters - fill these in before calling Authenticate
53
75
// They are all optional except UserName, ApiKey and AuthUrl
54
- UserName string // UserName for api
55
- ApiKey string // Key for api access
56
- AuthUrl string // Auth URL
57
- Retries int // Retries on error (default is 3)
58
- UserAgent string // Http User agent (default goswift/1.0)
59
- ConnectTimeout time.Duration // Connect channel timeout (default 10s)
60
- Timeout time.Duration // Data channel timeout (default 60s)
61
- Region string // Region to use eg "LON", "ORD" - default is use first region (V2 auth only)
62
- AuthVersion int // Set to 1 or 2 or leave at 0 for autodetect
63
- Internal bool // Set this to true to use the the internal / service network
64
- Tenant string // Name of the tenant (v2 auth only)
65
- TenantId string // Id of the tenant (v2 auth only)
76
+ UserName string // UserName for api
77
+ ApiKey string // Key for api access
78
+ AuthUrl string // Auth URL
79
+ Retries int // Retries on error (default is 3)
80
+ UserAgent string // Http User agent (default goswift/1.0)
81
+ ConnectTimeout time.Duration // Connect channel timeout (default 10s)
82
+ Timeout time.Duration // Data channel timeout (default 60s)
83
+ Region string // Region to use eg "LON", "ORD" - default is use first region (V2 auth only)
84
+ AuthVersion int // Set to 1 or 2 or leave at 0 for autodetect
85
+ Internal bool // Set this to true to use the the internal / service network
86
+ Tenant string // Name of the tenant (v2 auth only)
87
+ TenantId string // Id of the tenant (v2 auth only)
88
+ Transport http.RoundTripper // Optional specialised http.Transport (eg. for Google Appengine)
66
89
// These are filled in after Authenticate is called as are the defaults for above
67
90
storageUrl string
68
91
authToken string
69
- tr * http.Transport
70
92
client * http.Client
71
93
Auth Authenticator // the current authenticator
72
94
}
@@ -191,7 +213,7 @@ func (c *Connection) doTimeoutRequest(timer *time.Timer, req *http.Request) (*ht
191
213
return r .resp , r .err
192
214
case <- timer .C :
193
215
// Kill the connection on timeout so we don't leak sockets or goroutines
194
- cancelRequest (c .tr , req )
216
+ cancelRequest (c .Transport , req )
195
217
return nil , TimeoutError
196
218
}
197
219
panic ("unreachable" ) // For Go 1.0
@@ -212,8 +234,8 @@ func (c *Connection) Authenticate() (err error) {
212
234
if c .Timeout == 0 {
213
235
c .Timeout = 60 * time .Second
214
236
}
215
- if c .tr == nil {
216
- c .tr = & http.Transport {
237
+ if c .Transport == nil {
238
+ c .Transport = & http.Transport {
217
239
// TLSClientConfig: &tls.Config{RootCAs: pool},
218
240
// DisableCompression: true,
219
241
MaxIdleConnsPerHost : 2048 ,
@@ -222,12 +244,12 @@ func (c *Connection) Authenticate() (err error) {
222
244
if c .client == nil {
223
245
c .client = & http.Client {
224
246
// CheckRedirect: redirectPolicyFunc,
225
- Transport : c .tr ,
247
+ Transport : c .Transport ,
226
248
}
227
249
}
228
250
// Flush the keepalives connection - if we are
229
251
// re-authenticating then stuff has gone wrong
230
- c . tr . CloseIdleConnections ( )
252
+ flushKeepaliveConnections ( c . Transport )
231
253
c .Auth , err = newAuth (c .AuthUrl , c .AuthVersion )
232
254
if err != nil {
233
255
return err
@@ -245,7 +267,7 @@ func (c *Connection) Authenticate() (err error) {
245
267
checkClose (resp .Body , & err )
246
268
// Flush the auth connection - we don't want to keep
247
269
// it open if keepalives were enabled
248
- c . tr . CloseIdleConnections ( )
270
+ flushKeepaliveConnections ( c . Transport )
249
271
}()
250
272
if err = c .parseHeaders (resp , authErrorMap ); err != nil {
251
273
return
@@ -262,6 +284,15 @@ func (c *Connection) Authenticate() (err error) {
262
284
return nil
263
285
}
264
286
287
+ // flushKeepaliveConnections is called to flush pending requests after an error.
288
+ func flushKeepaliveConnections (transport http.RoundTripper ) {
289
+ if tr , ok := transport .(interface {
290
+ CloseIdleConnections ()
291
+ }); ok {
292
+ tr .CloseIdleConnections ()
293
+ }
294
+ }
295
+
265
296
// UnAuthenticate removes the authentication from the Connection.
266
297
func (c * Connection ) UnAuthenticate () {
267
298
c .storageUrl = ""
@@ -374,7 +405,7 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
374
405
} else {
375
406
// Cancel the request on timeout
376
407
cancel := func () {
377
- cancelRequest (c .tr , req )
408
+ cancelRequest (c .Transport , req )
378
409
}
379
410
// Wrap resp.Body to make it obey an idle timeout
380
411
resp .Body = newTimeoutReader (resp .Body , c .Timeout , cancel )
0 commit comments