type ServeMux struct { mu sync.RWMutex m map[string]muxEntry es []muxEntry // slice of entries sorted from longest to shortest. hosts bool// whether any patterns contain hostnames }
1 2 3 4 5
// muEntry存储了路由表达式和对应的handler type muxEntry struct { h Handler pattern string }
m对应的map用于路由的精确匹配,es对应的slice用于路由的部分匹配
ServeMux也实现了ServeHTTP方法,也就是实现了handler接口
1 2 3 4 5 6 7 8 9 10 11 12 13
// ServeHTTP dispatches the request to the handler whose // pattern most closely matches the request URL. func(mux *ServeMux)ServeHTTP(w ResponseWriter, r *Request) { if r.RequestURI == "*" { if r.ProtoAtLeast(1, 1) { w.Header().Set("Connection", "close") } w.WriteHeader(StatusBadRequest) return } h, _ := mux.Handler(r) h.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") } if handler == nil { panic("http: nil handler") } //已经注册过 if _, exist := mux.m[pattern]; exist { panic("http: multiple registrations for " + pattern) }
if mux.m == nil { mux.m = make(map[string]muxEntry) } e := muxEntry{h: handler, pattern: pattern} mux.m[pattern] = e // 如果路由pattern以'/'结尾,则将对应的muxEntry对象加入到[]muxEntry中,路由长的位于切片的前面 if pattern[len(pattern)-1] == '/' { mux.es = appendSorted(mux.es, e) }
inShutdown atomicBool // true when when server is in shutdown
disableKeepAlives int32// accessed atomically. nextProtoOnce sync.Once // guards setupHTTP2_* init nextProtoErr error // result of http2.ConfigureServer if used
for { w, err := c.readRequest(ctx) if c.r.remain != c.server.initialReadLimitSize() { // If we read any bytes off the wire, we're active. c.setState(c.rwc, StateActive) }
... serverHandler{c.server}.ServeHTTP(w, w.req) w.cancelCtx() if c.hijacked() { return } w.finishRequest() if !w.shouldReuseConnection() { if w.requestBodyLimitHit || w.closedRequestBodyEarly() { c.closeWriteAndWait() } return } c.setState(c.rwc, StateIdle) c.curReq.Store((*response)(nil))
if r.Method == "CONNECT" { if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok { return RedirectHandler(u.String(), StatusMovedPermanently), u.Path }
return mux.handler(r.Host, r.URL.Path) }
// All other requests have any port stripped and path cleaned // before passing to mux.handler. host := stripHostPort(r.Host) path := cleanPath(r.URL.Path)
// If the given path is /tree and its handler is not registered, // redirect for /tree/. if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok { return RedirectHandler(u.String(), StatusMovedPermanently), u.Path }
// handler is the main implementation of Handler. // The path is known to be in canonical form, except for CONNECT methods. func(mux *ServeMux)handler(host, path string)(h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock()
// Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" } return }
// Find a handler on a handler map given a path string. // Most-specific (longest) pattern wins. func(mux *ServeMux)match(path string)(h Handler, pattern string) { // Check for exact match first. v, ok := mux.m[path] if ok { return v.h, v.pattern }
// Check for longest valid match. mux.es contains all patterns // that end in / sorted from longest to shortest. for _, e := range mux.es { if strings.HasPrefix(path, e.pattern) { return e.h, e.pattern } } returnnil, "" }