OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / miekg / dns / serve_mux.go
diff --git a/vendor/github.com/miekg/dns/serve_mux.go b/vendor/github.com/miekg/dns/serve_mux.go
new file mode 100644 (file)
index 0000000..19ba0a1
--- /dev/null
@@ -0,0 +1,147 @@
+package dns
+
+import (
+       "bytes"
+       "sync"
+)
+
+// ServeMux is an DNS request multiplexer. It matches the zone name of
+// each incoming request against a list of registered patterns add calls
+// the handler for the pattern that most closely matches the zone name.
+//
+// ServeMux is DNSSEC aware, meaning that queries for the DS record are
+// redirected to the parent zone (if that is also registered), otherwise
+// the child gets the query.
+//
+// ServeMux is also safe for concurrent access from multiple goroutines.
+//
+// The zero ServeMux is empty and ready for use.
+type ServeMux struct {
+       z map[string]Handler
+       m sync.RWMutex
+}
+
+// NewServeMux allocates and returns a new ServeMux.
+func NewServeMux() *ServeMux {
+       return new(ServeMux)
+}
+
+// DefaultServeMux is the default ServeMux used by Serve.
+var DefaultServeMux = NewServeMux()
+
+func (mux *ServeMux) match(q string, t uint16) Handler {
+       mux.m.RLock()
+       defer mux.m.RUnlock()
+       if mux.z == nil {
+               return nil
+       }
+
+       var handler Handler
+
+       // TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
+       // lands in a go release, replace the following with strings.ToLower.
+       var sb bytes.Buffer
+       for i := 0; i < len(q); i++ {
+               c := q[i]
+               if !(c >= 'A' && c <= 'Z') {
+                       continue
+               }
+
+               sb.Grow(len(q))
+               sb.WriteString(q[:i])
+
+               for ; i < len(q); i++ {
+                       c := q[i]
+                       if c >= 'A' && c <= 'Z' {
+                               c += 'a' - 'A'
+                       }
+
+                       sb.WriteByte(c)
+               }
+
+               q = sb.String()
+               break
+       }
+
+       for off, end := 0, false; !end; off, end = NextLabel(q, off) {
+               if h, ok := mux.z[q[off:]]; ok {
+                       if t != TypeDS {
+                               return h
+                       }
+                       // Continue for DS to see if we have a parent too, if so delegate to the parent
+                       handler = h
+               }
+       }
+
+       // Wildcard match, if we have found nothing try the root zone as a last resort.
+       if h, ok := mux.z["."]; ok {
+               return h
+       }
+
+       return handler
+}
+
+// Handle adds a handler to the ServeMux for pattern.
+func (mux *ServeMux) Handle(pattern string, handler Handler) {
+       if pattern == "" {
+               panic("dns: invalid pattern " + pattern)
+       }
+       mux.m.Lock()
+       if mux.z == nil {
+               mux.z = make(map[string]Handler)
+       }
+       mux.z[Fqdn(pattern)] = handler
+       mux.m.Unlock()
+}
+
+// HandleFunc adds a handler function to the ServeMux for pattern.
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
+       mux.Handle(pattern, HandlerFunc(handler))
+}
+
+// HandleRemove deregisters the handler specific for pattern from the ServeMux.
+func (mux *ServeMux) HandleRemove(pattern string) {
+       if pattern == "" {
+               panic("dns: invalid pattern " + pattern)
+       }
+       mux.m.Lock()
+       delete(mux.z, Fqdn(pattern))
+       mux.m.Unlock()
+}
+
+// ServeDNS dispatches the request to the handler whose pattern most
+// closely matches the request message.
+//
+// ServeDNS is DNSSEC aware, meaning that queries for the DS record
+// are redirected to the parent zone (if that is also registered),
+// otherwise the child gets the query.
+//
+// If no handler is found, or there is no question, a standard SERVFAIL
+// message is returned
+func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
+       var h Handler
+       if len(req.Question) >= 1 { // allow more than one question
+               h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
+       }
+
+       if h != nil {
+               h.ServeDNS(w, req)
+       } else {
+               HandleFailed(w, req)
+       }
+}
+
+// Handle registers the handler with the given pattern
+// in the DefaultServeMux. The documentation for
+// ServeMux explains how patterns are matched.
+func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
+
+// HandleRemove deregisters the handle with the given pattern
+// in the DefaultServeMux.
+func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
+
+// HandleFunc registers the handler function with the given pattern
+// in the DefaultServeMux.
+func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
+       DefaultServeMux.HandleFunc(pattern, handler)
+}