github.com/xmidt-org/webpa-common@v1.11.9/service/servicehttp/redirectHandler.go (about) 1 package servicehttp 2 3 import ( 4 "net/http" 5 "strings" 6 7 "github.com/go-kit/kit/log/level" 8 "github.com/xmidt-org/webpa-common/logging" 9 "github.com/xmidt-org/webpa-common/service" 10 ) 11 12 // KeyFunc examines an HTTP request and produces the service key to use when finding 13 // an instance to use. 14 // 15 // The device.IDHashParser function is a valid KeyFunc, and is the typical one used by WebPA. 16 type KeyFunc func(*http.Request) ([]byte, error) 17 18 // RedirectHandler is an http.Handler that redirects all incoming requests using a key obtained 19 // from a request. The Accessor is passed the key to return the appropriate instance to redirect to. 20 type RedirectHandler struct { 21 // KeyFunc is the function used to extract a hash key from a request 22 KeyFunc KeyFunc 23 24 // Accessor produces instances given hash keys. Note that a Subscription implements the Accessor interface. 25 Accessor service.Accessor 26 27 // RedirectCode is the HTTP status code sent as part of the redirect. If not set, http.StatusTemporaryRedirect is used. 28 RedirectCode int 29 } 30 31 func (rh *RedirectHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) { 32 key, err := rh.KeyFunc(request) 33 ctxLogger := logging.GetLogger(request.Context()) 34 if err != nil { 35 ctxLogger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "unable to obtain service key from request", logging.ErrorKey(), err) 36 http.Error(response, err.Error(), http.StatusBadRequest) 37 return 38 } 39 40 instance, err := rh.Accessor.Get(key) 41 if err != nil && instance == "" { 42 ctxLogger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "accessor failed to return an instance", logging.ErrorKey(), err) 43 http.Error(response, err.Error(), http.StatusInternalServerError) 44 return 45 } 46 47 instance += strings.TrimRight(request.RequestURI, "/") 48 ctxLogger.Log(level.Key(), level.DebugValue(), logging.MessageKey(), "redirecting", "instance", instance) 49 50 code := rh.RedirectCode 51 if code < 300 { 52 code = http.StatusTemporaryRedirect 53 } 54 55 http.Redirect(response, request, instance, code) 56 }