1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2024-12-04 09:42:31 +02:00
imgproxy/transport/swift/swift.go
Joe Cai 7a2296aee8
Support OpenStack Swift Object Storage (#837)
* Add OpenStack Swift support

* Fix linting errors

* Update CHANGELOG

* Update swift documentation

* Fix linting error

* Swift transport: pass req.Context down, fix parseObjectURL() implementation

* Make swift transport test a test suite

* Use swift://{container}/{object_path} as the source image URL format

* Cleanup

* Swift transport: only close object when returning 304
2022-04-06 17:00:19 +06:00

89 lines
2.0 KiB
Go

package swift
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/imgproxy/imgproxy/v3/config"
"github.com/ncw/swift/v2"
)
type transport struct {
con *swift.Connection
}
func New() (http.RoundTripper, error) {
c := &swift.Connection{
UserName: config.SwiftUsername,
ApiKey: config.SwiftAPIKey,
AuthUrl: config.SwiftAuthURL,
AuthVersion: config.SwiftAuthVersion,
Domain: config.SwiftDomain, // v3 auth only
Tenant: config.SwiftTenant, // v2 auth only
Timeout: time.Duration(config.SwiftTimeoutSeconds) * time.Second,
ConnectTimeout: time.Duration(config.SwiftConnectTimeoutSeconds) * time.Second,
}
ctx := context.Background()
err := c.Authenticate(ctx)
if err != nil {
return nil, fmt.Errorf("swift authentication error: %s", err)
}
return transport{con: c}, nil
}
func (t transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
// Users should have converted the object storage URL in the format of swift://{container}/{object}
container := req.URL.Host
objectName := strings.TrimPrefix(req.URL.Path, "/")
headers := make(swift.Headers)
object, headers, err := t.con.ObjectOpen(req.Context(), container, objectName, false, headers)
if err != nil {
return nil, fmt.Errorf("error opening object: %v", err)
}
header := make(http.Header)
if config.ETagEnabled {
if etag, ok := headers["Etag"]; ok {
header.Set("ETag", etag)
if len(etag) > 0 && etag == req.Header.Get("If-None-Match") {
object.Close()
return &http.Response{
StatusCode: http.StatusNotModified,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: header,
ContentLength: 0,
Body: nil,
Close: false,
Request: req,
}, nil
}
}
}
return &http.Response{
Status: "200 OK",
StatusCode: 200,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: header,
Body: object,
Close: true,
Request: req,
}, nil
}