diff --git a/.gitignore b/.gitignore index 97cc35437d998..06c01bc160dea 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ go/** # archived site version archived_version + +# Local Netlify folder +.netlify diff --git a/netlify.toml b/netlify.toml index 9458eae5cfa0f..99662359d9dca 100644 --- a/netlify.toml +++ b/netlify.toml @@ -14,3 +14,7 @@ [headers.values] X-Frame-Options = "SAMEORIGIN" X-XSS-Protection = "1; mode=block" + +[[edge_functions]] + path = "/v*" + function = "redirect-to-latest" \ No newline at end of file diff --git a/netlify/edge-functions/redirect-to-latest.ts b/netlify/edge-functions/redirect-to-latest.ts new file mode 100644 index 0000000000000..34e305f9eccdb --- /dev/null +++ b/netlify/edge-functions/redirect-to-latest.ts @@ -0,0 +1,39 @@ +export default async (request: Request, context) => { + const url = new URL(request.url); + let pathname = url.pathname; + + // Normalize consecutive slashes + pathname = pathname.replace(/\/\/+/g, '/'); + + const versionMatch = pathname.match(/^\/v\d+\.\d+/); + if (!versionMatch) return context.next(); + + const versionPath = versionMatch[0]; + const remainder = pathname.slice(versionPath.length) || '/'; + + const languageCodeMatch = remainder.match(/^\/?([a-z]{2})(\/|$)/); + let languageCode: string | null = null; + let remainingPath = remainder; + + if (languageCodeMatch) { + languageCode = languageCodeMatch[1]; + remainingPath = remainder.slice(languageCodeMatch[0].length); + } + + const normalizedPath = remainingPath.replace(/^\/+/, ''); + + const redirectableSections = ['about', 'blog', 'get-involved', 'news', 'search']; + + const shouldRedirect = + normalizedPath === '' || // redirect to /latest/ + redirectableSections.some(section => + normalizedPath === section || normalizedPath.startsWith(`${section}/`) + ); + + if (shouldRedirect) { + const newPath = `/latest/${languageCode ? `${languageCode}/` : ''}${normalizedPath}`; + return Response.redirect(new URL(newPath, url.origin), 301); + } + + return context.next(); +}; diff --git a/scripts/test_netlify_redirects.sh b/scripts/test_netlify_redirects.sh new file mode 100755 index 0000000000000..4fd78b4766e28 --- /dev/null +++ b/scripts/test_netlify_redirects.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Test the Netlify redirect scripts by checking various URLs +# Usage: ./test-netlify-redirects.sh [] +set -e + +if [[ "$#" -ne 0 ]]; then + BASE_URL="$*" +else + BASE_URL="https://preliminary.istio.io" +fi + +URLS=( + # Should redirect + "/v1.1/uk" + "/v1.1/uk/" + "/v1.10/news/support/announcing-1.9-eol/" + "/v1.15/get-involved/" + "/v1.20/blog" + "/v1.20/uk/" + "/v1.21/uk/blog" + "/v1.21/zh/" + "/v1.22/zh/news" + "/v1.23/about" + "/v1.24/uk/search" + "/v1.24/zh" + "/v1.24/zh/" + "/v1.25/zh/get-involved" + "/v1.26/" + + # Should NOT redirect + "/archive/" + "/v1.20/docs/concepts" + "/v1.21/zh/docs/setup" + "/v1.22/docs/ops/diagnostic-tools" + "/v1.22/docs/ops/diagnostic-tools/" + "/v1.22/zh/docs/reference/config" + "/v1.23/docs/" + "/v1.24/docs/" + "/v1.24/uk/docs/" + "/v1.24/zh/docs/tasks/security" + "/v1.24/zh/docs/tasks/security/" + "/v1.25/zh/docs/tasks/security" + + # /latest URLs (should not redirect) + "/latest" + "/latest/" + "/latest/blog" + "/latest/docs/" + "/latest/uk/" + "/latest/uk/blog" + "/latest/zh/" + "/latest/zh/docs" +) + +for path in "${URLS[@]}"; do + full_url="${BASE_URL}${path}" + response=$(curl -s -o /dev/null -w "%{http_code} %{redirect_url}" "$full_url") + http_code=$(echo "$response" | cut -d' ' -f1) + redirect_url=$(echo "$response" | cut -d' ' -f2-) + + if [[ "$http_code" == "301" || "$http_code" == "302" ]]; then + echo "[REDIRECT] $path → $redirect_url" + elif [[ "$http_code" == "200" ]]; then + echo "[OK] $path" + else + echo "[?] $path - Status: $http_code" + fi +done +