// ServeHTTP dispatches the handler registered in the matched route. // // When there is a match, the route variables can be retrieved calling // mux.Vars(request). func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Clean path to canonical form and redirect. if p := cleanPath(req.URL.Path); p != req.URL.Path { // Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query. // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: // http://code.google.com/p/go/issues/detail?id=5252 url := *req.URL url.Path = p p = url.String() w.Header().Set("Location", p) w.WriteHeader(http.StatusMovedPermanently) return } var match RouteMatch var handler http.Handler if r.Match(req, &match) { handler = match.Handler setVars(req, match.Vars) setCurrentRoute(req, match.Route) } if handler == nil { handler = r.NotFoundHandler if handler == nil { handler = http.NotFoundHandler() } } if !r.KeepContext { defer context.Clear(req) } handler.ServeHTTP(w, req) }
// Implements http.Handler for the csrf type. func (cs *csrf) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Retrieve the token from the session. // An error represents either a cookie that failed HMAC validation // or that doesn't exist. realToken, err := cs.st.Get(r) if err != nil || len(realToken) != tokenLength { // If there was an error retrieving the token, the token doesn't exist // yet, or it's the wrong length, generate a new token. // Note that the new token will (correctly) fail validation downstream // as it will no longer match the request token. realToken, err = generateRandomBytes(tokenLength) if err != nil { envError(r, err) cs.opts.ErrorHandler.ServeHTTP(w, r) return } // Save the new (real) token in the session store. err = cs.st.Save(realToken, w) if err != nil { envError(r, err) cs.opts.ErrorHandler.ServeHTTP(w, r) return } } // Save the masked token to the request context context.Set(r, tokenKey, mask(realToken, r)) // HTTP methods not defined as idempotent ("safe") under RFC7231 require // inspection. if !contains(safeMethods, r.Method) { // Enforce an origin check for HTTPS connections. As per the Django CSRF // implementation (https://goo.gl/vKA7GE) the Referer header is almost // always present for same-domain HTTP requests. if r.URL.Scheme == "https" { // Fetch the Referer value. Call the error handler if it's empty or // otherwise fails to parse. referer, err := url.Parse(r.Referer()) if err != nil || referer.String() == "" { envError(r, ErrNoReferer) cs.opts.ErrorHandler.ServeHTTP(w, r) return } if sameOrigin(r.URL, referer) == false { envError(r, ErrBadReferer) cs.opts.ErrorHandler.ServeHTTP(w, r) return } } // If the token returned from the session store is nil for non-idempotent // ("unsafe") methods, call the error handler. if realToken == nil { envError(r, ErrNoToken) cs.opts.ErrorHandler.ServeHTTP(w, r) return } // Retrieve the combined token (pad + masked) token and unmask it. requestToken := unmask(cs.requestToken(r)) // Compare the request token against the real token if !compareTokens(requestToken, realToken) { envError(r, ErrBadToken) cs.opts.ErrorHandler.ServeHTTP(w, r) return } } // Set the Vary: Cookie header to protect clients from caching the response. w.Header().Add("Vary", "Cookie") // Call the wrapped handler/router on success. cs.h.ServeHTTP(w, r) // Clear the request context after the handler has completed. context.Clear(r) }