OK, descobri uma maneira de fazer isso.
O que fiz foi usar mod_rewrite
, que é um módulo do Apache (enviado por padrão com todas as instalações) para reescrever os URLs solicitados na hora. Aqui está o código:
# Custom error pages
ErrorDocument 404 /hidden/404/index.html
ErrorDocument 403 /hidden/403/index.html
# Pretend that /hidden doesn't exist
# (unless this is an internal redirect,
# such as rendering a 404 or 403)
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^/hidden/.* - [L,R=404]
Então, vamos percorrer essas linhas. As diretivas ErrorDocument
não foram alteradas - elas apenas dizem qual página deve ser exibida quando um determinado erro ocorre.
A carne real está nas diretivas RewriteCond
e RewriteRule
. O que a diretiva RewriteRule
diz é a seguinte: se uma URL for solicitada cujo caminho coincida com o regex ^/hidden/.*
(essencialmente, qualquer caminho que esteja em / hidden ou sua subárvore), deixe a URL inalterada (é isso que o -
significa), mas não interpreta mais RewriteRule
diretivas (é o que significa L
) e retorna um código de erro 404 (é o que significa R=404
).
Isso, combinado com a diretiva ErrorDocument 404 /hidden/404/index.html
, parece funcionar. O problema, no entanto, é que quando o Apache vai servir /hidden/404/index.html
, ele executa essas regras novamente. Isso significa que a diretiva RewriteRule
é executada, o que, por sua vez, diz para renderizar o 404, e a coisa toda apenas loops infinitos.
Assim, usamos a diretiva RewriteCond
para garantir que isso não aconteça. As diretivas RewriteCond
são condicionais - a diretiva RewriteRule
abaixo só será executada se a condição for satisfeita. A condição, neste caso, é "a variável de ambiente REDIRECT_STATUS
é igual à cadeia vazia". Agora, REDIRECT_STATUS
é uma variável de ambiente definida por ErrorDocument
e contém o código de status que está sendo redirecionado (portanto, se a diretiva ErrorDocument 404 ...
tiver sido acionada, ela será configurada para o valor "404") . No entanto, se nenhuma diretiva ErrorDocument
tivesse sido executada, então REDIRECT_STATUS
não teria sido definido e, portanto, pedir seu valor simplesmente retornaria a string vazia. Assim, RewriteCond %{ENV:REDIRECT_STATUS} =""
essencialmente diz: "não se incomode em avaliar a diretiva RewriteRule
abaixo, a menos que não estejamos no meio de uma página de erro".
note: Se você consultou a documentação de RewriteRule
, você deve ter notado que o argumento R
deveria executar um redirecionamento explícito. O motivo pelo qual funciona bem, nesse caso, é que há um recurso não documentado do argumento R
, que apenas redireciona os códigos de 300 classes. Assim, R=404
não faz um redirecionamento explícito, apenas um interno.