|
|
|
|
@ -70,12 +70,14 @@ |
|
|
|
|
package safeweb |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"cmp" |
|
|
|
|
crand "crypto/rand" |
|
|
|
|
"fmt" |
|
|
|
|
"log" |
|
|
|
|
"net" |
|
|
|
|
"net/http" |
|
|
|
|
"net/url" |
|
|
|
|
"path" |
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
"github.com/gorilla/csrf" |
|
|
|
|
@ -195,6 +197,30 @@ func NewServer(config Config) (*Server, error) { |
|
|
|
|
return s, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type handlerType int |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
unknownHandler handlerType = iota |
|
|
|
|
apiHandler |
|
|
|
|
browserHandler |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// checkHandlerType returns either apiHandler or browserHandler, depending on
|
|
|
|
|
// whether apiPattern or browserPattern is more specific (i.e. which pattern
|
|
|
|
|
// contains more pathname components). If they are equally specific, it returns
|
|
|
|
|
// unknownHandler.
|
|
|
|
|
func checkHandlerType(apiPattern, browserPattern string) handlerType { |
|
|
|
|
c := cmp.Compare(strings.Count(path.Clean(apiPattern), "/"), strings.Count(path.Clean(browserPattern), "/")) |
|
|
|
|
switch { |
|
|
|
|
case c > 0: |
|
|
|
|
return apiHandler |
|
|
|
|
case c < 0: |
|
|
|
|
return browserHandler |
|
|
|
|
default: |
|
|
|
|
return unknownHandler |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
_, bp := s.BrowserMux.Handler(r) |
|
|
|
|
_, ap := s.APIMux.Handler(r) |
|
|
|
|
@ -206,24 +232,25 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
case bp == "" && ap == "": // neither match
|
|
|
|
|
http.NotFound(w, r) |
|
|
|
|
case bp != "" && ap != "": |
|
|
|
|
// Both muxes match the path. This can be because:
|
|
|
|
|
// * one of them registers a wildcard "/" handler
|
|
|
|
|
// * there are overlapping specific handlers
|
|
|
|
|
//
|
|
|
|
|
// If it's the former, route to the more-specific handler. If it's the
|
|
|
|
|
// latter - that's a bug so return an error to avoid mis-routing the
|
|
|
|
|
// request.
|
|
|
|
|
// Both muxes match the path. Route to the more-specific handler (as
|
|
|
|
|
// determined by the number of components in the path). If it somehow
|
|
|
|
|
// happens that both patterns are equally specific, something strange
|
|
|
|
|
// has happened; say so.
|
|
|
|
|
//
|
|
|
|
|
// TODO(awly): match the longest path instead of only special-casing
|
|
|
|
|
// "/".
|
|
|
|
|
switch { |
|
|
|
|
case bp == "/": |
|
|
|
|
// NOTE: checkHandlerType does not know about what the serve* handlers
|
|
|
|
|
// will do — including, possibly, redirecting to more specific patterns.
|
|
|
|
|
// If you have a less-specific pattern that redirects to something more
|
|
|
|
|
// specific, this logic will not do what you wanted.
|
|
|
|
|
handler := checkHandlerType(ap, bp) |
|
|
|
|
switch handler { |
|
|
|
|
case apiHandler: |
|
|
|
|
s.serveAPI(w, r) |
|
|
|
|
case ap == "/": |
|
|
|
|
case browserHandler: |
|
|
|
|
s.serveBrowser(w, r) |
|
|
|
|
default: |
|
|
|
|
log.Printf("conflicting mux paths in safeweb: request %q matches browser mux pattern %q and API mux patter %q; returning 500", r.URL.Path, bp, ap) |
|
|
|
|
http.Error(w, "multiple handlers match this request", http.StatusInternalServerError) |
|
|
|
|
s := http.StatusInternalServerError |
|
|
|
|
log.Printf("conflicting mux paths in safeweb: request %q matches browser mux pattern %q and API mux pattern %q; returning %d", r.URL.Path, bp, ap, s) |
|
|
|
|
http.Error(w, "multiple handlers match this request", s) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|