summaryrefslogtreecommitdiffhomepage
path: root/caddyhttp/errors/setup.go
blob: b6e2025f025cdc3c91c9fb888388173b66c5f546 (plain)
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
package errors

import (
	"log"
	"os"
	"path/filepath"
	"strconv"

	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// setup configures a new errors middleware instance.
func setup(c *caddy.Controller) error {
	handler, err := errorsParse(c)

	if err != nil {
		return err
	}

	handler.Log.Attach(c)

	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
		handler.Next = next
		return handler
	})

	return nil
}

func errorsParse(c *caddy.Controller) (*ErrorHandler, error) {

	// Very important that we make a pointer because the startup
	// function that opens the log file must have access to the
	// same instance of the handler, not a copy.
	handler := &ErrorHandler{
		ErrorPages: make(map[int]string),
		Log:        &httpserver.Logger{},
	}

	cfg := httpserver.GetConfig(c)

	optionalBlock := func() error {
		for c.NextBlock() {

			what := c.Val()
			if !c.NextArg() {
				return c.ArgErr()
			}
			where := c.Val()

			if httpserver.IsLogRollerSubdirective(what) {
				var err error
				err = httpserver.ParseRoller(handler.Log.Roller, what, where)
				if err != nil {
					return err
				}
			} else {
				// Error page; ensure it exists
				if !filepath.IsAbs(where) {
					where = filepath.Join(cfg.Root, where)
				}

				f, err := os.Open(where)
				if err != nil {
					log.Printf("[WARNING] Unable to open error page '%s': %v", where, err)
				}
				f.Close()

				if what == "*" {
					if handler.GenericErrorPage != "" {
						return c.Errf("Duplicate status code entry: %s", what)
					}
					handler.GenericErrorPage = where
				} else {
					whatInt, err := strconv.Atoi(what)
					if err != nil {
						return c.Err("Expecting a numeric status code or '*', got '" + what + "'")
					}

					if _, exists := handler.ErrorPages[whatInt]; exists {
						return c.Errf("Duplicate status code entry: %s", what)
					}

					handler.ErrorPages[whatInt] = where
				}
			}
		}
		return nil
	}

	for c.Next() {
		// weird hack to avoid having the handler values overwritten.
		if c.Val() == "}" {
			continue
		}

		args := c.RemainingArgs()

		if len(args) == 1 {
			switch args[0] {
			case "visible":
				handler.Debug = true
			default:
				handler.Log.Output = args[0]
				handler.Log.Roller = httpserver.DefaultLogRoller()
			}
		}

		// Configuration may be in a block
		err := optionalBlock()
		if err != nil {
			return handler, err
		}
	}

	return handler, nil
}