github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/resource/api/private/server/handler.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package server 5 6 // TODO(ericsnow) Eliminate the apiserver dependencies, if possible. 7 8 import ( 9 "io" 10 "net/http" 11 12 "github.com/juju/errors" 13 14 "github.com/juju/juju/resource" 15 "github.com/juju/juju/resource/api" 16 ) 17 18 // TODO(ericsnow) Define the HTTPHandlerConstraints here? Perhaps 19 // even the HTTPHandlerSpec? 20 21 // LegacyHTTPHandler is the HTTP handler for the resources 22 // endpoint. We use it rather having a separate handler for each HTTP 23 // method since registered API handlers must handle *all* HTTP methods 24 // currently. 25 type LegacyHTTPHandler struct { 26 LegacyHTTPHandlerDeps 27 } 28 29 // NewLegacyHTTPHandler creates a new http.Handler for the resources endpoint. 30 func NewLegacyHTTPHandler(deps LegacyHTTPHandlerDeps) *LegacyHTTPHandler { 31 return &LegacyHTTPHandler{ 32 LegacyHTTPHandlerDeps: deps, 33 } 34 } 35 36 // ServeHTTP implements http.Handler. 37 func (h *LegacyHTTPHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 38 opener, err := h.NewResourceOpener(req) 39 if err != nil { 40 h.SendHTTPError(resp, err) 41 return 42 } 43 44 // We do this *after* authorization, etc. (in h.Extract...) in order 45 // to prioritize errors that may originate there. 46 switch req.Method { 47 case "GET": 48 logger.Infof("handling resource download request") 49 50 opened, err := h.HandleDownload(opener, req) 51 if err != nil { 52 logger.Errorf("cannot fetch resource reader: %v", err) 53 h.SendHTTPError(resp, err) 54 return 55 } 56 defer opened.Close() 57 58 h.UpdateDownloadResponse(resp, opened.Resource) 59 60 resp.WriteHeader(http.StatusOK) 61 if err := h.Copy(resp, opened); err != nil { 62 // We cannot use api.SendHTTPError here, so we log the error 63 // and move on. 64 logger.Errorf("unable to complete stream for resource: %v", err) 65 return 66 } 67 68 logger.Infof("resource download request successful") 69 default: 70 h.SendHTTPError(resp, errors.MethodNotAllowedf("unsupported method: %q", req.Method)) 71 } 72 } 73 74 // LegacyHTTPHandlerDeps exposes the external dependencies 75 // of LegacyHTTPHandler. 76 type LegacyHTTPHandlerDeps interface { 77 baseLegacyHTTPHandlerDeps 78 ExtraDeps 79 } 80 81 //ExtraDeps exposes the non-superficial dependencies of LegacyHTTPHandler. 82 type ExtraDeps interface { 83 // NewResourceOpener returns a new opener for the request. 84 NewResourceOpener(*http.Request) (resource.Opener, error) 85 } 86 87 type baseLegacyHTTPHandlerDeps interface { 88 // UpdateDownloadResponse updates the HTTP response with the info 89 // from the resource. 90 UpdateDownloadResponse(http.ResponseWriter, resource.Resource) 91 92 // SendHTTPError wraps the error in an API error and writes it to the response. 93 SendHTTPError(http.ResponseWriter, error) 94 95 // HandleDownload provides the download functionality. 96 HandleDownload(resource.Opener, *http.Request) (resource.Opened, error) 97 98 // Copy implements the functionality of io.Copy(). 99 Copy(io.Writer, io.Reader) error 100 } 101 102 // NewLegacyHTTPHandlerDeps returns an implementation of LegacyHTTPHandlerDeps. 103 func NewLegacyHTTPHandlerDeps(extraDeps ExtraDeps) LegacyHTTPHandlerDeps { 104 return &legacyHTTPHandlerDeps{ 105 ExtraDeps: extraDeps, 106 } 107 } 108 109 // legacyHTTPHandlerDeps is a partial implementation of LegacyHandlerDeps. 110 type legacyHTTPHandlerDeps struct { 111 ExtraDeps 112 } 113 114 // SendHTTPError implements LegacyHTTPHandlerDeps. 115 func (deps legacyHTTPHandlerDeps) SendHTTPError(resp http.ResponseWriter, err error) { 116 api.SendHTTPError(resp, err) 117 } 118 119 // UpdateDownloadResponse implements LegacyHTTPHandlerDeps. 120 func (deps legacyHTTPHandlerDeps) UpdateDownloadResponse(resp http.ResponseWriter, info resource.Resource) { 121 api.UpdateDownloadResponse(resp, info) 122 } 123 124 // HandleDownload implements LegacyHTTPHandlerDeps. 125 func (deps legacyHTTPHandlerDeps) HandleDownload(opener resource.Opener, req *http.Request) (resource.Opened, error) { 126 name := api.ExtractDownloadRequest(req) 127 return opener.OpenResource(name) 128 } 129 130 // Copy implements LegacyHTTPHandlerDeps. 131 func (deps legacyHTTPHandlerDeps) Copy(w io.Writer, r io.Reader) error { 132 _, err := io.Copy(w, r) 133 return err 134 }