diff --git a/doc/go1.html b/doc/go1.html index 4191c4ba25d..e3d2354e64e 100644 --- a/doc/go1.html +++ b/doc/go1.html @@ -1146,10 +1146,16 @@ The affected items are:
-Also, the Request.RawURL
field has been removed; it was a
+The Request.RawURL
field has been removed; it was a
historical artifact.
+The Handle
and HandleFunc
+functions, and the similarly-named methods of ServeMux
,
+now panic if an attempt is made to register the same pattern twice.
+
Updating:
Running go fix
will update the few programs that are affected except for
diff --git a/doc/go1.tmpl b/doc/go1.tmpl
index 819c71ed388..8f276827807 100644
--- a/doc/go1.tmpl
+++ b/doc/go1.tmpl
@@ -1049,10 +1049,16 @@ The affected items are:
-Also, the Request.RawURL
field has been removed; it was a
+The Request.RawURL
field has been removed; it was a
historical artifact.
+The Handle
and HandleFunc
+functions, and the similarly-named methods of ServeMux
,
+now panic if an attempt is made to register the same pattern twice.
+
Updating:
Running go fix
will update the few programs that are affected except for
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 288539ba576..8c4822ec748 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -833,11 +833,17 @@ func RedirectHandler(url string, code int) Handler {
// redirecting any request containing . or .. elements to an
// equivalent .- and ..-free URL.
type ServeMux struct {
- m map[string]Handler
+ mu sync.RWMutex
+ m map[string]muxEntry
+}
+
+type muxEntry struct {
+ explicit bool
+ h Handler
}
// NewServeMux allocates and returns a new ServeMux.
-func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }
+func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()
@@ -883,12 +889,28 @@ func (mux *ServeMux) match(path string) Handler {
}
if h == nil || len(k) > n {
n = len(k)
- h = v
+ h = v.h
}
}
return h
}
+// handler returns the handler to use for the request r.
+func (mux *ServeMux) handler(r *Request) Handler {
+ mux.mu.RLock()
+ defer mux.mu.RUnlock()
+
+ // Host-specific pattern takes precedence over generic ones
+ h := mux.match(r.Host + r.URL.Path)
+ if h == nil {
+ h = mux.match(r.URL.Path)
+ }
+ if h == nil {
+ h = NotFoundHandler()
+ }
+ return h
+}
+
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
@@ -898,30 +920,33 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
w.WriteHeader(StatusMovedPermanently)
return
}
- // Host-specific pattern takes precedence over generic ones
- h := mux.match(r.Host + r.URL.Path)
- if h == nil {
- h = mux.match(r.URL.Path)
- }
- if h == nil {
- h = NotFoundHandler()
- }
- h.ServeHTTP(w, r)
+ mux.handler(r).ServeHTTP(w, r)
}
// Handle registers the handler for the given pattern.
+// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
+ mux.mu.Lock()
+ defer mux.mu.Unlock()
+
if pattern == "" {
panic("http: invalid pattern " + pattern)
}
+ if handler == nil {
+ panic("http: nil handler")
+ }
+ if mux.m[pattern].explicit {
+ panic("http: multiple registrations for " + pattern)
+ }
- mux.m[pattern] = handler
+ mux.m[pattern] = muxEntry{explicit: true, h: handler}
// Helpful behavior:
- // If pattern is /tree/, insert permanent redirect for /tree.
+ // If pattern is /tree/, insert an implicit permanent redirect for /tree.
+ // It can be overridden by an explicit registration.
n := len(pattern)
- if n > 0 && pattern[n-1] == '/' {
- mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently)
+ if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {
+ mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(pattern, StatusMovedPermanently)}
}
}