2019-06-03 20:44:43 +03:00
|
|
|
// Package http provides a http server with features; acme, cors, etc
|
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/gorilla/handlers"
|
2020-08-19 17:47:17 +03:00
|
|
|
"github.com/unistack-org/micro/v3/api/server"
|
|
|
|
"github.com/unistack-org/micro/v3/api/server/cors"
|
|
|
|
"github.com/unistack-org/micro/v3/logger"
|
2019-06-03 20:44:43 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type httpServer struct {
|
|
|
|
mux *http.ServeMux
|
|
|
|
opts server.Options
|
|
|
|
|
|
|
|
mtx sync.RWMutex
|
|
|
|
address string
|
|
|
|
exit chan chan error
|
|
|
|
}
|
|
|
|
|
2020-04-02 19:44:48 +03:00
|
|
|
func NewServer(address string, opts ...server.Option) server.Server {
|
|
|
|
var options server.Options
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
return &httpServer{
|
2020-04-02 19:44:48 +03:00
|
|
|
opts: options,
|
2019-06-03 20:44:43 +03:00
|
|
|
mux: http.NewServeMux(),
|
|
|
|
address: address,
|
|
|
|
exit: make(chan chan error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) Address() string {
|
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
return s.address
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) Init(opts ...server.Option) error {
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&s.opts)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) Handle(path string, handler http.Handler) {
|
2020-04-19 02:41:03 +03:00
|
|
|
// TODO: move this stuff out to one place with ServeHTTP
|
2020-04-07 21:29:26 +03:00
|
|
|
|
|
|
|
// apply the wrappers, e.g. auth
|
|
|
|
for _, wrapper := range s.opts.Wrappers {
|
2020-04-19 02:41:03 +03:00
|
|
|
handler = wrapper(handler)
|
2020-04-07 21:29:26 +03:00
|
|
|
}
|
2020-03-04 14:40:53 +03:00
|
|
|
|
2020-04-19 02:41:03 +03:00
|
|
|
// wrap with cors
|
2020-03-04 14:40:53 +03:00
|
|
|
if s.opts.EnableCORS {
|
2020-04-19 02:41:03 +03:00
|
|
|
handler = cors.CombinedCORSHandler(handler)
|
2020-03-04 14:40:53 +03:00
|
|
|
}
|
|
|
|
|
2020-04-19 02:41:03 +03:00
|
|
|
// wrap with logger
|
|
|
|
handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
|
|
|
|
|
|
|
|
s.mux.Handle(path, handler)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) Start() error {
|
|
|
|
var l net.Listener
|
|
|
|
var err error
|
|
|
|
|
2019-10-11 18:52:57 +03:00
|
|
|
if s.opts.EnableACME && s.opts.ACMEProvider != nil {
|
2019-06-03 20:44:43 +03:00
|
|
|
// should we check the address to make sure its using :443?
|
2020-02-15 18:10:26 +03:00
|
|
|
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
|
2019-06-03 20:44:43 +03:00
|
|
|
} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
|
|
|
|
l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
|
|
|
|
} else {
|
|
|
|
// otherwise plain listen
|
|
|
|
l, err = net.Listen("tcp", s.address)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-11 20:55:39 +03:00
|
|
|
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
|
|
|
logger.Infof("HTTP API Listening on %s", l.Addr().String())
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
s.mtx.Lock()
|
|
|
|
s.address = l.Addr().String()
|
|
|
|
s.mtx.Unlock()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
if err := http.Serve(l, s.mux); err != nil {
|
|
|
|
// temporary fix
|
2020-03-11 20:55:39 +03:00
|
|
|
//logger.Fatal(err)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
ch := <-s.exit
|
|
|
|
ch <- l.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) Stop() error {
|
|
|
|
ch := make(chan error)
|
|
|
|
s.exit <- ch
|
|
|
|
return <-ch
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *httpServer) String() string {
|
|
|
|
return "http"
|
|
|
|
}
|