@@ -139,20 +139,32 @@ server {
139139 # Version root and language redirects
140140 # ========================================
141141
142+ # Redirect .next version without trailing slash to .next/
143+ # /5.next → /5.next/
144+ location ~ "^/([3-9]|[1-9][0-9]+)\.next$" {
145+ return 301 /$1.next/;
146+ }
147+
142148 # Redirect .next version with language code to ensure trailing slash
143- location ~ "^/(6|5|4|3 )\.next/([a-z]{2})$" {
149+ location ~ "^/([3-9]|[1-9][0-9]+ )\.next/([a-z]{2})$" {
144150 return 301 /$1.next/$2/;
145151 }
146152
153+ # Redirect version.x without trailing slash to version.x/
154+ # /5.x → /5.x/
155+ location ~ "^/([2-9]|[1-9][0-9]+)\.x$" {
156+ return 301 /$1.x/;
157+ }
158+
147159 # Redirect bare version numbers to version.x format with English
148160 # /5 → /5.x/en/
149- location ~ ^/([2-6] )/?$ {
161+ location ~ ^/([2-9]|[1-9][0-9]+ )/?$ {
150162 return 301 /$1.x/en/;
151163 }
152164
153165 # Redirect version with language code to .x format
154166 # /5/en → /5.x/en/, /5/ja → /5.x/ja/
155- location ~ "^/([2-6] )/([a-z]{2})/?$" {
167+ location ~ "^/([2-9]|[1-9][0-9]+ )/([a-z]{2})/?$" {
156168 return 301 /$1.x/$2/;
157169 }
158170
@@ -170,7 +182,7 @@ server {
170182
171183 # Redirect long version numbers to short .x format
172184 # /5.0/something → /5.x/something
173- location ~ "^/(6|5|4|3|2 )\.0/(.*)$" {
185+ location ~ "^/([2-9]|[1-9][0-9]+ )\.0/(.*)$" {
174186 return 301 /$1.x/$2;
175187 }
176188
@@ -194,7 +206,7 @@ server {
194206 # Development/pre-release documentation (.next versions)
195207 # ========================================
196208
197- location ~ "^/(6|5|4|3 )\.next/(.*)" {
209+ location ~ "^/([3-9]|[1-9][0-9]+ )\.next/(.*)" {
198210 set $doc_version $1.next;
199211 set $request_path $2;
200212
@@ -268,41 +280,56 @@ server {
268280 }
269281
270282 # Plugin root redirects to latest version
271- location ~ ^/(authentication|authorization|bake|chronos|debugkit|elasticsearch|migrations|phinx|queue )/?$ {
283+ location ~ ^/([a-z]+ )/?$ {
272284 set $plugin_name $1;
285+ # Validate plugin exists in map, otherwise 404
286+ if ($plugin_latest = "") {
287+ return 404;
288+ }
273289 return 301 /$plugin_name/$plugin_latest/en/;
274290 }
275- location ~ ^/elasticsearch/5/?(.*)$ {
276- proxy_set_header Host "elasticsearch-docs-5.cakephp.org";
277- proxy_pass http://localhost:80/$1;
278- }
279291
280292 # Plugin /latest redirects
281- location ~ ^/(authentication|authorization|bake|chronos|debugkit|elasticsearch|migrations|phinx|queue )/latest/?$ {
293+ location ~ ^/([a-z]+ )/latest/?$ {
282294 set $plugin_name $1;
295+ # Validate plugin exists in map, otherwise 404
296+ if ($plugin_latest = "") {
297+ return 404;
298+ }
283299 return 301 /$plugin_name/$plugin_latest/en/;
284300 }
285- location ~ ^/migrations/5/?(.*)$ {
286- proxy_set_header Host "migrations-docs-5.cakephp.org";
287- proxy_pass http://localhost:80/$1;
288- }
289301
290- location ~ ^/(authentication|authorization|bake|chronos|debugkit|elasticsearch|migrations|phinx|queue )/latest/(.*)$ {
302+ location ~ ^/([a-z]+ )/latest/(.*)$ {
291303 set $plugin_name $1;
304+ # Validate plugin exists in map, otherwise 404
305+ if ($plugin_latest = "") {
306+ return 404;
307+ }
292308 return 301 /$plugin_name/$plugin_latest/$2;
293309 }
294310
295311 # Plugin version root redirects (version → version/en/)
296- location ~ ^/(authentication|authorization|bake|chronos|debugkit|elasticsearch|migrations|phinx|queue)/([0-9]+)/?$ {
297- return 301 /$1/$2/en/;
312+ location ~ ^/([a-z]+)/([0-9]+)/?$ {
313+ set $plugin_name $1;
314+ set $plugin_version $2;
315+ # Validate plugin-version combo exists in map, otherwise 404
316+ if ($plugin_host = "") {
317+ return 404;
318+ }
319+ return 301 /$plugin_name/$plugin_version/en/;
298320 }
299321
300322 # Plugin proxy pass (unified for all plugins using maps)
301- location ~ ^/(authentication|authorization|bake|chronos|debugkit|elasticsearch|migrations|phinx|queue )/([0-9]+)/?(.*)$ {
323+ location ~ ^/([a-z]+ )/([0-9]+)/?(.*)$ {
302324 set $plugin_name $1;
303325 set $plugin_version $2;
304326 set $request_path $3;
305327
328+ # Validate plugin-version combo exists in map, otherwise 404
329+ if ($plugin_host = "") {
330+ return 404;
331+ }
332+
306333 # Cache static assets
307334 if ($request_path ~* ^(public|fonts|assets)/) {
308335 expires 1y;
0 commit comments