|
8 | 8 | "net/http"
|
9 | 9 | "net/http/httptest"
|
10 | 10 | "net/url"
|
| 11 | + "regexp" |
11 | 12 | "testing"
|
12 | 13 |
|
13 | 14 | "github.com/labstack/echo/v4"
|
@@ -83,46 +84,6 @@ func TestProxy(t *testing.T) {
|
83 | 84 | body = rec.Body.String()
|
84 | 85 | assert.Equal(t, "target 2", body)
|
85 | 86 |
|
86 |
| - // Rewrite |
87 |
| - e = echo.New() |
88 |
| - e.Use(ProxyWithConfig(ProxyConfig{ |
89 |
| - Balancer: rrb, |
90 |
| - Rewrite: map[string]string{ |
91 |
| - "/old": "/new", |
92 |
| - "/api/*": "/$1", |
93 |
| - "/js/*": "/public/javascripts/$1", |
94 |
| - "/users/*/orders/*": "/user/$1/order/$2", |
95 |
| - }, |
96 |
| - })) |
97 |
| - req.URL, _ = url.Parse("/api/users") |
98 |
| - rec = httptest.NewRecorder() |
99 |
| - e.ServeHTTP(rec, req) |
100 |
| - assert.Equal(t, "/users", req.URL.EscapedPath()) |
101 |
| - assert.Equal(t, http.StatusOK, rec.Code) |
102 |
| - req.URL, _ = url.Parse( "/js/main.js") |
103 |
| - rec = httptest.NewRecorder() |
104 |
| - e.ServeHTTP(rec, req) |
105 |
| - assert.Equal(t, "/public/javascripts/main.js", req.URL.EscapedPath()) |
106 |
| - assert.Equal(t, http.StatusOK, rec.Code) |
107 |
| - req.URL, _ = url.Parse("/old") |
108 |
| - rec = httptest.NewRecorder() |
109 |
| - e.ServeHTTP(rec, req) |
110 |
| - assert.Equal(t, "/new", req.URL.EscapedPath()) |
111 |
| - assert.Equal(t, http.StatusOK, rec.Code) |
112 |
| - req.URL, _ = url.Parse( "/users/jack/orders/1") |
113 |
| - rec = httptest.NewRecorder() |
114 |
| - e.ServeHTTP(rec, req) |
115 |
| - assert.Equal(t, "/user/jack/order/1", req.URL.EscapedPath()) |
116 |
| - assert.Equal(t, http.StatusOK, rec.Code) |
117 |
| - req.URL, _ = url.Parse("/user/jill/order/T%2FcO4lW%2Ft%2FVp%2F") |
118 |
| - rec = httptest.NewRecorder() |
119 |
| - e.ServeHTTP(rec, req) |
120 |
| - assert.Equal(t, "/user/jill/order/T%2FcO4lW%2Ft%2FVp%2F", req.URL.EscapedPath()) |
121 |
| - assert.Equal(t, http.StatusOK, rec.Code) |
122 |
| - req.URL, _ = url.Parse("/api/new users") |
123 |
| - rec = httptest.NewRecorder() |
124 |
| - e.ServeHTTP(rec, req) |
125 |
| - assert.Equal(t, "/new%20users", req.URL.EscapedPath()) |
126 | 87 | // ModifyResponse
|
127 | 88 | e = echo.New()
|
128 | 89 | e.Use(ProxyWithConfig(ProxyConfig{
|
@@ -196,3 +157,104 @@ func TestProxyRealIPHeader(t *testing.T) {
|
196 | 157 | assert.Equal(t, tt.extectedXRealIP, req.Header.Get(echo.HeaderXRealIP), "hasRealIPheader: %t / hasIPExtractor: %t", tt.hasRealIPheader, tt.hasIPExtractor)
|
197 | 158 | }
|
198 | 159 | }
|
| 160 | + |
| 161 | +func TestProxyRewrite(t *testing.T) { |
| 162 | + // Setup |
| 163 | + upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) |
| 164 | + defer upstream.Close() |
| 165 | + url, _ := url.Parse(upstream.URL) |
| 166 | + rrb := NewRoundRobinBalancer([]*ProxyTarget{{Name: "upstream", URL: url}}) |
| 167 | + req := httptest.NewRequest(http.MethodGet, "/", nil) |
| 168 | + rec := httptest.NewRecorder() |
| 169 | + |
| 170 | + // Rewrite |
| 171 | + e := echo.New() |
| 172 | + e.Use(ProxyWithConfig(ProxyConfig{ |
| 173 | + Balancer: rrb, |
| 174 | + Rewrite: map[string]string{ |
| 175 | + "/old": "/new", |
| 176 | + "/api/*": "/$1", |
| 177 | + "/js/*": "/public/javascripts/$1", |
| 178 | + "/users/*/orders/*": "/user/$1/order/$2", |
| 179 | + }, |
| 180 | + })) |
| 181 | + req.URL, _ = url.Parse("/api/users") |
| 182 | + rec = httptest.NewRecorder() |
| 183 | + e.ServeHTTP(rec, req) |
| 184 | + assert.Equal(t, "/users", req.URL.EscapedPath()) |
| 185 | + assert.Equal(t, http.StatusOK, rec.Code) |
| 186 | + req.URL, _ = url.Parse("/js/main.js") |
| 187 | + rec = httptest.NewRecorder() |
| 188 | + e.ServeHTTP(rec, req) |
| 189 | + assert.Equal(t, "/public/javascripts/main.js", req.URL.EscapedPath()) |
| 190 | + assert.Equal(t, http.StatusOK, rec.Code) |
| 191 | + req.URL, _ = url.Parse("/old") |
| 192 | + rec = httptest.NewRecorder() |
| 193 | + e.ServeHTTP(rec, req) |
| 194 | + assert.Equal(t, "/new", req.URL.EscapedPath()) |
| 195 | + assert.Equal(t, http.StatusOK, rec.Code) |
| 196 | + req.URL, _ = url.Parse("/users/jack/orders/1") |
| 197 | + rec = httptest.NewRecorder() |
| 198 | + e.ServeHTTP(rec, req) |
| 199 | + assert.Equal(t, "/user/jack/order/1", req.URL.EscapedPath()) |
| 200 | + assert.Equal(t, http.StatusOK, rec.Code) |
| 201 | + req.URL, _ = url.Parse("/user/jill/order/T%2FcO4lW%2Ft%2FVp%2F") |
| 202 | + rec = httptest.NewRecorder() |
| 203 | + e.ServeHTTP(rec, req) |
| 204 | + assert.Equal(t, "/user/jill/order/T%2FcO4lW%2Ft%2FVp%2F", req.URL.EscapedPath()) |
| 205 | + assert.Equal(t, http.StatusOK, rec.Code) |
| 206 | + req.URL, _ = url.Parse("/api/new users") |
| 207 | + rec = httptest.NewRecorder() |
| 208 | + e.ServeHTTP(rec, req) |
| 209 | + assert.Equal(t, "/new%20users", req.URL.EscapedPath()) |
| 210 | +} |
| 211 | + |
| 212 | +func TestProxyRewriteRegex(t *testing.T) { |
| 213 | + // Setup |
| 214 | + upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) |
| 215 | + defer upstream.Close() |
| 216 | + url, _ := url.Parse(upstream.URL) |
| 217 | + rrb := NewRoundRobinBalancer([]*ProxyTarget{{Name: "upstream", URL: url}}) |
| 218 | + req := httptest.NewRequest(http.MethodGet, "/", nil) |
| 219 | + rec := httptest.NewRecorder() |
| 220 | + |
| 221 | + // Rewrite |
| 222 | + e := echo.New() |
| 223 | + e.Use(ProxyWithConfig(ProxyConfig{ |
| 224 | + Balancer: rrb, |
| 225 | + Rewrite: map[string]string{ |
| 226 | + "^/a/*": "/v1/$1", |
| 227 | + "^/b/*/c/*": "/v2/$2/$1", |
| 228 | + "^/c/*/*": "/v3/$2", |
| 229 | + }, |
| 230 | + RegexRewrite: map[*regexp.Regexp]string{ |
| 231 | + regexp.MustCompile("^/x/.+?/(.*)"): "/v4/$1", |
| 232 | + regexp.MustCompile("^/y/(.+?)/(.*)"): "/v5/$2/$1", |
| 233 | + }, |
| 234 | + })) |
| 235 | + |
| 236 | + testCases := []struct { |
| 237 | + requestPath string |
| 238 | + statusCode int |
| 239 | + expectPath string |
| 240 | + }{ |
| 241 | + {"/unmatched", http.StatusOK, "/unmatched"}, |
| 242 | + {"/a/test", http.StatusOK, "/v1/test"}, |
| 243 | + {"/b/foo/c/bar/baz", http.StatusOK, "/v2/bar/baz/foo"}, |
| 244 | + {"/c/ignore/test", http.StatusOK, "/v3/test"}, |
| 245 | + {"/c/ignore1/test/this", http.StatusOK, "/v3/test/this"}, |
| 246 | + {"/x/ignore/test", http.StatusOK, "/v4/test"}, |
| 247 | + {"/y/foo/bar", http.StatusOK, "/v5/bar/foo"}, |
| 248 | + } |
| 249 | + |
| 250 | + |
| 251 | + for _, tc := range testCases { |
| 252 | + t.Run(tc.requestPath, func(t *testing.T) { |
| 253 | + req.URL, _ = url.Parse(tc.requestPath) |
| 254 | + rec = httptest.NewRecorder() |
| 255 | + e.ServeHTTP(rec, req) |
| 256 | + assert.Equal(t, tc.expectPath, req.URL.EscapedPath()) |
| 257 | + assert.Equal(t, tc.statusCode, rec.Code) |
| 258 | + }) |
| 259 | + } |
| 260 | +} |
0 commit comments