123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- package httpex
- import (
- "net/http"
- "path"
- "sync"
- )
- type ServeMux struct {
- mu sync.RWMutex
- m map[string]muxEntry
- hosts bool // whether any patterns contain hostnames
- }
- type muxEntry struct {
- explicit bool
- h http.Handler
- pattern string
- }
- // NewServeMux allocates and returns a new ServeMux.
- func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
- // DefaultServeMux is the default ServeMux used by Serve.
- var DefaultServeMux = NewServeMux()
- // Does path match pattern?
- func pathMatch(pattern, path string) bool {
- if len(pattern) == 0 {
- // should not happen
- return false
- }
- n := len(pattern)
- if pattern[n-1] != '/' {
- return pattern == path
- }
- return len(path) >= n && path[0:n] == pattern
- }
- // Return the canonical path for p, eliminating . and .. elements.
- func cleanPath(p string) string {
- if p == "" {
- return "/"
- }
- if p[0] != '/' {
- p = "/" + p
- }
- np := path.Clean(p)
- // path.Clean removes trailing slash except for root;
- // put the trailing slash back if necessary.
- if p[len(p)-1] == '/' && np != "/" {
- np += "/"
- }
- return np
- }
- // Find a handler on a handler map given a path string
- // Most-specific (longest) pattern wins
- func (mux *ServeMux) match(path string) (h http.Handler, pattern string) {
- 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.h
- pattern = v.pattern
- }
- }
- return
- }
- // Handler returns the handler to use for the given request,
- // consulting r.Method, r.Host, and r.URL.Path. It always returns
- // a non-nil handler. If the path is not in its canonical form, the
- // handler will be an internally-generated handler that redirects
- // to the canonical path.
- //
- // Handler also returns the registered pattern that matches the
- // request or, in the case of internally-generated redirects,
- // the pattern that will match after following the redirect.
- //
- // If there is no registered handler that applies to the request,
- // Handler returns a ``page not found'' handler and an empty pattern.
- func (mux *ServeMux) Handler(r *http.Request) (http.Handler, pattern string) {
- if r.Method != "CONNECT" {
- if p := cleanPath(r.URL.Path); p != r.URL.Path {
- _, pattern = mux.handler(r.Host, p)
- url := *r.URL
- url.Path = p
- return http.RedirectHandler(url.String(), http.StatusMovedPermanently), pattern
- }
- }
- return mux.handler(r.Host, r.URL.Path)
- }
- func (mux *ServeMux) handler(host, path string) (h http.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 = http.NotFoundHandler(), ""
- }
- return
- }
- // ServeHTTP dispatches the request to the handler whose
- // pattern most closely matches the request URL.
- func (mux *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- }
- func (mux *ServeMux) Handle(pattern string, handler http.Handler) {
- }
- // HandleFunc registers the handler function for the given pattern.
- func (mux *ServeMux) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
- }
|