16. Borrando de la memoria cache las páginas privadas de la aplicación

El origen

A raíz de este hilo en el oráculo, el Grupo Google CakePHP en español, y gracias a la respuesta que obtuve de Joaquin Windmüller, he implementado un componente para borrar de la memoria cache las páginas privadas. Todo esto empezó cuando se me ocurrió probar mi primer programa.

¿Qué puede escribir un usuario en su barra de direcciones?, pensaba. Exacto, pensaba lo mismo que en este otro hilo de CakePHP en español: voy a salir del programa y voy a escribir en la barra de direcciones de IE7 un URL privado, ¡a ver qué pasa! Por cierto, aunque lo intento, creo que todas las cosas que pasan por mi cabeza en el momento de hacer estas cosas nunca van a ser 100% reales. ¿Qué harán los usuarios delante de su PC? ¡Hacen falta muchas personas!

Haciendo las pruebas

El caso es que si en IE7 escribía un URL privado después de salir del programa, podía acceder al contenido, mientras que, por ejemplo, en Firefox 3.0.3, esto no pasaba. No he probado otros navegadores y supongo que será cuestión de armar un listado con los más utilizados para ver qué sucede.

Mi intento por arreglar esto, que, funcionar, funciona. ¿Será mejor el remedio que la enfermedad?

Según he entendido, muchos agentes de usuario guardan en su cache el contenido que reciben por HTTP. Sin embargo, uno puede cambiar este comportamiento predeterminado modificando los campos de la cabecera de respuesta. Más concretamente, y siguiendo las indicaciones de la documentación oficial de php, he escrito este componente:


class LimpiarcacheComponent extends Object{
   function limpiar(){
      header("Cache-Control: no-cache, must-revalidate");
      header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
   }
}

Este componente sirve para no guardar en la memoria cache las páginas privadas que sirve la aplicación CakePHP y lo primero que tenemos que hacer es cargarlo en la variable $components del controlador que sirve páginas privadas:


var $components = array('Limpiarcache');

A continuación, llamamos al método limpiar() al comienzo de las acciones que sirven contenido privado porque lo primero que queremos hacer es añadir estos campos a la cabecera del mensaje de respuesta HTTP. Por ejemplo, la acción que arma un listado de categorías quedaría así:


/**
       Método para listar y gestionar las categorías.
   */
   function listar(){
      $this->Limpiarcache->limpiar();
      /* Poblamos la variable $categorias de la vista listar.ctp. */
      $this->set('categorias', $this->paginate('Categoria'));
      $this->render('listar','zonaprivada');
   } // fin del método listar()

Si ahora usamos la aplicación CakePHP, salimos y, finalmente, escribimos el URL de alguna página privada, entonces ya no podemos acceder a su contenido. A nivel de HTTP, esto se traduce en un mensaje de respuesta con código de estado 302. Por ejemplo, para el URL de la acción que arma el listado de las categorías, http://www.midominio.com/usuarios/categorias/listar, el mensaje de respuesta HTTP es este:

HTTP/1.1 302 Found
Date: Thu, 15 Jan 2009 12:24:43 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.2.6
Set-Cookie: CAKEPHP=lq2pgsj7elrgifonjs1dd5ofh3; expires=Thu, 22 Jan 2009 12:24:43 GMT; path=/
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Location: http://www.midominio.com/usuarios/login
Content-Length: 0
Connection: close
Content-Type: text/html
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2009 12:24:43 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.2.6
Set-Cookie: CAKEPHP=c7j1jsf6lpbsnd53vr6cdnfui2; expires=Thu, 22 Jan 2009 12:24:44 GMT; path=/
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Content-Length: 6528
Connection: close
Content-Type: text/html

Mis dudas

Aún así, no me acaba de quedar muy claro el por qué de este código de respuesta 302. Consultando las definiciones de los códigos de respuesta HTTP 1.1 del RFC 2616, uno puede leer esto para el 302:

“The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field. The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s). If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.”

El final

Resumiendo, ¿qué ha pasado? Yo puedo leer hasta aquí. Funcionar, parece que funciona, y espero que este componente sirva para la mayoría de agentes de usuario. Si te animas a usarlo, recuerda: tú eres el único responsable del error catastrófico que puede producirse; si puedes ampliar o aclarar todo esto un poco, ¡deja aquí algún comentario!