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  }