server.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package httpex
  2. import (
  3. "net/http"
  4. "path"
  5. "sync"
  6. )
  7. type ServeMux struct {
  8. mu sync.RWMutex
  9. m map[string]muxEntry
  10. hosts bool // whether any patterns contain hostnames
  11. }
  12. type muxEntry struct {
  13. explicit bool
  14. h http.Handler
  15. pattern string
  16. }
  17. // NewServeMux allocates and returns a new ServeMux.
  18. func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
  19. // DefaultServeMux is the default ServeMux used by Serve.
  20. var DefaultServeMux = NewServeMux()
  21. // Does path match pattern?
  22. func pathMatch(pattern, path string) bool {
  23. if len(pattern) == 0 {
  24. // should not happen
  25. return false
  26. }
  27. n := len(pattern)
  28. if pattern[n-1] != '/' {
  29. return pattern == path
  30. }
  31. return len(path) >= n && path[0:n] == pattern
  32. }
  33. // Return the canonical path for p, eliminating . and .. elements.
  34. func cleanPath(p string) string {
  35. if p == "" {
  36. return "/"
  37. }
  38. if p[0] != '/' {
  39. p = "/" + p
  40. }
  41. np := path.Clean(p)
  42. // path.Clean removes trailing slash except for root;
  43. // put the trailing slash back if necessary.
  44. if p[len(p)-1] == '/' && np != "/" {
  45. np += "/"
  46. }
  47. return np
  48. }
  49. // Find a handler on a handler map given a path string
  50. // Most-specific (longest) pattern wins
  51. func (mux *ServeMux) match(path string) (h http.Handler, pattern string) {
  52. var n = 0
  53. for k, v := range mux.m {
  54. if !pathMatch(k, path) {
  55. continue
  56. }
  57. if h == nil || len(k) > n {
  58. n = len(k)
  59. h = v.h
  60. pattern = v.pattern
  61. }
  62. }
  63. return
  64. }
  65. // Handler returns the handler to use for the given request,
  66. // consulting r.Method, r.Host, and r.URL.Path. It always returns
  67. // a non-nil handler. If the path is not in its canonical form, the
  68. // handler will be an internally-generated handler that redirects
  69. // to the canonical path.
  70. //
  71. // Handler also returns the registered pattern that matches the
  72. // request or, in the case of internally-generated redirects,
  73. // the pattern that will match after following the redirect.
  74. //
  75. // If there is no registered handler that applies to the request,
  76. // Handler returns a ``page not found'' handler and an empty pattern.
  77. func (mux *ServeMux) Handler(r *http.Request) (http.Handler, pattern string) {
  78. if r.Method != "CONNECT" {
  79. if p := cleanPath(r.URL.Path); p != r.URL.Path {
  80. _, pattern = mux.handler(r.Host, p)
  81. url := *r.URL
  82. url.Path = p
  83. return http.RedirectHandler(url.String(), http.StatusMovedPermanently), pattern
  84. }
  85. }
  86. return mux.handler(r.Host, r.URL.Path)
  87. }
  88. func (mux *ServeMux) handler(host, path string) (h http.Handler, pattern string) {
  89. mux.mu.RLock()
  90. defer mux.mu.RUnlock()
  91. // Host-specific pattern takes precedence over generic ones
  92. if mux.hosts {
  93. h, pattern = mux.match(host + path)
  94. }
  95. if h == nil {
  96. h, pattern = mux.match(path)
  97. }
  98. if h == nil {
  99. h, pattern = http.NotFoundHandler(), ""
  100. }
  101. return
  102. }
  103. // ServeHTTP dispatches the request to the handler whose
  104. // pattern most closely matches the request URL.
  105. func (mux *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  106. }
  107. func (mux *ServeMux) Handle(pattern string, handler http.Handler) {
  108. }
  109. // HandleFunc registers the handler function for the given pattern.
  110. func (mux *ServeMux) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
  111. }