-
Notifications
You must be signed in to change notification settings - Fork 811
/
server.go
196 lines (174 loc) · 6.29 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
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
// Copyright 2018 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package server provides a preconfigured HTTP server with diagnostic hooks.
package server // import "gocloud.dev/server"
import (
"context"
"fmt"
"net/http"
"sync"
"time"
"github.com/google/wire"
"gocloud.dev/server/driver"
"gocloud.dev/server/health"
"gocloud.dev/server/requestlog"
"go.opencensus.io/plugin/ochttp"
"go.opencensus.io/trace"
)
// Set is a Wire provider set that produces a *Server given the fields of
// Options.
var Set = wire.NewSet(
New,
wire.Struct(new(Options), "RequestLogger", "HealthChecks", "TraceExporter", "DefaultSamplingPolicy", "Driver"),
wire.Value(&DefaultDriver{}),
wire.Bind(new(driver.Server), new(*DefaultDriver)),
)
// Server is a preconfigured HTTP server with diagnostic hooks.
// The zero value is a server with the default options.
type Server struct {
reqlog requestlog.Logger
handler http.Handler
wrappedHandler http.Handler
healthHandler health.Handler
te trace.Exporter
sampler trace.Sampler
once sync.Once
driver driver.Server
}
// Options is the set of optional parameters.
type Options struct {
// RequestLogger specifies the logger that will be used to log requests.
RequestLogger requestlog.Logger
// HealthChecks specifies the health checks to be run when the
// /healthz/readiness endpoint is requested.
HealthChecks []health.Checker
// TraceExporter exports sampled trace spans.
TraceExporter trace.Exporter
// DefaultSamplingPolicy is a function that takes a
// trace.SamplingParameters struct and returns a true or false decision about
// whether it should be sampled and exported.
DefaultSamplingPolicy trace.Sampler
// Driver serves HTTP requests.
Driver driver.Server
}
// New creates a new server. New(nil, nil) is the same as new(Server).
func New(h http.Handler, opts *Options) *Server {
srv := &Server{handler: h}
if opts != nil {
srv.reqlog = opts.RequestLogger
srv.te = opts.TraceExporter
for _, c := range opts.HealthChecks {
srv.healthHandler.Add(c)
}
srv.sampler = opts.DefaultSamplingPolicy
srv.driver = opts.Driver
}
return srv
}
func (srv *Server) init() {
srv.once.Do(func() {
if srv.te != nil {
trace.RegisterExporter(srv.te)
}
if srv.sampler != nil {
trace.ApplyConfig(trace.Config{DefaultSampler: srv.sampler})
}
if srv.driver == nil {
srv.driver = NewDefaultDriver()
}
if srv.handler == nil {
srv.handler = http.DefaultServeMux
}
// Setup health checks, /healthz route is taken by health checks by default.
// Note: App Engine Flex uses /_ah/health by default, which can be changed
// in app.yaml. We may want to do an auto-detection for flex in future.
const healthPrefix = "/healthz/"
mux := http.NewServeMux()
mux.HandleFunc(healthPrefix+"liveness", health.HandleLive)
mux.Handle(healthPrefix+"readiness", &srv.healthHandler)
h := srv.handler
if srv.reqlog != nil {
h = requestlog.NewHandler(srv.reqlog, h)
}
h = &ochttp.Handler{
Handler: h,
IsPublicEndpoint: true,
}
mux.Handle("/", h)
srv.wrappedHandler = mux
})
}
// ListenAndServe is a wrapper to use wherever http.ListenAndServe is used.
// It wraps the http.Handler provided to New with a handler that handles tracing and
// request logging. If the handler is nil, then http.DefaultServeMux will be used.
// A configured Requestlogger will log all requests except HealthChecks.
func (srv *Server) ListenAndServe(addr string) error {
srv.init()
return srv.driver.ListenAndServe(addr, srv.wrappedHandler)
}
// ListenAndServeTLS is a wrapper to use wherever http.ListenAndServeTLS is used.
// It wraps the http.Handler provided to New with a handler that handles tracing and
// request logging. If the handler is nil, then http.DefaultServeMux will be used.
// A configured Requestlogger will log all requests except HealthChecks.
func (srv *Server) ListenAndServeTLS(addr, certFile, keyFile string) error {
// Check if the driver implements the optional interface.
tlsDriver, ok := srv.driver.(driver.TLSServer)
if !ok {
return fmt.Errorf("driver %T does not support ListenAndServeTLS", srv.driver)
}
srv.init()
return tlsDriver.ListenAndServeTLS(addr, certFile, keyFile, srv.wrappedHandler)
}
// Shutdown gracefully shuts down the server without interrupting any active connections.
func (srv *Server) Shutdown(ctx context.Context) error {
if srv.driver == nil {
return nil
}
return srv.driver.Shutdown(ctx)
}
// DefaultDriver implements the driver.Server interface. The zero value is a valid http.Server.
type DefaultDriver struct {
Server http.Server
}
// NewDefaultDriver creates a driver with an http.Server with default timeouts.
func NewDefaultDriver() *DefaultDriver {
return &DefaultDriver{
Server: http.Server{
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
},
}
}
// ListenAndServe sets the address and handler on DefaultDriver's http.Server,
// then calls ListenAndServe on it.
func (dd *DefaultDriver) ListenAndServe(addr string, h http.Handler) error {
dd.Server.Addr = addr
dd.Server.Handler = h
return dd.Server.ListenAndServe()
}
// ListenAndServeTLS sets the address and handler on DefaultDriver's http.Server,
// then calls ListenAndServeTLS on it.
//
// DefaultDriver.Server.TLSConfig may be set to configure additional TLS settings.
func (dd *DefaultDriver) ListenAndServeTLS(addr, certFile, keyFile string, h http.Handler) error {
dd.Server.Addr = addr
dd.Server.Handler = h
return dd.Server.ListenAndServeTLS(certFile, keyFile)
}
// Shutdown gracefully shuts down the server without interrupting any active connections,
// by calling Shutdown on DefaultDriver's http.Server
func (dd *DefaultDriver) Shutdown(ctx context.Context) error {
return dd.Server.Shutdown(ctx)
}