107 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
| package storage
 | |
| 
 | |
| import (
 | |
| 	"crypto/x509"
 | |
| 	"encoding/pem"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/crowdmob/goamz/cloudfront"
 | |
| 	"github.com/docker/distribution/storagedriver"
 | |
| )
 | |
| 
 | |
| // cloudFrontLayerHandler provides an simple implementation of layerHandler that
 | |
| // constructs temporary signed CloudFront URLs from the storagedriver layer URL,
 | |
| // then issues HTTP Temporary Redirects to this CloudFront content URL.
 | |
| type cloudFrontLayerHandler struct {
 | |
| 	cloudfront           *cloudfront.CloudFront
 | |
| 	delegateLayerHandler *delegateLayerHandler
 | |
| }
 | |
| 
 | |
| var _ LayerHandler = &cloudFrontLayerHandler{}
 | |
| 
 | |
| // newCloudFrontLayerHandler constructs and returns a new CloudFront
 | |
| // LayerHandler implementation.
 | |
| // Required options: baseurl, privatekey, keypairid
 | |
| func newCloudFrontLayerHandler(storageDriver storagedriver.StorageDriver, options map[string]interface{}) (LayerHandler, error) {
 | |
| 	base, ok := options["baseurl"]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("No baseurl provided")
 | |
| 	}
 | |
| 	baseURL, ok := base.(string)
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("baseurl must be a string")
 | |
| 	}
 | |
| 	pk, ok := options["privatekey"]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("No privatekey provided")
 | |
| 	}
 | |
| 	pkPath, ok := pk.(string)
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("privatekey must be a string")
 | |
| 	}
 | |
| 	kpid, ok := options["keypairid"]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("No keypairid provided")
 | |
| 	}
 | |
| 	keypairID, ok := kpid.(string)
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("keypairid must be a string")
 | |
| 	}
 | |
| 
 | |
| 	pkBytes, err := ioutil.ReadFile(pkPath)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("Failed to read privatekey file: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	block, _ := pem.Decode([]byte(pkBytes))
 | |
| 	if block == nil {
 | |
| 		return nil, fmt.Errorf("Failed to decode private key as an rsa private key")
 | |
| 	}
 | |
| 	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	lh, err := newDelegateLayerHandler(storageDriver, options)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	dlh := lh.(*delegateLayerHandler)
 | |
| 
 | |
| 	cf := cloudfront.New(baseURL, privateKey, keypairID)
 | |
| 
 | |
| 	return &cloudFrontLayerHandler{cloudfront: cf, delegateLayerHandler: dlh}, nil
 | |
| }
 | |
| 
 | |
| // Resolve returns an http.Handler which can serve the contents of the given
 | |
| // Layer, or an error if not supported by the storagedriver.
 | |
| func (lh *cloudFrontLayerHandler) Resolve(layer Layer) (http.Handler, error) {
 | |
| 	layerURLStr, err := lh.delegateLayerHandler.urlFor(layer)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	layerURL, err := url.Parse(layerURLStr)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	cfURL, err := lh.cloudfront.CannedSignedURL(layerURL.Path, "", time.Now().Add(time.Minute))
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | |
| 		http.Redirect(w, r, cfURL, http.StatusTemporaryRedirect)
 | |
| 	}), nil
 | |
| }
 | |
| 
 | |
| // init registers the cloudfront layerHandler backend.
 | |
| func init() {
 | |
| 	RegisterLayerHandler("cloudfront", LayerHandlerInitFunc(newCloudFrontLayerHandler))
 | |
| }
 |