summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/server.go')
-rw-r--r--modules/caddyhttp/server.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go
new file mode 100644
index 0000000..5ab7693
--- /dev/null
+++ b/modules/caddyhttp/server.go
@@ -0,0 +1,91 @@
+package caddyhttp
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+
+ "bitbucket.org/lightcodelabs/caddy2"
+ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
+)
+
+// Server is an HTTP server.
+type Server struct {
+ Listen []string `json:"listen"`
+ ReadTimeout caddy2.Duration `json:"read_timeout"`
+ ReadHeaderTimeout caddy2.Duration `json:"read_header_timeout"`
+ Routes RouteList `json:"routes"`
+ Errors httpErrorConfig `json:"errors"`
+ TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies"`
+ DisableAutoHTTPS bool `json:"disable_auto_https"`
+ DisableAutoHTTPSRedir bool `json:"disable_auto_https_redir"`
+ MaxRehandles int `json:"max_rehandles"`
+
+ tlsApp *caddytls.TLS
+}
+
+// ServeHTTP is the entry point for all HTTP requests.
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if s.tlsApp.HandleHTTPChallenge(w, r) {
+ return
+ }
+
+ // set up the replacer
+ repl := newReplacer(r, w)
+ ctx := context.WithValue(r.Context(), caddy2.ReplacerCtxKey, repl)
+ ctx = context.WithValue(ctx, TableCtxKey, make(map[string]interface{})) // TODO: Implement this
+ r = r.WithContext(ctx)
+
+ // build and execute the main handler chain
+ stack := s.Routes.BuildCompositeRoute(w, r)
+ err := s.executeCompositeRoute(w, r, stack)
+ if err != nil {
+ // add the error value to the request context so
+ // it can be accessed by error handlers
+ c := context.WithValue(r.Context(), ErrorCtxKey, err)
+ r = r.WithContext(c)
+ // TODO: add error values to Replacer
+
+ if len(s.Errors.Routes) == 0 {
+ // TODO: implement a default error handler?
+ log.Printf("[ERROR] %s", err)
+ } else {
+ errStack := s.Errors.Routes.BuildCompositeRoute(w, r)
+ err := s.executeCompositeRoute(w, r, errStack)
+ if err != nil {
+ // TODO: what should we do if the error handler has an error?
+ log.Printf("[ERROR] handling error: %v", err)
+ }
+ }
+ }
+}
+
+// executeCompositeRoute executes stack with w and r. This function handles
+// the special ErrRehandle error value, which reprocesses requests through
+// the stack again. Any error value returned from this function would be an
+// actual error that needs to be handled.
+func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, stack Handler) error {
+ var err error
+ for i := -1; i <= s.MaxRehandles; i++ {
+ // we started the counter at -1 because we
+ // always want to run this at least once
+ err = stack.ServeHTTP(w, r)
+ if err != ErrRehandle {
+ break
+ }
+ if i >= s.MaxRehandles-1 {
+ return fmt.Errorf("too many rehandles")
+ }
+ }
+ return err
+}
+
+type httpErrorConfig struct {
+ Routes RouteList `json:"routes"`
+ // TODO: some way to configure the logging of errors, probably? standardize
+ // the logging configuration first.
+}
+
+// TableCtxKey is the context key for the request's variable table.
+const TableCtxKey caddy2.CtxKey = "table"