github.com/searKing/golang/go@v1.2.117/net/mux/server_mux.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mux 6 7 import ( 8 "errors" 9 "io" 10 "net" 11 "sync" 12 "time" 13 14 io_ "github.com/searKing/golang/go/io" 15 net_ "github.com/searKing/golang/go/net" 16 ) 17 18 // NotFound replies to the request with an HTTP 404 not found error. 19 func NotFound(c net.Conn) { 20 _, _ = c.Write([]byte("404 page not found")) 21 } 22 23 // NotFoundHandler returns a simple request handler 24 // that replies to each request with a “404 page not found” reply. 25 func NotFoundHandler() HandlerConn { return HandlerConnFunc(NotFound) } 26 27 // ServeMux is a net.ServeMux that accepts only the connections that matched. 28 // goroutine unsafe 29 type ServeMux struct { 30 // NotFound replies to the listener with a not found error. 31 NotFoundHandler HandlerConn 32 sniffTimeout time.Duration 33 34 mu sync.RWMutex 35 m []muxEntry 36 } 37 38 type muxEntry struct { 39 h HandlerConn 40 l *net_.NotifyListener 41 42 pattern Matcher 43 } 44 45 func (e muxEntry) Serve(c net.Conn) { 46 if e.h != nil { 47 e.h.Serve(c) 48 return 49 } 50 if e.l != nil { 51 e.l.C <- c 52 return 53 } 54 panic("mux_entry: nil handler") 55 } 56 57 type Matcher interface { 58 Match(io.Writer, io.Reader) bool 59 } 60 61 // MatcherFunc is a match that can also write response (say to do handshake). 62 type MatcherFunc func(io.Writer, io.Reader) bool 63 64 func (f MatcherFunc) Match(w io.Writer, r io.Reader) bool { 65 return f(w, r) 66 } 67 68 func MatcherAny(matchers ...Matcher) Matcher { 69 return MatcherFunc(func(w io.Writer, r io.Reader) bool { 70 sniffReader := io_.SniffReader(r) 71 for _, pattern := range matchers { 72 sniffReader.Sniff(true) 73 if pattern.Match(w, sniffReader) { 74 sniffReader.Sniff(false) 75 return true 76 } 77 sniffReader.Sniff(false) 78 } 79 return false 80 }) 81 } 82 83 // NewServeMux allocates and returns a new ServeMux. 84 func NewServeMux() *ServeMux { 85 return &ServeMux{ 86 NotFoundHandler: HandlerConnFunc(func(net.Conn) {}), 87 } 88 } 89 90 // DefaultServeMux is the default ServeMux used by Serve. 91 var DefaultServeMux = &defaultServeMux 92 93 var defaultServeMux ServeMux 94 95 // SetReadTimeout sets a timeout for the read of matchers 96 func (mux *ServeMux) SetReadTimeout(t time.Duration) { 97 mux.sniffTimeout = t 98 } 99 100 func (mux *ServeMux) HandleListener(pattern Matcher) net.Listener { 101 mux.mu.Lock() 102 defer mux.mu.Unlock() 103 104 if pattern == nil { 105 panic("listener: invalid pattern") 106 } 107 108 e := muxEntry{l: net_.NewNotifyListener(), pattern: pattern} 109 mux.m = append(mux.m, e) 110 return e.l 111 } 112 113 func (mux *ServeMux) Handle(pattern Matcher, handler HandlerConn) { 114 mux.mu.Lock() 115 defer mux.mu.Unlock() 116 117 if pattern == nil { 118 panic("listener: invalid pattern") 119 } 120 if handler == nil { 121 panic("listener: nil handler") 122 } 123 124 e := muxEntry{h: handler, pattern: pattern} 125 mux.m = append(mux.m, e) 126 return 127 } 128 129 // HandleFunc registers the handler function for the given pattern. 130 func (mux *ServeMux) HandleFunc(pattern Matcher, handler func(net.Conn)) { 131 if handler == nil { 132 panic("http: nil handler") 133 } 134 mux.Handle(pattern, HandlerConnFunc(handler)) 135 } 136 137 // Find a handler on a handler map. 138 func (mux *ServeMux) match(c *sniffConn) (h HandlerConn) { 139 for _, e := range mux.m { 140 c.startSniffing() 141 if e.pattern.Match(c, c) { 142 c.doneSniffing() 143 return e 144 } 145 c.doneSniffing() 146 } 147 return nil 148 149 } 150 151 // Handler is the main implementation of HandlerConn. 152 func (mux *ServeMux) Handler(c *sniffConn) (h HandlerConn) { 153 mux.mu.RLock() 154 defer mux.mu.RUnlock() 155 156 // set sniff timeout 157 if mux.sniffTimeout > noTimeout { 158 _ = c.SetReadDeadline(time.Now().Add(mux.sniffTimeout)) 159 } 160 h = mux.match(c) 161 162 // unset sniff timeout 163 if mux.sniffTimeout > noTimeout { 164 _ = c.SetReadDeadline(noTimeoutDeadline) 165 } 166 if h == nil { 167 notFoundHandler := mux.NotFoundHandler 168 if notFoundHandler == nil { 169 notFoundHandler = NotFoundHandler() 170 } 171 h = muxEntry{ 172 h: notFoundHandler, 173 } 174 } 175 return 176 } 177 178 func (mux *ServeMux) Serve(c net.Conn) { 179 muxC, ok := c.(*sniffConn) 180 if !ok { 181 muxC = newMuxConn(c) 182 } 183 184 h := mux.Handler(muxC) 185 h.Serve(c) 186 } 187 188 func (mux *ServeMux) Close() error { 189 var errs []error 190 for _, e := range mux.m { 191 if l := e.l; l != nil { 192 errs = append(errs, l.Close()) 193 } 194 } 195 return errors.Join(errs...) 196 } 197 198 func HandleListener(pattern Matcher) net.Listener { 199 return DefaultServeMux.HandleListener(pattern) 200 } 201 202 func Handle(pattern Matcher, handler HandlerConn) { 203 DefaultServeMux.Handle(pattern, handler) 204 } 205 206 // HandleFunc registers the handler function for the given pattern. 207 func HandleFunc(pattern Matcher, handler func(net.Conn)) { 208 DefaultServeMux.HandleFunc(pattern, handler) 209 } 210 func SetReadTimeout(t time.Duration) { 211 DefaultServeMux.SetReadTimeout(t) 212 }