-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathserver.go
124 lines (106 loc) · 2.47 KB
/
server.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
package server
import (
"context"
"log"
"net"
"net/http"
"os"
"strings"
"time"
"github.com/sharat87/httpbun/ex"
"github.com/sharat87/httpbun/response"
"github.com/sharat87/httpbun/routes"
"github.com/sharat87/httpbun/routes/responses"
"github.com/sharat87/httpbun/server/spec"
)
type Server struct {
*http.Server
spec spec.Spec
routes []ex.Route
closeCh chan error
}
func StartNew(spec spec.Spec) Server {
tlsCertFile := os.Getenv("HTTPBUN_TLS_CERT")
tlsKeyFile := os.Getenv("HTTPBUN_TLS_KEY")
bindTarget := spec.BindTarget
if bindTarget == "" {
if tlsCertFile != "" {
bindTarget = ":443"
} else {
bindTarget = ":80"
}
}
server := &Server{
Server: &http.Server{
Addr: bindTarget,
},
spec: spec,
closeCh: make(chan error, 1),
}
server.Handler = server
if !spec.RootIsAny {
// When root is any, we don't need the route handlers at all.
server.routes = routes.GetRoutes()
}
listener, err := net.Listen("tcp", bindTarget)
if err != nil {
log.Fatalf("Error listening on %q: %v", spec.BindTarget, err)
}
go func() {
defer close(server.closeCh)
if tlsCertFile == "" {
server.closeCh <- server.Serve(listener)
} else {
server.closeCh <- server.ServeTLS(listener, tlsCertFile, tlsKeyFile)
}
}()
return *server
}
func (s Server) Wait() error {
return <-s.closeCh
}
func (s Server) CloseAndWait() {
if s.Server != nil {
ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFunc()
if err := s.Server.Shutdown(ctx); err != nil {
log.Printf("Error shutting down server: %v", err)
if err := s.Server.Close(); err != nil {
log.Printf("Error closing server: %v", err)
}
}
}
log.Print(s.Wait())
}
func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !strings.HasPrefix(req.URL.Path, s.spec.PathPrefix) {
http.NotFound(w, req)
return
}
ex := ex.New(w, req, s.spec)
incomingIP := ex.FindIncomingIPAddress()
log.Printf(
"From %s %s %s",
incomingIP,
req.Method,
req.URL.String(),
)
// Skip all route checking when root-is-any is enabled.
if s.spec.RootIsAny {
info, err := responses.InfoJSON(ex)
if err != nil {
ex.Finish(response.BadRequest(err.Error()))
} else {
ex.Finish(response.Response{Body: info})
}
return
}
for _, route := range s.routes {
if ex.MatchAndLoadFields(route.Pat) {
ex.Finish(route.Fn(ex))
return
}
}
log.Printf("NotFound ip=%s %s %s", incomingIP, req.Method, req.URL.String())
http.NotFound(w, req)
}