Skip to content

Commit 1c51c0e

Browse files
committed
feat(redirect): add include_path (and trim_prefix) for wildcard redirect support
Signed-off-by: Vaughn Dice <[email protected]>
1 parent 76c30c6 commit 1c51c0e

File tree

2 files changed

+76
-5
lines changed

2 files changed

+76
-5
lines changed

README.md

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ The `spin-redirect` component can be configured to address your needs in differe
1313

1414
The following table outlines available configuration values:
1515

16-
| Key | Description | Default Value |
17-
|---------------|-------------------------------------------------------|------------------|
18-
| `destination` | Where should the component redirect to | `/` |
19-
| `statuscode` | What HTTP status code should be used when redirecting | `302` |
16+
| Key | Description | Default Value |
17+
|----------------|-------------------------------------------------------------------------------------------------------------------------|---------------|
18+
| `destination` | Where should the component redirect to | `/` |
19+
| `statuscode` | What HTTP status code should be used when redirecting | `302` |
20+
| `include_path` | Whether to include the original request path on the destination redirect; see [wildcard redirects](#wildcard-redirects) | `false` |
21+
| `trim_prefix` | A specific prefix portion of the original request path to trim (when `include_path` is `true`) | |
2022

2123
The `spin-redirect` component tries to look up the config value in the Spin component configuration using the keys shown in the table above (lower case). If desired key is not present, it transforms the key to upper case (e.g., `DESTINATION`) and checks environment variables.
2224

@@ -73,3 +75,47 @@ statuscode="301"
7375
route = "/"
7476

7577
```
78+
79+
### Wildcard redirects
80+
81+
Wildcard redirects can be enabled by setting `include_path` to `true`. In the example below,
82+
all requests to the application will be redirected to `/foo`, with the original request path included,
83+
e.g. `/bar` will redirect to `/foo/bar`, `/baz` will redirect to `/foo/baz` and so on.
84+
85+
```toml
86+
spin_manifest_version = 2
87+
88+
[application]
89+
name = "wildcard-redirect"
90+
version = "0.1.0"
91+
92+
[[trigger.http]]
93+
id = "trigger-redirect-to-foo"
94+
component = "redirect-to-foo"
95+
route = "/..."
96+
97+
[component.redirect-to-foo]
98+
source = "modules/redirect.wasm"
99+
environment = { DESTINATION = "/foo", INCLUDE_PATH = "true" }
100+
```
101+
102+
A prefix portion of the original request path can be trimmed via the `trim_prefix` configuration.
103+
104+
In this example, the `/v1/` prefix is trimmed, such that requests to `/v1/bar` will redirect to `/v2/bar` and so on.
105+
106+
```toml
107+
spin_manifest_version = 2
108+
109+
[application]
110+
name = "wildcard-redirect"
111+
version = "0.1.0"
112+
113+
[[trigger.http]]
114+
id = "trigger-redirect-v1-to-v2"
115+
component = "redirect-v1-to-v2"
116+
route = "/v1/..."
117+
118+
[component.redirect-v1-to-v2]
119+
source = "modules/redirect.wasm"
120+
environment = { DESTINATION = "/v2", INCLUDE_PATH = "true", TRIM_PREFIX = "/v1/" }
121+
```

redirect.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package main
22

33
import (
44
"net/http"
5+
"net/url"
6+
"path"
57
"strconv"
8+
"strings"
69

710
spinhttp "github.com/fermyon/spin/sdk/go/http"
811
)
@@ -16,6 +19,10 @@ const (
1619
destinationKey string = "destination"
1720
// Key for loading desired HTTP status code
1821
statusCodeKey string = "statuscode"
22+
// Key to enable adding original path in redirect
23+
includePathKey string = "include_path"
24+
// Key for trimming a preceding portion of the included path
25+
trimPrefixKey string = "trim_prefix"
1926
)
2027

2128
func init() {
@@ -43,7 +50,7 @@ func (s SpinRedirect) handleFunc(w http.ResponseWriter, r *http.Request) {
4350
dest, _ := s.getDestination()
4451
code, _ := s.getStatusCode(r.Method)
4552

46-
w.Header().Set("Location", dest)
53+
w.Header().Set("Location", s.WithPath(dest, r))
4754
w.WriteHeader(code)
4855
}
4956

@@ -92,3 +99,21 @@ func isValidRedirectStatusCode(code int, method string) bool {
9299
}
93100
return false
94101
}
102+
103+
// WithPath returns the provided dest with the path portion of the request,
104+
// assuming the includePathKey has a value of true
105+
func (s SpinRedirect) WithPath(dest string, r *http.Request) string {
106+
includePath := s.cfg.Get(includePathKey)
107+
if includePath != "true" {
108+
return dest
109+
}
110+
111+
u, err := url.Parse(dest)
112+
if err != nil {
113+
return dest
114+
}
115+
116+
u.Path = path.Join(u.Path, strings.TrimPrefix(r.URL.Path, s.cfg.Get(trimPrefixKey)))
117+
118+
return u.String()
119+
}

0 commit comments

Comments
 (0)