-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp.go
263 lines (246 loc) · 6.93 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package goservicetools
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"reflect"
"strconv"
"sync"
"time"
"github.com/ilya1st/configuration-go"
"github.com/rs/zerolog"
)
/*
This file will contains functions we need fot init HTTP, HTTP/2, HTTPS server
First we would init just an http
*/
var (
// todo: Socket here
httpListener net.Listener
httpServer *http.Server
httpServerServeError error
httpServerMutex sync.RWMutex
httpShutdownTimeout int
httpSsl bool
httpSslCert string
httpSslKey string
)
//PrepareHTTPListener prepare http socket to run
// Notice: here we assume config is clean and normal
func PrepareHTTPListener(graceful bool, httpConfig configuration.IConfig) error {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
l := GetSystemLogger()
if httpConfig == nil || reflect.ValueOf(httpConfig).IsNil() {
panic(fmt.Errorf("PrepareHTTPListener: httpconfig is nil"))
}
if graceful && (os.Getenv("GRACEFUL_HTTP_FD") != "") { // fd 0 stdin, 1 stdout, 2 stderr, 3 http
fd, err := strconv.ParseInt(os.Getenv("GRACEFUL_HTTP_FD"), 10, 32)
if err != nil {
err = fmt.Errorf("PrepareHTTPListener: No variable GRACEFUL_HTTP_FD set for graceful start. Internal error: %v", err)
if l == nil {
panic(err)
} else {
l.Panic().Msg(err.Error())
}
}
file := os.NewFile(uintptr(fd), "[httpsocket]")
if file == nil {
return fmt.Errorf("PrepareHTTPSocket: Not valid http listener file descriptor while graceful restart")
}
li, err := net.FileListener(file)
if nil != err {
err = fmt.Errorf("PrepareHTTPSocket: cannot prepare filelistener for http server. Error: %v", err)
if l == nil {
fmt.Fprint(os.Stderr, err.Error())
} else {
l.Error().Msg(err.Error())
}
return err
}
httpListener = li
return nil
}
address, err := httpConfig.GetStringValue("address")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
socketType, err := httpConfig.GetStringValue("socket_type")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
switch socketType {
case "unix":
case "tcp":
default:
panic("PrepareHTTPSocket: wrong socket type")
}
httpListener, err = net.Listen(socketType, address)
if err != nil {
panic(fmt.Errorf("Error while listen socket: %v", err))
}
return nil
}
// GetHTTPListener returns internal http socket
func GetHTTPListener() net.Listener {
httpServerMutex.RLock()
defer httpServerMutex.RUnlock()
return httpListener
}
// DropHTTPListener close socket. Call when not graceful there
func DropHTTPListener() {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
if nil != httpListener {
httpListener.Close()
httpListener = nil
}
}
// GetHTTPServer gets http server instance if started
func GetHTTPServer() *http.Server {
httpServerMutex.RLock()
defer httpServerMutex.RUnlock()
return httpServer
}
type httpErrorWriter struct{ log *zerolog.Logger }
func (l *httpErrorWriter) Write(p []byte) (n int, err error) {
if l.log == nil {
return len(p), nil
}
l.log.Warn().Msg(string(p))
return len(p), nil
}
// SetupHTTPServer setups http server(not stats!). for case of graceful gives their socket
// graceful or not here depends on was changed configuration file or not
// this one you must use after PrepareHTTPListener runned
func SetupHTTPServer(httpConfig configuration.IConfig) error {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
l := GetSystemLogger()
if l == nil || reflect.ValueOf(l).IsNil() {
panic(fmt.Errorf("PrepareHTTPSocket: nil logger there"))
}
if httpConfig == nil || reflect.ValueOf(httpConfig).IsNil() {
l.Fatal().Msg("SetupHTTPServer: httpconfig is nil. Will panic")
}
if httpServer != nil { // all already done
return nil
}
if httpListener == nil {
panic(fmt.Errorf("env.SetupHTTPServer: First setup httpListener - use PrepareHTTPListener() first"))
}
var err error
httpShutdownTimeout, err = httpConfig.GetIntValue("shutdown_timeout")
if err != nil {
err = fmt.Errorf("PrepareHTTPListener: httpconfig shutdown_timeout error:%v. Will panic", err)
l.Info().Msg(err.Error())
panic(err)
}
if httpShutdownTimeout < 0 {
err = fmt.Errorf("PrepareHTTPListener: shutdown_timeout is negative: no way to work. Check config")
l.Info().Msg(err.Error())
panic(err)
}
address, err := httpConfig.GetStringValue("address")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
// no checks cause all is in CheckHTTPconfig
sslConf, err := httpConfig.GetSubconfig("ssl")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
httpSsl, err = sslConf.GetBooleanValue("ssl")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
if httpSsl {
httpSslCert, err = sslConf.GetStringValue("cert")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
httpSslKey, err = sslConf.GetStringValue("key")
if err != nil {
panic(fmt.Errorf("PrepareHTTPSocket: config error: %v", err))
}
}
httpServer = &http.Server{
Addr: address,
// setup our error log here
ErrorLog: log.New(&httpErrorWriter{log: l}, "", 0),
}
return nil
}
// DropHTTPServer shut downs and drop server - not listener
func DropHTTPServer() {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
if httpServer == nil {
return
}
// TODO: add shutdown timeout to server config
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(httpShutdownTimeout)*time.Millisecond)
defer func() {
l := GetSystemLogger()
if l != nil {
l.Warn().Msgf("HTTP server shutdown hangs more then timeout %d", httpShutdownTimeout)
}
cancel()
}()
httpServer.Shutdown(ctx)
httpServer = nil
}
// SetHTTPServeMux sets up server mux
func SetHTTPServeMux(mux http.Handler) {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
if httpServer == nil {
panic(fmt.Errorf("Cannot setup server mux to nil"))
}
httpServer.Handler = mux
}
// StartHTTPServer starts listen http with g
func StartHTTPServer() {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
if httpServer == nil {
panic(fmt.Errorf("Server is not. First init them"))
}
if httpListener == nil {
panic(fmt.Errorf("HTTP Listener not prepared. Press prepare them"))
}
httpServerServeError = nil
go func() { // cause Serve() is locking there - but we do not need that shit
httpListener := GetHTTPListener()
if httpListener == nil {
return
}
var err error
if httpSsl {
err = httpServer.ServeTLS(httpListener, httpSslCert, httpSslKey)
} else {
err = httpServer.Serve(httpListener)
}
if err != http.ErrServerClosed {
l := GetHTTPLogger()
if l != nil {
l.Error().Msgf("http server serve() error: %v", err)
}
}
}()
}
func init() {
httpServerMutex.Lock()
defer httpServerMutex.Unlock()
httpListener = nil
httpServer = nil
// default value
httpShutdownTimeout = 10000
httpServerServeError = nil
httpSsl = false
httpSslCert = ""
httpSslKey = ""
}