Example #1
0
// ParseRoller parses roller contents out of c.
func ParseRoller(c *caddy.Controller) (*LogRoller, error) {
	var size, age, keep int
	// This is kind of a hack to support nested blocks:
	// As we are already in a block: either log or errors,
	// c.nesting > 0 but, as soon as c meets a }, it thinks
	// the block is over and return false for c.NextBlock.
	for c.NextBlock() {
		what := c.Val()
		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		value := c.Val()
		var err error
		switch what {
		case "size":
			size, err = strconv.Atoi(value)
		case "age":
			age, err = strconv.Atoi(value)
		case "keep":
			keep, err = strconv.Atoi(value)
		}
		if err != nil {
			return nil, err
		}
	}
	return &LogRoller{
		MaxSize:    size,
		MaxAge:     age,
		MaxBackups: keep,
		LocalTime:  true,
	}, nil
}
Example #2
0
func mimeParse(c *caddy.Controller) (Config, error) {
	configs := Config{}

	for c.Next() {
		// At least one extension is required

		args := c.RemainingArgs()
		switch len(args) {
		case 2:
			if err := validateExt(configs, args[0]); err != nil {
				return configs, err
			}
			configs[args[0]] = args[1]
		case 1:
			return configs, c.ArgErr()
		case 0:
			for c.NextBlock() {
				ext := c.Val()
				if err := validateExt(configs, ext); err != nil {
					return configs, err
				}
				if !c.NextArg() {
					return configs, c.ArgErr()
				}
				configs[ext] = c.Val()
			}
		}

	}

	return configs, nil
}
Example #3
0
func parse(m *module, c *caddy.Controller) (err error) {
	args := c.RemainingArgs()
	if len(args) == 1 && args[0] == "cloudflare" {
		addCloudflareIps(m)
		if c.NextBlock() {
			return c.Err("No realip subblocks allowed if using preset.")
		}
	} else if len(args) != 0 {
		return c.ArgErr()
	}
	for c.NextBlock() {
		var err error
		switch c.Val() {
		case "header":
			m.Header, err = StringArg(c)
		case "from":
			var cidr *net.IPNet
			cidr, err = CidrArg(c)
			m.From = append(m.From, cidr)
		case "strict":
			m.Strict, err = BoolArg(c)
		default:
			return c.Errf("Unknown realip arg: %s", c.Val())
		}
		if err != nil {
			return err
		}
	}
	return nil
}
Example #4
0
// Assert only one arg and return it
func StringArg(c *caddy.Controller) (string, error) {
	args := c.RemainingArgs()
	if len(args) != 1 {
		return "", c.ArgErr()
	}
	return args[0], nil
}
Example #5
0
func loadParams(c *caddy.Controller, mdc *Config) error {
	cfg := httpserver.GetConfig(c.Key)

	switch c.Val() {
	case "ext":
		for _, ext := range c.RemainingArgs() {
			mdc.Extensions[ext] = struct{}{}
		}
		return nil
	case "css":
		if !c.NextArg() {
			return c.ArgErr()
		}
		mdc.Styles = append(mdc.Styles, c.Val())
		return nil
	case "js":
		if !c.NextArg() {
			return c.ArgErr()
		}
		mdc.Scripts = append(mdc.Scripts, c.Val())
		return nil
	case "template":
		tArgs := c.RemainingArgs()
		switch len(tArgs) {
		default:
			return c.ArgErr()
		case 1:
			fpath := filepath.ToSlash(filepath.Clean(cfg.Root + string(filepath.Separator) + tArgs[0]))

			if err := SetTemplate(mdc.Template, "", fpath); err != nil {
				c.Errf("default template parse error: %v", err)
			}
			return nil
		case 2:
			fpath := filepath.ToSlash(filepath.Clean(cfg.Root + string(filepath.Separator) + tArgs[1]))

			if err := SetTemplate(mdc.Template, tArgs[0], fpath); err != nil {
				c.Errf("template parse error: %v", err)
			}
			return nil
		}
	case "templatedir":
		if !c.NextArg() {
			return c.ArgErr()
		}
		_, err := mdc.Template.ParseGlob(c.Val())
		if err != nil {
			c.Errf("template load error: %v", err)
		}
		if c.NextArg() {
			return c.ArgErr()
		}
		return nil
	default:
		return c.Err("Expected valid markdown configuration property")
	}
}
Example #6
0
func setupBind(c *caddy.Controller) error {
	config := httpserver.GetConfig(c)
	for c.Next() {
		if !c.Args(&config.ListenHost) {
			return c.ArgErr()
		}
		config.TLS.ListenHost = config.ListenHost // necessary for ACME challenges, see issue #309
	}
	return nil
}
Example #7
0
func internalParse(c *caddy.Controller) ([]string, error) {
	var paths []string

	for c.Next() {
		if !c.NextArg() {
			return paths, c.ArgErr()
		}
		paths = append(paths, c.Val())
	}

	return paths, nil
}
Example #8
0
func jsonpParse(c *caddy.Controller) ([]string, error) {
	var paths []string

	if db1 {
		fmt.Printf("jsonpParse called\n")
	}

	for c.Next() {
		if !c.NextArg() {
			return paths, c.ArgErr()
		}
		paths = append(paths, c.Val())
	}

	return paths, nil
}
Example #9
0
// extParse sets up an instance of extension middleware
// from a middleware controller and returns a list of extensions.
func extParse(c *caddy.Controller) ([]string, error) {
	var exts []string

	for c.Next() {
		// At least one extension is required
		if !c.NextArg() {
			return exts, c.ArgErr()
		}
		exts = append(exts, c.Val())

		// Tack on any other extensions that may have been listed
		exts = append(exts, c.RemainingArgs()...)
	}

	return exts, nil
}
Example #10
0
func BoolArg(c *caddy.Controller) (bool, error) {
	args := c.RemainingArgs()
	if len(args) > 1 {
		return false, c.ArgErr()
	}
	if len(args) == 0 {
		return true, nil
	}
	switch args[0] {
	case "false":
		return false, nil
	case "true":
		return true, nil
	default:
		return false, c.Errf("Unexpected bool value: %s", args[0])
	}
}
Example #11
0
func expVarParse(c *caddy.Controller) (Resource, error) {
	var resource Resource
	var err error

	for c.Next() {
		args := c.RemainingArgs()
		switch len(args) {
		case 0:
			resource = Resource(defaultExpvarPath)
		case 1:
			resource = Resource(args[0])
		default:
			return resource, c.ArgErr()
		}
	}

	return resource, err
}
Example #12
0
// registerCallback registers a callback function to execute by
// using c to parse the directive. It registers the callback
// to be executed using registerFunc.
func registerCallback(c *caddy.Controller, registerFunc func(func() error)) error {
	var funcs []func() error

	for c.Next() {
		args := c.RemainingArgs()
		if len(args) == 0 {
			return c.ArgErr()
		}

		nonblock := false
		if len(args) > 1 && args[len(args)-1] == "&" {
			// Run command in background; non-blocking
			nonblock = true
			args = args[:len(args)-1]
		}

		command, args, err := caddy.SplitCommandAndArgs(strings.Join(args, " "))
		if err != nil {
			return c.Err(err.Error())
		}

		fn := func() error {
			cmd := exec.Command(command, args...)
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			if nonblock {
				log.Printf("[INFO] Nonblocking Command:\"%s %s\"", command, strings.Join(args, " "))
				return cmd.Start()
			}
			log.Printf("[INFO] Blocking Command:\"%s %s\"", command, strings.Join(args, " "))
			return cmd.Run()
		}

		funcs = append(funcs, fn)
	}

	return c.OncePerServerBlock(func() error {
		for _, fn := range funcs {
			registerFunc(fn)
		}
		return nil
	})
}
Example #13
0
// nlgidsParse will parse the following directives.
// recipients [email protected] [email protected]
// subject [email protected]
// secret /opt/etc/NLgids-fcbeb7928cdb.json
func nlgidsParse(c *caddy.Controller) (*Config, error) {
	config := new(Config)
	config.Tours = "/opt/www/nlgids.london/tours.json"
	for c.Next() {
		for c.NextBlock() {
			switch c.Val() {
			case "recipients":
				rcpts := c.RemainingArgs()
				if len(rcpts) == 0 {
					return nil, c.ArgErr()
				}
				config.Recipients = append(config.Recipients, rcpts...)
			case "subject":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				config.Subject = c.Val()
				if !strings.Contains(config.Subject, "@") {
					return nil, fmt.Errorf("nlgids: subject must contain @-sign: %s", c.Val())
				}
			case "secret":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				config.Secret = c.Val()
				_, err := os.Open(config.Secret)
				if err != nil {
					return nil, fmt.Errorf("nlgids: secret file must be readable: %s", err)
				}
			case "template":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				config.Template = c.Val()
			case "tours":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				config.Tours = c.Val()
			}
		}
	}
	return config, nil
}
Example #14
0
func setupMaxRequestBody(c *caddy.Controller) error {
	config := httpserver.GetConfig(c)

	if !c.Next() {
		return c.ArgErr()
	}

	args := c.RemainingArgs()
	argList := []pathLimitUnparsed{}

	switch len(args) {
	case 0:
		// Format: { <path> <limit> ... }
		for c.NextBlock() {
			path := c.Val()
			if !c.NextArg() {
				// Uneven pairing of path/limit
				return c.ArgErr()
			}
			argList = append(argList, pathLimitUnparsed{
				Path:  path,
				Limit: c.Val(),
			})
		}
	case 1:
		// Format: <limit>
		argList = []pathLimitUnparsed{{
			Path:  "/",
			Limit: args[0],
		}}
	case 2:
		// Format: <path> <limit>
		argList = []pathLimitUnparsed{{
			Path:  args[0],
			Limit: args[1],
		}}
	default:
		return c.ArgErr()
	}

	pathLimit, err := parseArguments(argList)
	if err != nil {
		return c.ArgErr()
	}

	SortPathLimits(pathLimit)

	config.MaxRequestBodySizes = pathLimit

	return nil
}
Example #15
0
func markdownParse(c *caddy.Controller) ([]*Config, error) {
	var mdconfigs []*Config

	for c.Next() {
		md := &Config{
			Renderer:   blackfriday.HtmlRenderer(0, "", ""),
			Extensions: make(map[string]struct{}),
			Template:   GetDefaultTemplate(),
		}

		// Get the path scope
		args := c.RemainingArgs()
		switch len(args) {
		case 0:
			md.PathScope = "/"
		case 1:
			md.PathScope = args[0]
		default:
			return mdconfigs, c.ArgErr()
		}

		// Load any other configuration parameters
		for c.NextBlock() {
			if err := loadParams(c, md); err != nil {
				return mdconfigs, err
			}
		}

		// If no extensions were specified, assume some defaults
		if len(md.Extensions) == 0 {
			md.Extensions[".md"] = struct{}{}
			md.Extensions[".markdown"] = struct{}{}
			md.Extensions[".mdown"] = struct{}{}
		}

		mdconfigs = append(mdconfigs, md)
	}

	return mdconfigs, nil
}
Example #16
0
// statusParse parses status directive
func statusParse(c *caddy.Controller) ([]httpserver.HandlerConfig, error) {
	var rules []httpserver.HandlerConfig

	for c.Next() {
		hadBlock := false
		args := c.RemainingArgs()

		switch len(args) {
		case 1:
			status, err := strconv.Atoi(args[0])
			if err != nil {
				return rules, c.Errf("Expecting a numeric status code, got '%s'", args[0])
			}

			for c.NextBlock() {
				hadBlock = true
				basePath := c.Val()

				for _, cfg := range rules {
					rule := cfg.(*Rule)
					if rule.Base == basePath {
						return rules, c.Errf("Duplicate path: '%s'", basePath)
					}
				}

				rule := NewRule(basePath, status)
				rules = append(rules, rule)

				if c.NextArg() {
					return rules, c.ArgErr()
				}
			}

			if !hadBlock {
				return rules, c.ArgErr()
			}
		case 2:
			status, err := strconv.Atoi(args[0])
			if err != nil {
				return rules, c.Errf("Expecting a numeric status code, got '%s'", args[0])
			}

			basePath := args[1]
			for _, cfg := range rules {
				rule := cfg.(*Rule)
				if rule.Base == basePath {
					return rules, c.Errf("Duplicate path: '%s'", basePath)
				}
			}

			rule := NewRule(basePath, status)
			rules = append(rules, rule)
		default:
			return rules, c.ArgErr()
		}
	}

	return rules, nil
}
Example #17
0
// setup returns a new instance of a pprof handler. It accepts no arguments or options.
func setup(c *caddy.Controller) error {
	found := false

	for c.Next() {
		if found {
			return c.Err("pprof can only be specified once")
		}
		if len(c.RemainingArgs()) != 0 {
			return c.ArgErr()
		}
		if c.NextBlock() {
			return c.ArgErr()
		}
		found = true
	}

	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
		return &Handler{Next: next, Mux: NewMux()}
	})

	return nil
}
Example #18
0
func basicAuthParse(c *caddy.Controller) ([]Rule, error) {
	var rules []Rule
	cfg := httpserver.GetConfig(c)

	var err error
	for c.Next() {
		var rule Rule

		args := c.RemainingArgs()

		switch len(args) {
		case 2:
			rule.Username = args[0]
			if rule.Password, err = passwordMatcher(rule.Username, args[1], cfg.Root); err != nil {
				return rules, c.Errf("Get password matcher from %s: %v", c.Val(), err)
			}

			for c.NextBlock() {
				rule.Resources = append(rule.Resources, c.Val())
				if c.NextArg() {
					return rules, c.Errf("Expecting only one resource per line (extra '%s')", c.Val())
				}
			}
		case 3:
			rule.Resources = append(rule.Resources, args[0])
			rule.Username = args[1]
			if rule.Password, err = passwordMatcher(rule.Username, args[2], cfg.Root); err != nil {
				return rules, c.Errf("Get password matcher from %s: %v", c.Val(), err)
			}
		default:
			return rules, c.ArgErr()
		}

		rules = append(rules, rule)
	}

	return rules, nil
}
Example #19
0
func templatesParse(c *caddy.Controller) ([]Rule, error) {
	var rules []Rule

	for c.Next() {
		var rule Rule

		rule.Path = defaultTemplatePath
		rule.Extensions = defaultTemplateExtensions

		args := c.RemainingArgs()

		switch len(args) {
		case 0:
			// Optional block
			for c.NextBlock() {
				switch c.Val() {
				case "path":
					args := c.RemainingArgs()
					if len(args) != 1 {
						return nil, c.ArgErr()
					}
					rule.Path = args[0]

				case "ext":
					args := c.RemainingArgs()
					if len(args) == 0 {
						return nil, c.ArgErr()
					}
					rule.Extensions = args

				case "between":
					args := c.RemainingArgs()
					if len(args) != 2 {
						return nil, c.ArgErr()
					}
					rule.Delims[0] = args[0]
					rule.Delims[1] = args[1]
				}
			}
		default:
			// First argument would be the path
			rule.Path = args[0]

			// Any remaining arguments are extensions
			rule.Extensions = args[1:]
			if len(rule.Extensions) == 0 {
				rule.Extensions = defaultTemplateExtensions
			}
		}

		for _, ext := range rule.Extensions {
			rule.IndexFiles = append(rule.IndexFiles, "index"+ext)
		}

		rules = append(rules, rule)
	}
	return rules, nil
}
Example #20
0
func setupRoot(c *caddy.Controller) error {
	config := httpserver.GetConfig(c)

	for c.Next() {
		if !c.NextArg() {
			return c.ArgErr()
		}
		config.Root = c.Val()
	}

	// Check if root path exists
	_, err := os.Stat(config.Root)
	if err != nil {
		if os.IsNotExist(err) {
			// Allow this, because the folder might appear later.
			// But make sure the user knows!
			log.Printf("[WARNING] Root path does not exist: %s", config.Root)
		} else {
			return c.Errf("Unable to access root path '%s': %v", config.Root, err)
		}
	}

	return nil
}
Example #21
0
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)}

	cfg := httpserver.GetConfig(c)

	optionalBlock := func() (bool, error) {
		var hadBlock bool

		for c.NextBlock() {
			hadBlock = true

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

			if what == "log" {
				if where == "visible" {
					handler.Debug = true
				} else {
					handler.LogFile = where
					if c.NextArg() {
						if c.Val() == "{" {
							c.IncrNest()
							logRoller, err := httpserver.ParseRoller(c)
							if err != nil {
								return hadBlock, err
							}
							handler.LogRoller = logRoller
						}
					}
				}
			} else {
				// Error page; ensure it exists
				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 hadBlock, c.Errf("Duplicate status code entry: %s", what)
					}
					handler.GenericErrorPage = where
				} else {
					whatInt, err := strconv.Atoi(what)
					if err != nil {
						return hadBlock, c.Err("Expecting a numeric status code or '*', got '" + what + "'")
					}

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

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

	for c.Next() {
		// weird hack to avoid having the handler values overwritten.
		if c.Val() == "}" {
			continue
		}
		// Configuration may be in a block
		hadBlock, err := optionalBlock()
		if err != nil {
			return handler, err
		}

		// Otherwise, the only argument would be an error log file name or 'visible'
		if !hadBlock {
			if c.NextArg() {
				if c.Val() == "visible" {
					handler.Debug = true
				} else {
					handler.LogFile = c.Val()
				}
			}
		}
	}

	return handler, nil
}
Example #22
0
func gzipParse(c *caddy.Controller) ([]Config, error) {
	var configs []Config

	for c.Next() {
		config := Config{}

		// Request Filters
		pathFilter := PathFilter{IgnoredPaths: make(Set)}
		extFilter := ExtFilter{Exts: make(Set)}

		// Response Filters
		lengthFilter := LengthFilter(0)

		// No extra args expected
		if len(c.RemainingArgs()) > 0 {
			return configs, c.ArgErr()
		}

		for c.NextBlock() {
			switch c.Val() {
			case "ext":
				exts := c.RemainingArgs()
				if len(exts) == 0 {
					return configs, c.ArgErr()
				}
				for _, e := range exts {
					if !strings.HasPrefix(e, ".") && e != ExtWildCard && e != "" {
						return configs, fmt.Errorf(`gzip: invalid extension "%v" (must start with dot)`, e)
					}
					extFilter.Exts.Add(e)
				}
			case "not":
				paths := c.RemainingArgs()
				if len(paths) == 0 {
					return configs, c.ArgErr()
				}
				for _, p := range paths {
					if p == "/" {
						return configs, fmt.Errorf(`gzip: cannot exclude path "/" - remove directive entirely instead`)
					}
					if !strings.HasPrefix(p, "/") {
						return configs, fmt.Errorf(`gzip: invalid path "%v" (must start with /)`, p)
					}
					pathFilter.IgnoredPaths.Add(p)
				}
			case "level":
				if !c.NextArg() {
					return configs, c.ArgErr()
				}
				level, _ := strconv.Atoi(c.Val())
				config.Level = level
			case "min_length":
				if !c.NextArg() {
					return configs, c.ArgErr()
				}
				length, err := strconv.ParseInt(c.Val(), 10, 64)
				if err != nil {
					return configs, err
				} else if length == 0 {
					return configs, fmt.Errorf(`gzip: min_length must be greater than 0`)
				}
				lengthFilter = LengthFilter(length)
			default:
				return configs, c.ArgErr()
			}
		}

		// Request Filters
		config.RequestFilters = []RequestFilter{}

		// If ignored paths are specified, put in front to filter with path first
		if len(pathFilter.IgnoredPaths) > 0 {
			config.RequestFilters = []RequestFilter{pathFilter}
		}

		// Then, if extensions are specified, use those to filter.
		// Otherwise, use default extensions filter.
		if len(extFilter.Exts) > 0 {
			config.RequestFilters = append(config.RequestFilters, extFilter)
		} else {
			config.RequestFilters = append(config.RequestFilters, DefaultExtFilter())
		}

		// Response Filters
		// If min_length is specified, use it.
		if int64(lengthFilter) != 0 {
			config.ResponseFilters = append(config.ResponseFilters, lengthFilter)
		}

		configs = append(configs, config)
	}

	return configs, nil
}
Example #23
0
func NoArgs(c *caddy.Controller) error {
	if len(c.RemainingArgs()) != 0 {
		return c.ArgErr()
	}
	return nil
}
Example #24
0
func parse(c *caddy.Controller) (mc *config, _ error) {
	// This parses the following config blocks
	mc = newConfig()

	for c.Next() {
		args := c.RemainingArgs()

		switch len(args) {
		case 1:
			mc.endpoint = args[0]
		}

		for c.NextBlock() {
			var err error
			switch c.Val() {
			case "publickeyAttachmentFileName":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.pgpAttachmentName = c.Val()
			case "maillog":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				if mc.maillog.IsNil() {
					mc.maillog = maillog.New(c.Val(), "")
				} else {
					mc.maillog.MailDir = c.Val()
				}
			case "errorlog":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				if mc.maillog.IsNil() {
					mc.maillog = maillog.New("", c.Val())
				} else {
					mc.maillog.ErrDir = c.Val()
				}
			case "to":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.to, err = splitEmailAddresses(c.Val())
				if err != nil {
					return nil, err
				}
			case "cc":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.cc, err = splitEmailAddresses(c.Val())
				if err != nil {
					return nil, err
				}
			case "bcc":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.bcc, err = splitEmailAddresses(c.Val())
				if err != nil {
					return nil, err
				}
			case "subject":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.subject = c.Val()
			case "body":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.body = c.Val()
			case "username":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.username = c.Val()
			case "password":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.password = c.Val()
			case "host":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.host = c.Val()
			case "port":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				mc.portRaw = c.Val()
			case "ratelimit_interval":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				var rli time.Duration
				rli, err = time.ParseDuration(c.Val())
				if err != nil {
					return nil, err
				}
				if rli.Nanoseconds() != 0 {
					mc.rateLimitInterval = rli
				}
			case "ratelimit_capacity":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}
				var rlc int64
				rlc, err = strconv.ParseInt(c.Val(), 10, 64)
				if err != nil {
					return nil, err
				}
				if rlc > 0 {
					mc.rateLimitCapacity = rlc
				}
			default:
				anyKey := c.Val()
				if isValidEmail(anyKey) {
					if !c.NextArg() {
						return nil, c.ArgErr()
					}
					pgpPublicKey := c.Val()
					mc.pgpEmailKeys = append(mc.pgpEmailKeys, anyKey, pgpPublicKey)
				}
			}
		}
	}
	return
}
Example #25
0
// Parse parses the configuration set by the user so it can be
// used by the middleware
func parse(c *caddy.Controller, root string) (*Config, *filemanager.FileManager, error) {
	var (
		cfg    *Config
		fm     *filemanager.FileManager
		err    error
		tokens string
	)

	cfg = new(Config)

	if cfg.Hugo, err = exec.LookPath("hugo"); err != nil {
		fmt.Println(HugoNotFound)
		return cfg, fm, errors.New(HugoNotFound)
	}

	for c.Next() {
		cfg.Public = strings.Replace(root, "./", "", -1)
		cfg.BaseURL = "/admin"
		cfg.Root = "./"

		args := c.RemainingArgs()

		if len(args) >= 1 {
			cfg.Root = args[0]
			cfg.Root = strings.TrimSuffix(cfg.Root, "/")
			cfg.Root += "/"
		}

		if len(args) >= 2 {
			cfg.BaseURL = args[1]
			cfg.BaseURL = strings.TrimPrefix(cfg.BaseURL, "/")
			cfg.BaseURL = "/" + cfg.BaseURL
		}

		for c.NextBlock() {
			switch c.Val() {
			case "flag":
				if !c.NextArg() {
					return cfg, &filemanager.FileManager{}, c.ArgErr()
				}

				values := strings.Split(c.Val(), " ")

				if len(values) == 0 {
					return cfg, fm, errors.New("Not enough arguments for 'flag' option.")
				}

				value := "true"

				if len(values) > 1 {
					value = values[1]
				}

				cfg.Args = append(cfg.Args, "--"+values[0]+"="+value)
			case "before_publish":
				if cfg.BeforePublish, err = config.CommandRunner(c); err != nil {
					return cfg, &filemanager.FileManager{}, err
				}
			case "after_publish":
				if cfg.AfterPublish, err = config.CommandRunner(c); err != nil {
					return cfg, &filemanager.FileManager{}, err
				}
			default:
				line := "\n\t" + c.Val()

				if c.NextArg() {
					line += " " + c.Val()
				}

				tokens += line
			}
		}
	}

	tokens = "filemanager " + cfg.BaseURL + " {\n\tshow " + cfg.Root + tokens
	tokens += "\n}"

	fmConfig, err := config.Parse(caddy.NewTestController("http", tokens))

	if err != nil {
		return cfg, fm, err
	}

	fm = &filemanager.FileManager{Configs: fmConfig}
	fm.Configs[0].HugoEnabled = true

	format := getFrontMatter(cfg)

	cfg.WebDavURL = fm.Configs[0].WebDavURL

	for _, user := range fm.Configs[0].Users {
		user.FrontMatter = format
	}

	if err != nil {
		return cfg, fm, err
	}

	return cfg, fm, nil
}
Example #26
0
func redirParse(c *caddy.Controller) ([]Rule, error) {
	var redirects []Rule

	cfg := httpserver.GetConfig(c.Key)

	// setRedirCode sets the redirect code for rule if it can, or returns an error
	setRedirCode := func(code string, rule *Rule) error {
		if code == "meta" {
			rule.Meta = true
		} else if codeNumber, ok := httpRedirs[code]; ok {
			rule.Code = codeNumber
		} else {
			return c.Errf("Invalid redirect code '%v'", code)
		}
		return nil
	}

	// checkAndSaveRule checks the rule for validity (except the redir code)
	// and saves it if it's valid, or returns an error.
	checkAndSaveRule := func(rule Rule) error {
		if rule.FromPath == rule.To {
			return c.Err("'from' and 'to' values of redirect rule cannot be the same")
		}

		for _, otherRule := range redirects {
			if otherRule.FromPath == rule.FromPath {
				return c.Errf("rule with duplicate 'from' value: %s -> %s", otherRule.FromPath, otherRule.To)
			}
		}

		redirects = append(redirects, rule)
		return nil
	}

	for c.Next() {
		args := c.RemainingArgs()

		var hadOptionalBlock bool
		for c.NextBlock() {
			hadOptionalBlock = true

			var rule Rule

			if cfg.TLS.Enabled {
				rule.FromScheme = "https"
			} else {
				rule.FromScheme = "http"
			}

			// Set initial redirect code
			// BUG: If the code is specified for a whole block and that code is invalid,
			// the line number will appear on the first line inside the block, even if that
			// line overwrites the block-level code with a valid redirect code. The program
			// still functions correctly, but the line number in the error reporting is
			// misleading to the user.
			if len(args) == 1 {
				err := setRedirCode(args[0], &rule)
				if err != nil {
					return redirects, err
				}
			} else {
				rule.Code = http.StatusMovedPermanently // default code
			}

			// RemainingArgs only gets the values after the current token, but in our
			// case we want to include the current token to get an accurate count.
			insideArgs := append([]string{c.Val()}, c.RemainingArgs()...)

			switch len(insideArgs) {
			case 1:
				// To specified (catch-all redirect)
				// Not sure why user is doing this in a table, as it causes all other redirects to be ignored.
				// As such, this feature remains undocumented.
				rule.FromPath = "/"
				rule.To = insideArgs[0]
			case 2:
				// From and To specified
				rule.FromPath = insideArgs[0]
				rule.To = insideArgs[1]
			case 3:
				// From, To, and Code specified
				rule.FromPath = insideArgs[0]
				rule.To = insideArgs[1]
				err := setRedirCode(insideArgs[2], &rule)
				if err != nil {
					return redirects, err
				}
			default:
				return redirects, c.ArgErr()
			}

			err := checkAndSaveRule(rule)
			if err != nil {
				return redirects, err
			}
		}

		if !hadOptionalBlock {
			var rule Rule

			if cfg.TLS.Enabled {
				rule.FromScheme = "https"
			} else {
				rule.FromScheme = "http"
			}

			rule.Code = http.StatusMovedPermanently // default

			switch len(args) {
			case 1:
				// To specified (catch-all redirect)
				rule.FromPath = "/"
				rule.To = args[0]
			case 2:
				// To and Code specified (catch-all redirect)
				rule.FromPath = "/"
				rule.To = args[0]
				err := setRedirCode(args[1], &rule)
				if err != nil {
					return redirects, err
				}
			case 3:
				// From, To, and Code specified
				rule.FromPath = args[0]
				rule.To = args[1]
				err := setRedirCode(args[2], &rule)
				if err != nil {
					return redirects, err
				}
			default:
				return redirects, c.ArgErr()
			}

			err := checkAndSaveRule(rule)
			if err != nil {
				return redirects, err
			}
		}
	}

	return redirects, nil
}
Example #27
0
// setupTLS sets up the TLS configuration and installs certificates that
// are specified by the user in the config file. All the automatic HTTPS
// stuff comes later outside of this function.
func setupTLS(c *caddy.Controller) error {
	configGetter, ok := configGetters[c.ServerType()]
	if !ok {
		return fmt.Errorf("no caddytls.ConfigGetter for %s server type; must call RegisterConfigGetter", c.ServerType())
	}
	config := configGetter(c)
	if config == nil {
		return fmt.Errorf("no caddytls.Config to set up for %s", c.Key)
	}

	config.Enabled = true

	for c.Next() {
		var certificateFile, keyFile, loadDir, maxCerts string

		args := c.RemainingArgs()
		switch len(args) {
		case 1:
			// even if the email is one of the special values below,
			// it is still necessary for future analysis that we store
			// that value in the ACMEEmail field.
			config.ACMEEmail = args[0]

			// user can force-disable managed TLS this way
			if args[0] == "off" {
				config.Enabled = false
				return nil
			}

			// user might want a temporary, in-memory, self-signed cert
			if args[0] == "self_signed" {
				config.SelfSigned = true
			}
		case 2:
			certificateFile = args[0]
			keyFile = args[1]
			config.Manual = true
		}

		// Optional block with extra parameters
		var hadBlock bool
		for c.NextBlock() {
			hadBlock = true
			switch c.Val() {
			case "key_type":
				arg := c.RemainingArgs()
				value, ok := supportedKeyTypes[strings.ToUpper(arg[0])]
				if !ok {
					return c.Errf("Wrong key type name or key type not supported: '%s'", c.Val())
				}
				config.KeyType = value
			case "protocols":
				args := c.RemainingArgs()
				if len(args) == 1 {
					value, ok := supportedProtocols[strings.ToLower(args[0])]
					if !ok {
						return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
					}

					config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value
				} else {
					value, ok := supportedProtocols[strings.ToLower(args[0])]
					if !ok {
						return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
					}
					config.ProtocolMinVersion = value
					value, ok = supportedProtocols[strings.ToLower(args[1])]
					if !ok {
						return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
					}
					config.ProtocolMaxVersion = value
					if config.ProtocolMinVersion > config.ProtocolMaxVersion {
						return c.Errf("Minimum protocol version cannot be higher than maximum (reverse the order)")
					}
				}
			case "ciphers":
				for c.NextArg() {
					value, ok := supportedCiphersMap[strings.ToUpper(c.Val())]
					if !ok {
						return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val())
					}
					config.Ciphers = append(config.Ciphers, value)
				}
			case "clients":
				clientCertList := c.RemainingArgs()
				if len(clientCertList) == 0 {
					return c.ArgErr()
				}

				listStart, mustProvideCA := 1, true
				switch clientCertList[0] {
				case "request":
					config.ClientAuth = tls.RequestClientCert
					mustProvideCA = false
				case "require":
					config.ClientAuth = tls.RequireAnyClientCert
					mustProvideCA = false
				case "verify_if_given":
					config.ClientAuth = tls.VerifyClientCertIfGiven
				default:
					config.ClientAuth = tls.RequireAndVerifyClientCert
					listStart = 0
				}
				if mustProvideCA && len(clientCertList) <= listStart {
					return c.ArgErr()
				}

				config.ClientCerts = clientCertList[listStart:]
			case "load":
				c.Args(&loadDir)
				config.Manual = true
			case "max_certs":
				c.Args(&maxCerts)
				config.OnDemand = true
			case "dns":
				args := c.RemainingArgs()
				if len(args) != 1 {
					return c.ArgErr()
				}
				dnsProvName := args[0]
				if _, ok := dnsProviders[dnsProvName]; !ok {
					return c.Errf("Unsupported DNS provider '%s'", args[0])
				}
				config.DNSProvider = args[0]
			case "storage":
				args := c.RemainingArgs()
				if len(args) != 1 {
					return c.ArgErr()
				}
				storageProvName := args[0]
				if _, ok := storageProviders[storageProvName]; !ok {
					return c.Errf("Unsupported Storage provider '%s'", args[0])
				}
				config.StorageProvider = args[0]
			default:
				return c.Errf("Unknown keyword '%s'", c.Val())
			}
		}

		// tls requires at least one argument if a block is not opened
		if len(args) == 0 && !hadBlock {
			return c.ArgErr()
		}

		// set certificate limit if on-demand TLS is enabled
		if maxCerts != "" {
			maxCertsNum, err := strconv.Atoi(maxCerts)
			if err != nil || maxCertsNum < 1 {
				return c.Err("max_certs must be a positive integer")
			}
			config.OnDemandState.MaxObtain = int32(maxCertsNum)
		}

		// don't try to load certificates unless we're supposed to
		if !config.Enabled || !config.Manual {
			continue
		}

		// load a single certificate and key, if specified
		if certificateFile != "" && keyFile != "" {
			err := cacheUnmanagedCertificatePEMFile(certificateFile, keyFile)
			if err != nil {
				return c.Errf("Unable to load certificate and key files for '%s': %v", c.Key, err)
			}
			log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile)
		}

		// load a directory of certificates, if specified
		if loadDir != "" {
			err := loadCertsInDir(c, loadDir)
			if err != nil {
				return err
			}
		}
	}

	SetDefaultTLSParams(config)

	// generate self-signed cert if needed
	if config.SelfSigned {
		err := makeSelfSignedCert(config)
		if err != nil {
			return fmt.Errorf("self-signed: %v", err)
		}
	}

	return nil
}
Example #28
0
func webSocketParse(c *caddy.Controller) ([]Config, error) {
	var websocks []Config
	var respawn bool

	optionalBlock := func() (hadBlock bool, err error) {
		for c.NextBlock() {
			hadBlock = true
			if c.Val() == "respawn" {
				respawn = true
			} else {
				return true, c.Err("Expected websocket configuration parameter in block")
			}
		}
		return
	}

	for c.Next() {
		var val, path, command string

		// Path or command; not sure which yet
		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		val = c.Val()

		// Extra configuration may be in a block
		hadBlock, err := optionalBlock()
		if err != nil {
			return nil, err
		}

		if !hadBlock {
			// The next argument on this line will be the command or an open curly brace
			if c.NextArg() {
				path = val
				command = c.Val()
			} else {
				path = "/"
				command = val
			}

			// Okay, check again for optional block
			_, err = optionalBlock()
			if err != nil {
				return nil, err
			}
		}

		// Split command into the actual command and its arguments
		cmd, args, err := caddy.SplitCommandAndArgs(command)
		if err != nil {
			return nil, err
		}

		websocks = append(websocks, Config{
			Path:      path,
			Command:   cmd,
			Arguments: args,
			Respawn:   respawn, // TODO: This isn't used currently
		})
	}

	return websocks, nil

}
Example #29
0
func rewriteParse(c *caddy.Controller) ([]httpserver.HandlerConfig, error) {
	var rules []httpserver.HandlerConfig

	for c.Next() {
		var rule Rule
		var err error
		var base = "/"
		var pattern, to string
		var ext []string

		args := c.RemainingArgs()

		var matcher httpserver.RequestMatcher

		switch len(args) {
		case 1:
			base = args[0]
			fallthrough
		case 0:
			// Integrate request matcher for 'if' conditions.
			matcher, err = httpserver.SetupIfMatcher(c)
			if err != nil {
				return nil, err
			}

			for c.NextBlock() {
				if httpserver.IfMatcherKeyword(c) {
					continue
				}
				switch c.Val() {
				case "r", "regexp":
					if !c.NextArg() {
						return nil, c.ArgErr()
					}
					pattern = c.Val()
				case "to":
					args1 := c.RemainingArgs()
					if len(args1) == 0 {
						return nil, c.ArgErr()
					}
					to = strings.Join(args1, " ")
				case "ext":
					args1 := c.RemainingArgs()
					if len(args1) == 0 {
						return nil, c.ArgErr()
					}
					ext = args1
				default:
					return nil, c.ArgErr()
				}
			}
			// ensure to is specified
			if to == "" {
				return nil, c.ArgErr()
			}
			if rule, err = NewComplexRule(base, pattern, to, ext, matcher); err != nil {
				return nil, err
			}
			rules = append(rules, rule)

		// the only unhandled case is 2 and above
		default:
			rule = NewSimpleRule(args[0], strings.Join(args[1:], " "))
			rules = append(rules, rule)
		}

	}

	return rules, nil
}
Example #30
0
func logParse(c *caddy.Controller) ([]Rule, error) {
	var rules []Rule

	for c.Next() {
		args := c.RemainingArgs()

		var logRoller *httpserver.LogRoller
		if c.NextBlock() {
			if c.Val() == "rotate" {
				if c.NextArg() {
					if c.Val() == "{" {
						var err error
						logRoller, err = httpserver.ParseRoller(c)
						if err != nil {
							return nil, err
						}
						// This part doesn't allow having something after the rotate block
						if c.Next() {
							if c.Val() != "}" {
								return nil, c.ArgErr()
							}
						}
					}
				}
			}
		}
		if len(args) == 0 {
			// Nothing specified; use defaults
			rules = append(rules, Rule{
				PathScope:  "/",
				OutputFile: DefaultLogFilename,
				Format:     DefaultLogFormat,
				Roller:     logRoller,
			})
		} else if len(args) == 1 {
			// Only an output file specified
			rules = append(rules, Rule{
				PathScope:  "/",
				OutputFile: args[0],
				Format:     DefaultLogFormat,
				Roller:     logRoller,
			})
		} else {
			// Path scope, output file, and maybe a format specified

			format := DefaultLogFormat

			if len(args) > 2 {
				switch args[2] {
				case "{common}":
					format = CommonLogFormat
				case "{combined}":
					format = CombinedLogFormat
				default:
					format = args[2]
				}
			}

			rules = append(rules, Rule{
				PathScope:  args[0],
				OutputFile: args[1],
				Format:     format,
				Roller:     logRoller,
			})
		}
	}

	return rules, nil
}