Mostrando las entradas con la etiqueta mousehole. Mostrar todas las entradas
Mostrando las entradas con la etiqueta mousehole. Mostrar todas las entradas

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.