Skip to content

Commit d4d2652

Browse files
sbegin0craigbox
andauthored
Redirect any "v.XX" not including docs to "latest" using a netlify edge function (#16378)
* Sam's version * Skynet's revised version * Fix test * Add test script * Lint test script --------- Co-authored-by: Craig Box <[email protected]>
1 parent f83d4a8 commit d4d2652

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ go/**
3838

3939
# archived site version
4040
archived_version
41+
42+
# Local Netlify folder
43+
.netlify

netlify.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@
1818
[headers.values]
1919
X-Frame-Options = "SAMEORIGIN"
2020
X-XSS-Protection = "1; mode=block"
21+
22+
[[edge_functions]]
23+
path = "/v*"
24+
function = "redirect-to-latest"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export default async (request: Request, context) => {
2+
const url = new URL(request.url);
3+
let pathname = url.pathname;
4+
5+
// Normalize consecutive slashes
6+
pathname = pathname.replace(/\/\/+/g, '/');
7+
8+
const versionMatch = pathname.match(/^\/v\d+\.\d+/);
9+
if (!versionMatch) return context.next();
10+
11+
const versionPath = versionMatch[0];
12+
const remainder = pathname.slice(versionPath.length) || '/';
13+
14+
const languageCodeMatch = remainder.match(/^\/?([a-z]{2})(\/|$)/);
15+
let languageCode: string | null = null;
16+
let remainingPath = remainder;
17+
18+
if (languageCodeMatch) {
19+
languageCode = languageCodeMatch[1];
20+
remainingPath = remainder.slice(languageCodeMatch[0].length);
21+
}
22+
23+
const normalizedPath = remainingPath.replace(/^\/+/, '');
24+
25+
const redirectableSections = ['about', 'blog', 'get-involved', 'news', 'search'];
26+
27+
const shouldRedirect =
28+
normalizedPath === '' || // redirect to /latest/
29+
redirectableSections.some(section =>
30+
normalizedPath === section || normalizedPath.startsWith(`${section}/`)
31+
);
32+
33+
if (shouldRedirect) {
34+
const newPath = `/latest/${languageCode ? `${languageCode}/` : ''}${normalizedPath}`;
35+
return Response.redirect(new URL(newPath, url.origin), 301);
36+
}
37+
38+
return context.next();
39+
};

scripts/test_netlify_redirects.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/bash
2+
3+
# Copyright Istio Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Test the Netlify redirect scripts by checking various URLs
18+
# Usage: ./test-netlify-redirects.sh [<base_url>]
19+
set -e
20+
21+
if [[ "$#" -ne 0 ]]; then
22+
BASE_URL="$*"
23+
else
24+
BASE_URL="https://preliminary.istio.io"
25+
fi
26+
27+
URLS=(
28+
# Should redirect
29+
"/v1.1/uk"
30+
"/v1.1/uk/"
31+
"/v1.10/news/support/announcing-1.9-eol/"
32+
"/v1.15/get-involved/"
33+
"/v1.20/blog"
34+
"/v1.20/uk/"
35+
"/v1.21/uk/blog"
36+
"/v1.21/zh/"
37+
"/v1.22/zh/news"
38+
"/v1.23/about"
39+
"/v1.24/uk/search"
40+
"/v1.24/zh"
41+
"/v1.24/zh/"
42+
"/v1.25/zh/get-involved"
43+
"/v1.26/"
44+
45+
# Should NOT redirect
46+
"/archive/"
47+
"/v1.20/docs/concepts"
48+
"/v1.21/zh/docs/setup"
49+
"/v1.22/docs/ops/diagnostic-tools"
50+
"/v1.22/docs/ops/diagnostic-tools/"
51+
"/v1.22/zh/docs/reference/config"
52+
"/v1.23/docs/"
53+
"/v1.24/docs/"
54+
"/v1.24/uk/docs/"
55+
"/v1.24/zh/docs/tasks/security"
56+
"/v1.24/zh/docs/tasks/security/"
57+
"/v1.25/zh/docs/tasks/security"
58+
59+
# /latest URLs (should not redirect)
60+
"/latest"
61+
"/latest/"
62+
"/latest/blog"
63+
"/latest/docs/"
64+
"/latest/uk/"
65+
"/latest/uk/blog"
66+
"/latest/zh/"
67+
"/latest/zh/docs"
68+
)
69+
70+
for path in "${URLS[@]}"; do
71+
full_url="${BASE_URL}${path}"
72+
response=$(curl -s -o /dev/null -w "%{http_code} %{redirect_url}" "$full_url")
73+
http_code=$(echo "$response" | cut -d' ' -f1)
74+
redirect_url=$(echo "$response" | cut -d' ' -f2-)
75+
76+
if [[ "$http_code" == "301" || "$http_code" == "302" ]]; then
77+
echo "[REDIRECT] $path$redirect_url"
78+
elif [[ "$http_code" == "200" ]]; then
79+
echo "[OK] $path"
80+
else
81+
echo "[?] $path - Status: $http_code"
82+
fi
83+
done
84+

0 commit comments

Comments
 (0)