OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / miekg / dns / serve_mux.go
1 package dns
2
3 import (
4         "bytes"
5         "sync"
6 )
7
8 // ServeMux is an DNS request multiplexer. It matches the zone name of
9 // each incoming request against a list of registered patterns add calls
10 // the handler for the pattern that most closely matches the zone name.
11 //
12 // ServeMux is DNSSEC aware, meaning that queries for the DS record are
13 // redirected to the parent zone (if that is also registered), otherwise
14 // the child gets the query.
15 //
16 // ServeMux is also safe for concurrent access from multiple goroutines.
17 //
18 // The zero ServeMux is empty and ready for use.
19 type ServeMux struct {
20         z map[string]Handler
21         m sync.RWMutex
22 }
23
24 // NewServeMux allocates and returns a new ServeMux.
25 func NewServeMux() *ServeMux {
26         return new(ServeMux)
27 }
28
29 // DefaultServeMux is the default ServeMux used by Serve.
30 var DefaultServeMux = NewServeMux()
31
32 func (mux *ServeMux) match(q string, t uint16) Handler {
33         mux.m.RLock()
34         defer mux.m.RUnlock()
35         if mux.z == nil {
36                 return nil
37         }
38
39         var handler Handler
40
41         // TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
42         // lands in a go release, replace the following with strings.ToLower.
43         var sb bytes.Buffer
44         for i := 0; i < len(q); i++ {
45                 c := q[i]
46                 if !(c >= 'A' && c <= 'Z') {
47                         continue
48                 }
49
50                 sb.Grow(len(q))
51                 sb.WriteString(q[:i])
52
53                 for ; i < len(q); i++ {
54                         c := q[i]
55                         if c >= 'A' && c <= 'Z' {
56                                 c += 'a' - 'A'
57                         }
58
59                         sb.WriteByte(c)
60                 }
61
62                 q = sb.String()
63                 break
64         }
65
66         for off, end := 0, false; !end; off, end = NextLabel(q, off) {
67                 if h, ok := mux.z[q[off:]]; ok {
68                         if t != TypeDS {
69                                 return h
70                         }
71                         // Continue for DS to see if we have a parent too, if so delegate to the parent
72                         handler = h
73                 }
74         }
75
76         // Wildcard match, if we have found nothing try the root zone as a last resort.
77         if h, ok := mux.z["."]; ok {
78                 return h
79         }
80
81         return handler
82 }
83
84 // Handle adds a handler to the ServeMux for pattern.
85 func (mux *ServeMux) Handle(pattern string, handler Handler) {
86         if pattern == "" {
87                 panic("dns: invalid pattern " + pattern)
88         }
89         mux.m.Lock()
90         if mux.z == nil {
91                 mux.z = make(map[string]Handler)
92         }
93         mux.z[Fqdn(pattern)] = handler
94         mux.m.Unlock()
95 }
96
97 // HandleFunc adds a handler function to the ServeMux for pattern.
98 func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
99         mux.Handle(pattern, HandlerFunc(handler))
100 }
101
102 // HandleRemove deregisters the handler specific for pattern from the ServeMux.
103 func (mux *ServeMux) HandleRemove(pattern string) {
104         if pattern == "" {
105                 panic("dns: invalid pattern " + pattern)
106         }
107         mux.m.Lock()
108         delete(mux.z, Fqdn(pattern))
109         mux.m.Unlock()
110 }
111
112 // ServeDNS dispatches the request to the handler whose pattern most
113 // closely matches the request message.
114 //
115 // ServeDNS is DNSSEC aware, meaning that queries for the DS record
116 // are redirected to the parent zone (if that is also registered),
117 // otherwise the child gets the query.
118 //
119 // If no handler is found, or there is no question, a standard SERVFAIL
120 // message is returned
121 func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
122         var h Handler
123         if len(req.Question) >= 1 { // allow more than one question
124                 h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
125         }
126
127         if h != nil {
128                 h.ServeDNS(w, req)
129         } else {
130                 HandleFailed(w, req)
131         }
132 }
133
134 // Handle registers the handler with the given pattern
135 // in the DefaultServeMux. The documentation for
136 // ServeMux explains how patterns are matched.
137 func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
138
139 // HandleRemove deregisters the handle with the given pattern
140 // in the DefaultServeMux.
141 func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
142
143 // HandleFunc registers the handler function with the given pattern
144 // in the DefaultServeMux.
145 func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
146         DefaultServeMux.HandleFunc(pattern, handler)
147 }