Example #1
0
func redirParse(c *Controller) ([]redirect.Rule, error) {
	var redirects []redirect.Rule

	for c.Next() {
		var rule redirect.Rule
		args := c.RemainingArgs()

		switch len(args) {
		case 1:
			// To specified
			rule.From = "/"
			rule.To = args[0]
			rule.Code = http.StatusMovedPermanently
		case 2:
			// To and Code specified
			rule.From = "/"
			rule.To = args[0]
			if code, ok := httpRedirs[args[1]]; !ok {
				return redirects, c.Err("Invalid redirect code '" + args[1] + "'")
			} else {
				rule.Code = code
			}
		case 3:
			// From, To, and Code specified
			rule.From = args[0]
			rule.To = args[1]
			if code, ok := httpRedirs[args[2]]; !ok {
				return redirects, c.Err("Invalid redirect code '" + args[2] + "'")
			} else {
				rule.Code = code
			}
		default:
			return redirects, c.ArgErr()
		}

		if rule.From == rule.To {
			return redirects, c.Err("Redirect rule cannot allow From and To arguments to be the same.")
		}

		redirects = append(redirects, rule)
	}

	return redirects, nil
}
Example #2
0
File: redir.go Project: CrawX/caddy
func redirParse(c *Controller) ([]redirect.Rule, error) {
	var redirects []redirect.Rule

	// setRedirCode sets the redirect code for rule if it can, or returns an error
	setRedirCode := func(code string, rule *redirect.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 redirect.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 redirect.Rule

			if c.Config.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 redirect.Rule

			if c.Config.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
}