2015-01-30 14:52:18 +08:00
|
|
|
// 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"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
2015-01-22 05:10:52 +08:00
|
|
|
"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"
|
|
|
|
)
|
|
|
|
|
2015-01-19 14:11:21 +08:00
|
|
|
// 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 {
|
|
|
|
config config.Config
|
|
|
|
reqlog *log.Logger
|
|
|
|
errlog *log.Logger
|
|
|
|
fileServer http.Handler
|
|
|
|
stack http.HandlerFunc
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
|
2015-01-22 05:10:52 +08:00
|
|
|
// 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 {
|
2015-01-19 14:11:21 +08:00
|
|
|
err := s.buildStack()
|
2015-01-14 03:43:45 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-03-17 01:44:54 +08:00
|
|
|
// use highest value across all configurations
|
|
|
|
if s.config.MaxCPU > 0 && s.config.MaxCPU > runtime.GOMAXPROCS(0) {
|
2015-01-22 05:10:52 +08:00
|
|
|
runtime.GOMAXPROCS(s.config.MaxCPU)
|
|
|
|
}
|
|
|
|
|
2015-03-17 01:44:54 +08:00
|
|
|
server := &http.Server{
|
|
|
|
Addr: s.config.Address(),
|
|
|
|
Handler: s,
|
|
|
|
}
|
|
|
|
|
|
|
|
http2.ConfigureServer(server, nil) // TODO: This may not be necessary after HTTP/2 merged into std lib
|
|
|
|
|
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 each request to s.
|
|
|
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
s.stack(w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log writes a message to the server's configured error log,
|
|
|
|
// if there is one, or if there isn't, to the default stderr log.
|
|
|
|
func (s *Server) Log(v ...interface{}) {
|
|
|
|
if s.errlog != nil {
|
|
|
|
s.errlog.Println(v)
|
|
|
|
} else {
|
|
|
|
log.Println(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 14:11:21 +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.
|
2015-01-19 14:11:21 +08:00
|
|
|
func (s *Server) buildStack() error {
|
2015-03-25 11:55:51 +08:00
|
|
|
s.fileServer = FileServer(http.Dir(s.config.Root))
|
2015-01-14 03:43:45 +08:00
|
|
|
|
2015-01-19 14:11:21 +08:00
|
|
|
for _, start := range s.config.Startup {
|
|
|
|
err := start()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-01-14 03:43:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:49:01 +08:00
|
|
|
// TODO: We only compile middleware for the "/" scope.
|
|
|
|
// Partial support for multiple location contexts already
|
2015-03-25 11:55:51 +08:00
|
|
|
// exists at the parser and config levels, but until full
|
2015-03-04 00:49:01 +08:00
|
|
|
// 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 generator
|
|
|
|
// function calls like handler1(handler2(handler3(finalHandler))).
|
|
|
|
func (s *Server) compile(layers []middleware.Middleware) {
|
|
|
|
s.stack = s.fileServer.ServeHTTP // core app layer
|
|
|
|
for _, layer := range layers {
|
|
|
|
s.stack = layer(s.stack)
|
|
|
|
}
|
|
|
|
}
|