regras mod_rewrite HTTPS / HTTP, interação estranha com reescrita index.php do CMS subsequente

1

Com as reescritas abaixo em htaccess, conforme o esperado , essa solicitação HTTPS não é reescrita:

https://example.com/system/anything

não é reescrito para

http://example.com/system/anything

Mas, inesperadamente, essa solicitação HTTPS é reescrita:

https://example.com/preview/anything

é reescrito para

http://example.com/index.php/preview/anything

Por que isso acontece?

Alguns outros fatos / observações:

/system/ é um caminho real no servidor. No entanto, /preview/ não é um caminho real: é um segmento de URL que faz sentido no CMS, por exemplo, /index.php/preview/anything é como o CMS recebe a solicitação para a URL /preview/anything .

Outras URLs que não são do sistema são reescritas corretamente (de HTTPS para HTTP) e são transmitidas corretamente para index.php. Por exemplo,

https://example.com/real

é reescrito para

http://example.com/real

Aqui está o bloco completo de regras:

 <IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /

 # Force HTTPS for System URLs
 RewriteCond %{REQUEST_URI} ^/system(.*)$ [NC]
 RewriteCond %{HTTPS} !=on
 RewriteRule ^(.*)$ "https://example.com/$1" [R=301,L]

 # Force HTTP for Other URLs, but not: system or preview
 RewriteCond %{REQUEST_URI} !^/(system|preview)/(.*)$ [NC]
 RewriteCond %{HTTPS} =on
 RewriteRule ^(.*)$ "http://example.com/$1" [R=302,L]

 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule ^(.*)$ /index.php/$1 [L]
 </IfModule>

Alguma idéia de por que /preview/ recebe o tratamento estranho?

Adicionado: Observe que /preview/anything está recebendo um 302 redirecionado para /index.php/preview/anything - e isso é uma grande parte do que parece ser tão estranho / inesperado. Não deveria estar recebendo um redirecionamento na regra final, apenas uma reescrita.

    
por Jay F 11.12.2013 / 03:07

4 respostas

1

Essas regras de reconfiguração estão em um arquivo .htaccess ? Nesse caso, o sinalizador [L] não faz o que você acha que faz - interrompe o processamento do conjunto de regras atual, mas, em seguida, o pedido é processado pelo Apache novamente, usando .htaccess arquivos apropriados para o URI reconfigurado, portanto, suas regras podem ser executadas novamente. Isso não acontece com regras que estão no arquivo de configuração do Apache (e não dentro de uma seção <Directory> ) - nesse caso, o [L] flag é tratado como esperado.

Por exemplo, https://example.com/preview/anything é reescrito internamente em https://example.com/index.php/preview/anything pela terceira regra; no entanto, para processar essa solicitação, o Apache deve ler o arquivo .htaccess novamente e, dessa vez, o URI corresponde à sua segunda regra, que retorna um 302 de redirecionamento.

O Apache 2.4.x suporta o [END] flag que interrompe esses loops de reescrita, ao contrário de [L] ; soluções para versões anteriores do Apache são mais complexas.

Se você quiser ter certeza de que o Apache faz apenas uma única passagem sobre suas regras de reescrita, você pode adicionar a seguinte regra antes de todas as outras:

RewriteCond %{ENV:REDIRECT_STATUS} !=""
RewriteRule ^ - [L]

Na primeira passagem, REDIRECT_STATUS estará vazio; na segunda passagem, ele terá um valor não vazio (geralmente 200 ), e a regra corresponderá e realmente parará de novas reescritas.

Caso tal regra não seja apropriada (por exemplo, em alguns casos, você precisa manipular URIs reconfiguradas na segunda passagem), é possível definir uma variável de ambiente em regras que devem ser realmente finais:

RewriteRule ^(.*)$ /index.php/$1 [L,E=FINISH:1]

e adicione a seguinte regra antes de todas as outras:

RewriteCond %{ENV:REDIRECT_FINISH} !=""
RewriteRule ^ - [L]

Observe que, durante a segunda passagem, o Apache precede REDIRECT_ aos nomes de variáveis de ambiente que foram definidos durante a primeira passagem; portanto, você precisa definir FINISH , mas teste REDIRECT_FINISH .

Como alternativa, você pode tentar modificar suas condições de correspondência para que as URIs de segunda passagem modificadas na primeira passagem não sejam correspondidas (por exemplo, insira (index\.php/)? no regexp na segunda regra).

    
por 14.12.2013 / 15:33
0

Parece que a última regra está introduzindo um redirecionamento absoluto http -based quando está sendo feito, talvez devido a algum bug ou recurso no Apache ou mod_rewrite.

Que tal você dividir em duas regras com uma condição extra?

Tente isto:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTPS} =off
RewriteRule ^(.*)$ http://example.com/index.php/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ https://example.com/index.php/$1 [L]
    
por 13.12.2013 / 05:19
0

O esquema http (em vez de https ) incomoda você? Se assim for, você deve olhar para a diretiva RewriteBase .

Dos documentos do mod_rewrite :

The RewriteBase directive specifies the URL prefix to be used for per-directory (htaccess) RewriteRule directives that substitute a relative path.

This directive is required when you use a relative path in a substitution in per-directory (htaccess) context (...)

    
por 13.12.2013 / 07:01
0

Eu não acho que você precisa do '(. *) $' no final das instruções RewriteCond, porque você não está usando os dados capturados em qualquer lugar. Você poderia simplificar os dois assim:

RewriteCond %{REQUEST_URI} ^/system [NC]

e     RewriteCond% {REQUEST_URI}! ^ / (Sistema | pré-visualização) / [NC]

O que eu também recomendo é ligar o RewriteLog e configurar o RewriteLogLevel para ver exatamente o que o apache está fazendo por solicitação. Com o apache 2.2 ou menos, seria:

RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 7

Você deve ver, passo a passo, exatamente o que corresponde e qual ação o apache realizou.

    
por 13.12.2013 / 22:46