Ya encontré la causa... y me ha dejado sorprendido, porque era algo que desconocía...
La clave está en la línea donde se hace la redirección:
print $sesion->header(-location=>"web.pl");Bueno, el caso es que lo normal es indicar, en un campo 'Location', una URL absoluta, pero los nuevos navegadores admiten URI relativas, como es este caso.
Y resulta que, efectivamente, el comportamiento del servidor web es muy distinto. A mi me pasa lo mismo que a pedrete: el
script web.pl es ejecutado y su salida es el resultado que se envía al cliente, y la URL que sigue mostrando es el de la petición anterior, login.pl.
Después de tres horas de investigación, he descubierto lo que pasa.
La explicación está en el RFC 3875, donde se describe el funcionamiento del protocolo CGI. Lo que nos interesa está justo en la explicación de la cabecera Location (
sección 6.3.2.). Esto es lo que dice:
The Location header field is used to specify to the server that the
script is returning a reference to a document rather than an actual
document (see sections 6.2.3 and 6.2.4). It is either an absolute
URI (optionally with a fragment identifier), indicating that the
client is to fetch the referenced document, or a local URI path
(optionally with a query string), indicating that the server is to
fetch the referenced document and return it to the client as the
response.
de lo cual nos quedamos con esta frase:
«Puede ser tanto una URL absoluta (con un identificador de fragmento opcional),
indicando que será el cliente el que solicite el documento referido, o una ruta URI
local (con una cadena de consulta opcional), indicando que será el servidor el que
solicite el documento referido y devolviéndolo al cliente, como respuesta.»Y esa es la causa: al poner una URI local, es el
propio servidor el que hace la petición, y la devuelve al cliente como si fuera el contenido de la primera petición. La URL que aparece en el navegador cliente sigue mostrando la dirección anterior, porque el cliente no ha recibido ningún código de estado HTTP 3xx (redirigir a una nueva dirección).
Entonces, este comportamiento lo podemos usar para algún caso especial de redirigir o seleccionar contenidos, pero para el caso de pedrete, no le sirve porque su navegador no llega a recibir la primera
cookie (se la come el Apache
).
Con los siguientes ejemplos cortos, ya funciona:
Using perl Syntax Highlighting
#!/usr/bin/perl
#use warnings;
#use strict;
use CGI;
use CGI::Session;
my $cgi = CGI->new;
my($user) = $cgi->param('user');
my($pass) = $cgi->param('pass');
if (CredentialsOK($user,$pass)){
my $sesion = CGI::Session->new;
$sesion->param('userlogged',$user);
print $sesion->header(-location => "http://mi.dominio.com/cgi/web.pl"); # <==
$sesion->flush();
}
else {
print $cgi->redirect(-uri=>"/login.html");
}
sub CredentialsOK {
my($user,$pass) = @_;
return ($user eq 'jf' and $pass eq 'perl03');
}
Coloreado en 0.002 segundos, usando
GeSHi 1.0.8.4
Using perl Syntax Highlighting
#!/usr/bin/perl
use warnings;
use CGI;
use CGI::Session;
my $cgi = CGI->new;
my $sesion = CGI::Session->load($cgi);
if ($sesion->is_expired or $sesion->is_empty) {
print $cgi->redirect(-uri => "/login.html"); # mejor si es absoluto
}
else {
print
$cgi->header(),
$cgi->start_html('Titulo'),
$cgi->p('Bienvenido ' . $sesion->param('userlogged')), # sí, ¡funciona!
$cgi->end_html(),
;
}
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
El cambio fundamental es poner una URL absoluta dentro de header().
Mejor aún, usar siempre un redirect(), porque siempre enviará un resultado 3xx al navegador:
Using perl Syntax Highlighting
print $cgi->redirect("/cgi/web.pl");
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
No se puede escribir
$sesion->redirect(...), porque CGI::Session no tiene definido ese método.
Resumen:- si queremos realizar un redireccionamiento, lo ideal es usar el método redirect()
- si no podemos usar un redirect() (?), entonces debemos indicarlo como cabecera 'Location' dentro de un header(). Y aquí hay que pensar en el distinto comportamiento de si es un URL absoluto o un URI relativo
Nunca te acostarás...