mirror of
https://github.com/golang/go
synced 2024-11-22 01:34:41 -07:00
http: add host patterns
R=bradfitzgo, rsc CC=golang-dev https://golang.org/cl/4070043
This commit is contained in:
parent
9557103ea6
commit
865d576702
@ -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"
|
||||
|
@ -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,6 +597,23 @@ func cleanPath(p string) string {
|
||||
return np
|
||||
}
|
||||
|
||||
// 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, path) {
|
||||
continue
|
||||
}
|
||||
if h == nil || len(k) > n {
|
||||
n = len(k)
|
||||
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) {
|
||||
@ -607,18 +623,10 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
|
||||
w.WriteHeader(StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
|
||||
// Most-specific (longest) pattern wins.
|
||||
var h Handler
|
||||
var n = 0
|
||||
for k, v := range mux.m {
|
||||
if !pathMatch(k, r.URL.Path) {
|
||||
continue
|
||||
}
|
||||
if h == nil || len(k) > n {
|
||||
n = len(k)
|
||||
h = v
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user