github.com/volatiletech/authboss@v2.4.1+incompatible/defaults/responder.go (about) 1 package defaults 2 3 import ( 4 "net/http" 5 "strings" 6 7 "github.com/volatiletech/authboss" 8 ) 9 10 // Responder helps respond to http requests 11 type Responder struct { 12 Renderer authboss.Renderer 13 } 14 15 // NewResponder constructor 16 func NewResponder(renderer authboss.Renderer) *Responder { 17 return &Responder{Renderer: renderer} 18 } 19 20 // Respond to an HTTP request. It's main job is to merge data that comes in from 21 // various middlewares via the context with the data sent by the controller and 22 // render that. 23 func (r *Responder) Respond(w http.ResponseWriter, req *http.Request, code int, page string, data authboss.HTMLData) error { 24 ctxData := req.Context().Value(authboss.CTXKeyData) 25 if ctxData != nil { 26 if data == nil { 27 data = authboss.HTMLData{} 28 } 29 data.Merge(ctxData.(authboss.HTMLData)) 30 } 31 32 rendered, mime, err := r.Renderer.Render(req.Context(), page, data) 33 if err != nil { 34 return err 35 } 36 37 w.Header().Set("Content-Type", mime) 38 w.WriteHeader(code) 39 40 _, err = w.Write(rendered) 41 return err 42 } 43 44 func isAPIRequest(r *http.Request) bool { 45 return strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") 46 } 47 48 // Redirector for http requests 49 type Redirector struct { 50 Renderer authboss.Renderer 51 52 // FormValueName for the redirection 53 FormValueName string 54 55 // CoerceRedirectTo200 forces http.StatusTemporaryRedirect and 56 // and http.StatusPermanentRedirect to http.StatusOK 57 CorceRedirectTo200 bool 58 } 59 60 // NewRedirector constructor 61 func NewRedirector(renderer authboss.Renderer, formValueName string) *Redirector { 62 return &Redirector{FormValueName: formValueName, Renderer: renderer} 63 } 64 65 // Redirect the client elsewhere. If it's an API request it will simply render 66 // a JSON response with information that should help a client to decide what 67 // to do. 68 func (r *Redirector) Redirect(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error { 69 var redirectFunction = r.redirectNonAPI 70 if isAPIRequest(req) { 71 redirectFunction = r.redirectAPI 72 } 73 74 return redirectFunction(w, req, ro) 75 } 76 77 func (r Redirector) redirectAPI(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error { 78 path := ro.RedirectPath 79 redir := req.FormValue(r.FormValueName) 80 if len(redir) != 0 && ro.FollowRedirParam { 81 path = redir 82 } 83 84 var status = "success" 85 var message string 86 if len(ro.Success) != 0 { 87 message = ro.Success 88 } 89 if len(ro.Failure) != 0 { 90 status = "failure" 91 message = ro.Failure 92 } 93 94 data := authboss.HTMLData{ 95 "location": path, 96 } 97 98 data["status"] = status 99 if len(message) != 0 { 100 data["message"] = message 101 } 102 103 body, mime, err := r.Renderer.Render(req.Context(), "redirect", data) 104 if err != nil { 105 return err 106 } 107 108 if len(body) != 0 { 109 w.Header().Set("Content-Type", mime) 110 } 111 112 if ro.Code != 0 { 113 if r.CorceRedirectTo200 && (ro.Code == http.StatusTemporaryRedirect || ro.Code == http.StatusPermanentRedirect) { 114 w.WriteHeader(http.StatusOK) 115 } else { 116 w.WriteHeader(ro.Code) 117 } 118 } 119 _, err = w.Write(body) 120 return err 121 } 122 123 func (r Redirector) redirectNonAPI(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error { 124 path := ro.RedirectPath 125 redir := req.FormValue(r.FormValueName) 126 if len(redir) != 0 && ro.FollowRedirParam { 127 path = redir 128 } 129 130 if len(ro.Success) != 0 { 131 authboss.PutSession(w, authboss.FlashSuccessKey, ro.Success) 132 } 133 if len(ro.Failure) != 0 { 134 authboss.PutSession(w, authboss.FlashErrorKey, ro.Failure) 135 } 136 137 http.Redirect(w, req, path, http.StatusFound) 138 return nil 139 }