diff --git a/cmd/imageproxy/main.go b/cmd/imageproxy/main.go index 9d3bcd9..2fea6a7 100644 --- a/cmd/imageproxy/main.go +++ b/cmd/imageproxy/main.go @@ -45,6 +45,7 @@ var baseURL = flag.String("baseURL", "", "default base URL for relative remote U var cacheDir = flag.String("cacheDir", "", "directory to use for file cache") var cacheSize = flag.Uint64("cacheSize", 100, "maximum size of file cache (in MB)") var signatureKey = flag.String("signatureKey", "", "HMAC key used in calculating request signatures") +var scaleUp = flag.Bool("scaleUp", false, "allow images to scale beyond their original dimensions") var version = flag.Bool("version", false, "print version information") func main() { @@ -90,6 +91,8 @@ func main() { } } + p.ScaleUp = *scaleUp + server := &http.Server{ Addr: *addr, Handler: p, diff --git a/data.go b/data.go index 406742e..a311505 100644 --- a/data.go +++ b/data.go @@ -65,6 +65,9 @@ type Options struct { // HMAC Signature for signed requests. Signature string + + // Allow images to scale beyond their original dimensions. + ScaleUp bool } var emptyOptions = Options{} diff --git a/data_test.go b/data_test.go index e799854..5d63d35 100644 --- a/data_test.go +++ b/data_test.go @@ -29,11 +29,11 @@ func TestOptions_String(t *testing.T) { "0x0", }, { - Options{1, 2, true, 90, true, true, 80, ""}, + Options{1, 2, true, 90, true, true, 80, "", false}, "1x2,fit,r90,fv,fh,q80", }, { - Options{0.15, 1.3, false, 45, false, false, 95, "c0ffee"}, + Options{0.15, 1.3, false, 45, false, false, 95, "c0ffee", false}, "0.15x1.3,r45,q95,sc0ffee", }, } @@ -82,8 +82,8 @@ func TestParseOptions(t *testing.T) { {"FOO,1,BAR,r90,BAZ", Options{Width: 1, Height: 1, Rotate: 90}}, // all flags, in different orders - {"q70,1x2,fit,r90,fv,fh,sc0ffee", Options{1, 2, true, 90, true, true, 70, "c0ffee"}}, - {"r90,fh,sc0ffee,q90,1x2,fv,fit", Options{1, 2, true, 90, true, true, 90, "c0ffee"}}, + {"q70,1x2,fit,r90,fv,fh,sc0ffee", Options{1, 2, true, 90, true, true, 70, "c0ffee", false}}, + {"r90,fh,sc0ffee,q90,1x2,fv,fit", Options{1, 2, true, 90, true, true, 90, "c0ffee", false}}, } for _, tt := range tests { diff --git a/imageproxy.go b/imageproxy.go index ee000da..9ce9817 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -54,6 +54,9 @@ type Proxy struct { // SignatureKey is the HMAC key used to verify signed requests. SignatureKey []byte + + // Allow images to scale beyond their original dimensions. + ScaleUp bool } // NewProxy constructs a new proxy. The provided http RoundTripper will be @@ -67,17 +70,20 @@ func NewProxy(transport http.RoundTripper, cache Cache) *Proxy { cache = NopCache } + proxy := Proxy{ + Cache: cache, + } + client := new(http.Client) client.Transport = &httpcache.Transport{ - Transport: &TransformingTransport{transport, client}, + Transport: &TransformingTransport{transport, client, &proxy}, Cache: cache, MarkCachedResponses: true, } - return &Proxy{ - Client: client, - Cache: cache, - } + proxy.Client = client + + return &proxy } // ServeHTTP handles image requests. @@ -232,6 +238,9 @@ type TransformingTransport struct { // used rather than Transport directly in order to ensure that // responses are properly cached. CachingClient *http.Client + + // Proxy is used to access command line flag settings during roundtripping. + Proxy *Proxy } // RoundTrip implements the http.RoundTripper interface. @@ -256,6 +265,12 @@ func (t *TransformingTransport) RoundTrip(req *http.Request) (*http.Response, er } opt := ParseOptions(req.URL.Fragment) + + // assign static settings from proxy to options + if t.Proxy != nil { + opt.ScaleUp = t.Proxy.ScaleUp + } + img, err := Transform(b, opt) if err != nil { glog.Errorf("error transforming image: %v", err) diff --git a/imageproxy_test.go b/imageproxy_test.go index 7e27917..7ac5c68 100644 --- a/imageproxy_test.go +++ b/imageproxy_test.go @@ -12,6 +12,8 @@ import ( "net/url" "strings" "testing" + + "github.com/gregjones/httpcache" ) func TestAllowed(t *testing.T) { @@ -187,6 +189,15 @@ func TestCheck304(t *testing.T) { } } +// make sure that the proxy is passed to transport in order +// to access the command line flags. +func TestProxyPointer(t *testing.T) { + p := NewProxy(nil, nil) + if p.Client.Transport.(*httpcache.Transport).Transport.(*TransformingTransport).Proxy != p { + t.Errorf("Transport doesnt have proxy pointer") + } +} + // testTransport is an http.RoundTripper that returns certained canned // responses for particular requests. type testTransport struct{} @@ -272,7 +283,10 @@ func TestProxy_ServeHTTP_is304(t *testing.T) { func TestTransformingTransport(t *testing.T) { client := new(http.Client) - tr := &TransformingTransport{testTransport{}, client} + tr := &TransformingTransport{ + Transport: testTransport{}, + CachingClient: client, + } client.Transport = tr tests := []struct { diff --git a/transform.go b/transform.go index 4302aed..f199eb3 100644 --- a/transform.go +++ b/transform.go @@ -102,11 +102,13 @@ func transformImage(m image.Image, opt Options) image.Image { } // never resize larger than the original image - if w > imgW { - w = imgW - } - if h > imgH { - h = imgH + if !opt.ScaleUp { + if w > imgW { + w = imgW + } + if h > imgH { + h = imgH + } } // resize diff --git a/transform_test.go b/transform_test.go index 60efde5..3c4b465 100644 --- a/transform_test.go +++ b/transform_test.go @@ -127,6 +127,11 @@ func TestTransformImage(t *testing.T) { Options{Width: 100, Height: 100}, ref, }, + { // can resize larger than original image + ref, + Options{Width: 4, Height: 4, ScaleUp: true}, + newImage(4, 4, red, red, green, green, red, red, green, green, blue, blue, yellow, yellow, blue, blue, yellow, yellow), + }, { // invalid values ref, Options{Width: -1, Height: -1},