]> Cypherpunks repositories - gostls13.git/commitdiff
http: add host patterns
authorJose Luis Vázquez González <josvazg@gmail.com>
Tue, 1 Feb 2011 18:58:59 +0000 (13:58 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 1 Feb 2011 18:58:59 +0000 (13:58 -0500)
R=bradfitzgo, rsc
CC=golang-dev
https://golang.org/cl/4070043

src/pkg/http/serve_test.go
src/pkg/http/server.go

index 053d6dca448ec9697400938d56901d643b7bfef5..7da3fc6f3434c39a3b5bcc1a57f8d01e84c1a208 100644 (file)
@@ -136,6 +136,71 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
        }
 }
 
+type stringHandler string
+
+func (s stringHandler) ServeHTTP(w ResponseWriter, r *Request) {
+       w.SetHeader("Result", string(s))
+}
+
+var handlers = []struct {
+       pattern string
+       msg     string
+}{
+       {"/", "Default"},
+       {"/someDir/", "someDir"},
+       {"someHost.com/someDir/", "someHost.com/someDir"},
+}
+
+var vtests = []struct {
+       url      string
+       expected string
+}{
+       {"http://localhost/someDir/apage", "someDir"},
+       {"http://localhost/otherDir/apage", "Default"},
+       {"http://someHost.com/someDir/apage", "someHost.com/someDir"},
+       {"http://otherHost.com/someDir/apage", "someDir"},
+       {"http://otherHost.com/aDir/apage", "Default"},
+}
+
+func TestHostHandlers(t *testing.T) {
+       for _, h := range handlers {
+               Handle(h.pattern, stringHandler(h.msg))
+       }
+       l, err := net.Listen("tcp", "127.0.0.1:0") // any port
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer l.Close()
+       go Serve(l, nil)
+       conn, err := net.Dial("tcp", "", l.Addr().String())
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer conn.Close()
+       cc := NewClientConn(conn, nil)
+       for _, vt := range vtests {
+               var r *Response
+               var req Request
+               if req.URL, err = ParseURL(vt.url); err != nil {
+                       t.Errorf("cannot parse url: %v", err)
+                       continue
+               }
+               if err := cc.Write(&req); err != nil {
+                       t.Errorf("writing request: %v", err)
+                       continue
+               }
+               r, err := cc.Read()
+               if err != nil {
+                       t.Errorf("reading response: %v", err)
+                       continue
+               }
+               s := r.Header["Result"]
+               if s != vt.expected {
+                       t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected)
+               }
+       }
+}
+
 type responseWriterMethodCall struct {
        method                 string
        headerKey, headerValue string // if method == "SetHeader"
index 644724f58e6cc2d3388c4db86c704ea2725d2c8a..9eb70a4c7500569ac72bf6ffad65e92ed5e2f432 100644 (file)
@@ -539,9 +539,8 @@ func RedirectHandler(url string, code int) Handler {
 // patterns and calls the handler for the pattern that
 // most closely matches the URL.
 //
-// Patterns named fixed paths, like "/favicon.ico",
-// or subtrees, like "/images/" (note the trailing slash).
-// Patterns must begin with /.
+// Patterns named fixed, rooted paths, like "/favicon.ico",
+// or rooted subtrees, like "/images/" (note the trailing slash).
 // Longer patterns take precedence over shorter ones, so that
 // if there are handlers registered for both "/images/"
 // and "/images/thumbnails/", the latter handler will be
@@ -549,11 +548,11 @@ func RedirectHandler(url string, code int) Handler {
 // former will receiver requests for any other paths in the
 // "/images/" subtree.
 //
-// In the future, the pattern syntax may be relaxed to allow
-// an optional host-name at the beginning of the pattern,
-// so that a handler might register for the two patterns
-// "/codesearch" and "codesearch.google.com/"
-// without taking over requests for http://www.google.com/.
+// Patterns may optionally begin with a host name, restricting matches to
+// URLs on that host only.  Host-specific patterns take precedence over
+// general patterns, so that a handler might register for the two patterns
+// "/codesearch" and "codesearch.google.com/" without also taking over
+// requests for "http://www.google.com/".
 //
 // ServeMux also takes care of sanitizing the URL request path,
 // redirecting any request containing . or .. elements to an
@@ -598,21 +597,13 @@ func cleanPath(p string) string {
        return np
 }
 
-// ServeHTTP dispatches the request to the handler whose
-// pattern most closely matches the request URL.
-func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
-       // Clean path to canonical form and redirect.
-       if p := cleanPath(r.URL.Path); p != r.URL.Path {
-               w.SetHeader("Location", p)
-               w.WriteHeader(StatusMovedPermanently)
-               return
-       }
-
-       // Most-specific (longest) pattern wins.
+// Find a handler on a handler map given a path string
+// Most-specific (longest) pattern wins
+func (mux *ServeMux) match(path string) Handler {
        var h Handler
        var n = 0
        for k, v := range mux.m {
-               if !pathMatch(k, r.URL.Path) {
+               if !pathMatch(k, path) {
                        continue
                }
                if h == nil || len(k) > n {
@@ -620,6 +611,23 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
                        h = v
                }
        }
+       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) {
+       // Clean path to canonical form and redirect.
+       if p := cleanPath(r.URL.Path); p != r.URL.Path {
+               w.SetHeader("Location", p)
+               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()
        }
@@ -628,7 +636,7 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
 
 // Handle registers the handler for the given pattern.
 func (mux *ServeMux) Handle(pattern string, handler Handler) {
-       if pattern == "" || pattern[0] != '/' {
+       if pattern == "" {
                panic("http: invalid pattern " + pattern)
        }