...
1 package services
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "time"
9
10 "github.com/datawire/dlib/dgroup"
11 "github.com/datawire/dlib/dhttp"
12 "github.com/datawire/dlib/dlog"
13 )
14
15
16 type HealthCheckServer struct {
17 Port int16
18 Backend string
19 SecurePort int16
20 SecureBackend string
21 Cert string
22 Key string
23 TLSVersion string
24 Healthy bool
25 HealthyStatusCode int
26 UnhealthyStatusCode int
27 }
28
29
30 func (h *HealthCheckServer) Start(ctx context.Context) <-chan bool {
31 dlog.Printf(ctx, "HTTP: %s listening on %d/%d", h.Backend, h.Port, h.SecurePort)
32
33 h.Healthy = true
34 mux := http.NewServeMux()
35 mux.HandleFunc("/", h.handler)
36
37 sc := &dhttp.ServerConfig{
38 Handler: mux,
39 }
40
41 g := dgroup.NewGroup(ctx, dgroup.GroupConfig{})
42 g.Go("cleartext", func(ctx context.Context) error {
43 return sc.ListenAndServe(ctx, fmt.Sprintf(":%v", h.Port))
44 })
45 g.Go("tls", func(ctx context.Context) error {
46 return sc.ListenAndServeTLS(ctx, fmt.Sprintf(":%v", h.SecurePort), h.Cert, h.Key)
47 })
48
49 exited := make(chan bool)
50 go func() {
51 if err := g.Wait(); err != nil {
52 dlog.Error(ctx, err)
53 panic(err)
54 }
55 close(exited)
56 }()
57 return exited
58 }
59
60 func (h *HealthCheckServer) handler(w http.ResponseWriter, r *http.Request) {
61 ctx := r.Context()
62
63 backend := h.Backend
64 conntype := "CLR"
65
66 var request = make(map[string]interface{})
67 var url = make(map[string]interface{})
68 request["url"] = url
69 url["fragment"] = r.URL.Fragment
70 url["host"] = r.URL.Host
71 url["opaque"] = r.URL.Opaque
72 url["path"] = r.URL.Path
73 url["query"] = r.URL.Query()
74 url["rawQuery"] = r.URL.RawQuery
75 url["scheme"] = r.URL.Scheme
76 if r.URL.User != nil {
77 url["username"] = r.URL.User.Username()
78 pw, ok := r.URL.User.Password()
79 if ok {
80 url["password"] = pw
81 }
82 }
83 request["method"] = r.Method
84 request["headers"] = lower(r.Header)
85 request["host"] = r.Host
86
87 var tlsrequest = make(map[string]interface{})
88 request["tls"] = tlsrequest
89
90 tlsrequest["enabled"] = r.TLS != nil
91
92 if r.TLS != nil {
93
94 backend = h.SecureBackend
95 conntype = "TLS"
96
97 tlsrequest["negotiated-protocol"] = r.TLS.NegotiatedProtocol
98 tlsrequest["server-name"] = r.TLS.ServerName
99 tlsrequest["negotiated-protocol-version"] = getTLSVersion(r.TLS)
100 }
101
102
103 w.Header().Set("Date", time.Now().Format(time.RFC1123))
104
105 statusCode := h.HealthyStatusCode
106 if !h.Healthy {
107 statusCode = h.UnhealthyStatusCode
108 }
109
110 fmt.Println(r.URL.Path)
111
112
113 if r.URL.Path == "/makeUnhealthy/" {
114 h.Healthy = false
115 }
116
117 w.WriteHeader(statusCode)
118
119
120 var response = make(map[string]interface{})
121 response["headers"] = lower(w.Header())
122
123 var body = make(map[string]interface{})
124 body["backend"] = backend
125 body["request"] = request
126 body["response"] = response
127
128 b, err := json.MarshalIndent(body, "", " ")
129 if err != nil {
130 b = []byte(fmt.Sprintf("Error: %v", err))
131 }
132
133 dlog.Printf(ctx, "%s (%s): \"%s %s\" -> HTTP %v", r.Method, r.URL.Path, backend, conntype, statusCode)
134 _, _ = w.Write(b)
135 }
136
View as plain text