-
Notifications
You must be signed in to change notification settings - Fork 193
/
http.go
118 lines (95 loc) · 2.29 KB
/
http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"fmt"
"io"
"log"
"net/http"
"strconv"
"github.com/abh/geodns/monitor"
"github.com/abh/geodns/zones"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
type httpServer struct {
mux *http.ServeMux
zones *zones.MuxManager
serverInfo *monitor.ServerInfo
}
type rate struct {
Name string
Count int64
Metrics zones.ZoneMetrics
}
type rates []*rate
func (s rates) Len() int { return len(s) }
func (s rates) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ratesByCount struct{ rates }
func (s ratesByCount) Less(i, j int) bool {
ic := s.rates[i].Count
jc := s.rates[j].Count
if ic == jc {
return s.rates[i].Name < s.rates[j].Name
}
return ic > jc
}
func topParam(req *http.Request, def int) int {
req.ParseForm()
topOption := def
topParam := req.Form["top"]
if len(topParam) > 0 {
var err error
topOption, err = strconv.Atoi(topParam[0])
if err != nil {
topOption = def
}
}
return topOption
}
func NewHTTPServer(mm *zones.MuxManager, serverInfo *monitor.ServerInfo) *httpServer {
hs := &httpServer{
zones: mm,
mux: &http.ServeMux{},
serverInfo: serverInfo,
}
hs.mux.HandleFunc("/", hs.mainServer)
hs.mux.Handle("/metrics", promhttp.Handler())
return hs
}
func (hs *httpServer) Mux() *http.ServeMux {
return hs.mux
}
func (hs *httpServer) Run(listen string) {
log.Println("Starting HTTP interface on", listen)
log.Fatal(http.ListenAndServe(listen, &basicauth{h: hs.mux}))
}
func (hs *httpServer) mainServer(w http.ResponseWriter, req *http.Request) {
if req.RequestURI != "/version" {
http.NotFound(w, req)
return
}
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
io.WriteString(w, `GeoDNS `+hs.serverInfo.Version+`\n`)
}
type basicauth struct {
h http.Handler
}
func (b *basicauth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cfgMutex.RLock()
user := Config.HTTP.User
password := Config.HTTP.Password
cfgMutex.RUnlock()
if len(user) == 0 {
b.h.ServeHTTP(w, r)
return
}
ruser, rpass, ok := r.BasicAuth()
if ok {
if ruser == user && rpass == password {
b.h.ServeHTTP(w, r)
return
}
}
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm=%q`, "GeoDNS Status"))
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}