2008-10-11

Jugando con un proxy HTTP

El proxy transparente de Telefónica está andando mal y trae versiones viejas de un montón de páginas. Así que estuve pensando la forma de forzarlo a que traiga la última versión. Lo hablé con algunos compañeros de laburo, y lo que me sugirieron es que instale un proxy que agregue headers que fuercen el no-cacheo de las páginas. En particular, sugirieron que instalara privoxy y lo configurara con los headers que quiero agregar.
Pero, ¿para que voy a hacer algo rápida y fácilmente si me puedo meter en un quilombito? El mismísimo whytheluckystiff hizo mousehole, un proxy implementado en ruby puro. Pero mousehole está pensado para transformar las páginas a medida que van bajando, no para cambiar los headers a la ida. Así que tuve que toquetear un poquito.
Por lo que pude ver, mousehole tiene 3 capas. Una primera capa es el handler de mongrel que atiende los pedidos de http, la capa del medio es una capa que maneja los plug-ins del proxy (a los que llama apps) y una tercera capa son las apps propiamente dichas. Para agregar la funcionalidad de cambiar el request tuve que tocar estas 3 capas.
En el handler, agregué un lugar para interceptar la página antes de pedir al host la página. Este es el diff del svn:


Index: lib/mouseHole/proxyhandler.rb
===================================================================
--- lib/mouseHole/proxyhandler.rb (revision 129)
+++ lib/mouseHole/proxyhandler.rb (working copy)
@@ -46,6 +46,8 @@
choose_header(reqh, header)
set_via(header)

+ uri, header = @central.change_request(uri, header)
+
http = Net::HTTP.new(env['server-name'], env['server-port'], @central.proxy_host, @central.proxy_port)
http.open_timeout = 10
http.read_timeout = 20

En la capa que maneja los plugins (que en el código se llama central) hice que cuando llegue un pedido, intente reescribir los headers en cada app. Este es el diff del svn:

Index: lib/mouseHole/central.rb
===================================================================
--- lib/mouseHole/central.rb (revision 129)
+++ lib/mouseHole/central.rb (working copy)
@@ -95,6 +95,13 @@
end
end

+ def change_request(uri, header)
+ @apps.values.each do |app|
+ uri, header = app.change_request(uri, header)
+ end
+ [uri, header]
+ end
+
def rewrite(page, resin)
apps = find_rewrites(page)
return false if apps.empty?

Y por último, en la clase base de las apps hice que por default deje los headers y el URI original, así es todo retrocompatible (o casi). Acá está el diff del svn:

Index: lib/mouseHole/app.rb
===================================================================
--- lib/mouseHole/app.rb (revision 129)
+++ lib/mouseHole/app.rb (working copy)
@@ -58,6 +58,10 @@
end
end

+ def change_request(uri, header)
+ [uri, header]
+ end
+
def do_rewrite(page)
@document = page.document
begin

Con todo esto andando, pude hacer mi cometido, que es hacer un proxy que le agregue el header "Cache-Control: no-cache" a los requests, para que Speedy no me de versiones viejas. El código de la app que hace esto quedó resimple:

class NoCache < MouseHole::App
title "No Cache"
namespace "aure"
description %{
Forces all the request to be non cached.
Sets the Cache-Control header to no-cache.
}
version "0.1"

def change_request(uri, header)
header << ['Cache-Control', 'no-cache']
[uri, header]
end
end


Gracias Speedy y Telefónica por la inspiración y happy hacking,
Aureliano.

PD: si los headers no sirven, voy a cambiar el URI agregando parámetros aleatorios y listo, así que no me provoquen.

7 comentarios:

Marcelo dijo...

Nada quita que tu momento de hacking haya sido bárbaro y "rejuvenecedor"... pero también existe este plugin Firefox: Modify Headers :-)

Claro que hay que hacer la salvedad de que mientras éste se instala en 1 minuto y sirve sólo para la navegación web, el proxy que armaste sirve para todos los protocolos.

Saludos
Marcelo

aurelianito dijo...

En realidad, mi idea es usar el proxy también para los updates de ubuntu. Porque el proxy transparente de speedy trae versiones viejas de algunas cosas y quedan desincronizadas las firmas de los paquetes con las claves publicas para corroborar su autenticidad. Por eso un plugin para firefox no me alcanza.
También estuvo la parte de que es divertido hackear un toque.

Marcelo dijo...

Ah! a mí me pasó lo mismo, pero no tuve tiempo para hackear como vos :-(

Para los updates de Ubuntu, podés hacer un:

$ sudo cat > /etc/apt/apt.conf.d/98no-cache
Acquire {
http {
No-Cache "true";
}
};
(Ctrl+D)

Así APT setea esos headers en las conexiones HTTP. :-)

Saludos
Marcelo

aurelianito dijo...

¡Buenísimo! No sabía. Ahora lo configuro así.

Andrés dijo...

Probaron con :

apt-get update -o Acquire::http::No-Cache=True

aurelianito dijo...

No puedo hacer eso desde el adept (manager|updater). Por eso es mejor para mi dejarlo en la configuración.

Alfred dijo...

https://www.browseunblocked.com

Es bastante rapido, y encima va encriptado asi que no pueden limitar youtube y esas cosas.