caddy/server/server.go

156 lines
4.1 KiB
Go
Raw Normal View History

// Package server implements a configurable, general-purpose web server.
// It relies on configurations obtained from the adjacent config package
// and can execute middleware as defined by the adjacent middleware package.
2015-01-14 03:43:45 +08:00
package server
import (
"errors"
"fmt"
2015-01-14 03:43:45 +08:00
"log"
"net/http"
2015-03-26 23:52:03 +08:00
"os"
"os/signal"
"runtime"
2015-01-14 03:43:45 +08:00
2015-03-17 01:44:54 +08:00
"github.com/bradfitz/http2"
2015-01-14 03:43:45 +08:00
"github.com/mholt/caddy/config"
"github.com/mholt/caddy/middleware"
)
// The default configuration file to load if none is specified
const DefaultConfigFile = "Caddyfile"
// servers maintains a registry of running servers, keyed by address.
2015-01-14 03:43:45 +08:00
var servers = make(map[string]*Server)
// Server represents an instance of a server, which serves
// static content at a particular address (host and port).
type Server struct {
HTTP2 bool // temporary while http2 is not in std lib (TODO: remove flag when part of std lib)
2015-01-14 03:43:45 +08:00
config config.Config
fileServer middleware.Handler
stack middleware.Handler
2015-01-14 03:43:45 +08:00
}
// New creates a new Server and registers it with the list
// of servers created. Each server must have a unique host:port
// combination. This function does not start serving.
func New(conf config.Config) (*Server, error) {
addr := conf.Address()
// Unique address check
if _, exists := servers[addr]; exists {
return nil, errors.New("Address " + addr + " is already in use")
}
// Use all CPUs (if needed) by default
if conf.MaxCPU == 0 {
conf.MaxCPU = runtime.NumCPU()
}
2015-01-14 03:43:45 +08:00
// Initialize
s := new(Server)
s.config = conf
// Register the server
servers[addr] = s
return s, nil
}
// Serve starts the server. It blocks until the server quits.
func (s *Server) Serve() error {
// Execute startup functions
for _, start := range s.config.Startup {
err := start()
if err != nil {
return err
}
}
// Build middleware stack
err := s.buildStack()
2015-01-14 03:43:45 +08:00
if err != nil {
return err
}
// Use highest procs value across all configurations
2015-03-17 01:44:54 +08:00
if s.config.MaxCPU > 0 && s.config.MaxCPU > runtime.GOMAXPROCS(0) {
runtime.GOMAXPROCS(s.config.MaxCPU)
}
2015-03-17 01:44:54 +08:00
server := &http.Server{
Addr: s.config.Address(),
Handler: s,
}
if s.HTTP2 {
// TODO: This call may not be necessary after HTTP/2 is merged into std lib
http2.ConfigureServer(server, nil)
}
2015-03-17 01:44:54 +08:00
2015-03-26 23:52:03 +08:00
// Execute shutdown commands on exit
go func() {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill) // TODO: syscall.SIGQUIT? (Ctrl+\, Unix-only)
<-interrupt
for _, shutdownFunc := range s.config.Shutdown {
err := shutdownFunc()
if err != nil {
log.Fatal(err)
}
}
os.Exit(0)
}()
2015-01-14 03:43:45 +08:00
if s.config.TLS.Enabled {
2015-03-17 01:44:54 +08:00
return server.ListenAndServeTLS(s.config.TLS.Certificate, s.config.TLS.Key)
2015-01-14 03:43:45 +08:00
} else {
2015-03-17 01:44:54 +08:00
return server.ListenAndServe()
2015-01-14 03:43:45 +08:00
}
}
// ServeHTTP is the entry point for every request to s.
2015-01-14 03:43:45 +08:00
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2015-03-27 12:52:27 +08:00
defer func() {
// In case the user doesn't enable error middleware, we still
// need to make sure that we stay alive up here
2015-03-27 12:52:27 +08:00
if rec := recover(); rec != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
2015-03-27 12:52:27 +08:00
}
}()
status, _ := s.stack.ServeHTTP(w, r)
// Fallback error response in case error handling wasn't chained in
if status >= 400 {
w.WriteHeader(status)
fmt.Fprintf(w, "%d %s", status, http.StatusText(status))
}
2015-01-14 03:43:45 +08:00
}
// buildStack builds the server's middleware stack based
2015-01-14 03:43:45 +08:00
// on its config. This method should be called last before
// ListenAndServe begins.
func (s *Server) buildStack() error {
s.fileServer = FileServer(http.Dir(s.config.Root))
2015-01-14 03:43:45 +08:00
// TODO: We only compile middleware for the "/" scope.
// Partial support for multiple location contexts already
// exists at the parser and config levels, but until full
// support is implemented, this is all we do right here.
s.compile(s.config.Middleware["/"])
2015-01-14 03:43:45 +08:00
return nil
}
// compile is an elegant alternative to nesting middleware function
// calls like handler1(handler2(handler3(finalHandler))).
2015-01-14 03:43:45 +08:00
func (s *Server) compile(layers []middleware.Middleware) {
s.stack = s.fileServer // core app layer
for i := len(layers) - 1; i >= 0; i-- {
s.stack = layers[i](s.stack)
2015-01-14 03:43:45 +08:00
}
}