From cc5410494e8f6d2af4b3b555420f452730899975 Mon Sep 17 00:00:00 2001 From: Solderpunk Date: Wed, 1 Jul 2020 11:13:38 +0200 Subject: [PATCH] Handle redirects using regular expressions, not just literal paths. --- README.md | 16 ++++++++++------ handler.go | 26 ++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index bb5222f..ecaccd6 100644 --- a/README.md +++ b/README.md @@ -206,12 +206,16 @@ directory listing: ### Redirects -* `TempRedirects`: In this section of the config file, keys and values - are both path strings. If the path component of a received request - matches one of the keys, Molly Brown will serve a redirect to the - corresponding value, using status code 30. Note that currently - redirects cannot be specified using regular exressions, only literal - path strings. +* `TempRedirects`: In this section of the config file, keys are + regular expressions which the server will attempt to match against + the path component if incoming request URLs. If a match is found, + Molly Brown will serve a redirect to a new URL derived by replacing + the path component with the value corresponding to the matched key. + Within the replacement values, $1, $2, etc. will be replaced by the + first, second, etc. submatch in the regular expression. Named + captures can also be used for more sophisticated redirect logic - + see the documentation for the Go standard library's `regexp` package + for full details. * `PermRedirects`: As per `TempRedirects` above, but Molly Brown will use the 31 status code instead of 30. diff --git a/handler.go b/handler.go index 61387d0..cf16c18 100644 --- a/handler.go +++ b/handler.go @@ -248,19 +248,21 @@ func parseMollyFiles(path string, config *Config, errorLogEntries chan string) { } func handleRedirects(URL *url.URL, config Config, conn net.Conn, log *LogEntry) { - for src, dst := range config.TempRedirects { - if URL.Path == src { - URL.Path = dst - conn.Write([]byte("30 " + URL.String() + "\r\n")) - log.Status = 30 - return + handleRedirectsInner(URL, config.TempRedirects, 30, conn, log) + handleRedirectsInner(URL, config.PermRedirects, 31, conn, log) +} + +func handleRedirectsInner(URL *url.URL, redirects map[string]string, status int, conn net.Conn, log *LogEntry) { + strStatus := strconv.Itoa(status) + for src, dst := range redirects { + compiled, err := regexp.Compile(src) + if err != nil { + continue } - } - for src, dst := range config.PermRedirects { - if URL.Path == src { - URL.Path = dst - conn.Write([]byte("31 " + URL.String() + "\r\n")) - log.Status = 31 + if compiled.MatchString(URL.Path) { + URL.Path = compiled.ReplaceAllString(URL.Path, dst) + conn.Write([]byte(strStatus + " " + URL.String() + "\r\n")) + log.Status = status return } }