Un proxy basilare con Twisted Python

ho rielaborato questo esempio: http://stackoverflow.com/questions/6491932/need-help-writing-a-twisted-proxy

Nello script definisco alcune classi in un ordine ben preciso, per evitare errori di tipo
NameError: name ‘NomeDellaClasse’ is not defined.

Per capire come si imposta il proxy, iniziamo dalla classe proxy.Proxy:
questa eredita da twisted.web.http.HTTPChannel, e la documentazione spiega che per avviare il reactor bisogna chiamare la factory http.HTTPFactory(), dopodichè segnalare alla factory quale classe derivata da proxy.Proxy usare:

class MyProxy(proxy.Proxy):
    pass

f = http.HTTPFactory()
f.protocol = MyProxy
reactor.listenTCP(8888, f)
try:
	reactor.run()
except KeyboardInterrupt:
	reactor.stop()

Questo script definisce un proxy perfettamente funzionante.
Ma mancano varie funzionalità: queste sono definite nei metodi delle varie classi del modulo proxy.

Per usare le altre classi bisogna ridefinirle (override), a cominciare proprio da Proxy:

Proxy

nel suo codice sorgente si vede che c’è la variabile requestFactory, per specificare quale ProxyRequest usare.

ProxyRequest

Ridefinendo proxy.ProxyRequest abbiamo a disposizione i metodi per manipolare le richieste HTTP.
Dal suo codice sorgente si vedono 2 parametri da specificare, protocols e ports.
Il metodo ProxyRequest.process() crea la richiesta:
come si può vedere, le proprietà protocols e ports vengono usate per creare la clientFactory

class ProxyRequest(Request):
    protocols = {'http': ProxyClientFactory}
    ports = {'http': 80}
    ...
    def process(self):
        parsed = urlparse.urlparse(self.uri)
        protocol = parsed[0]
        host = parsed[1]
        port = self.ports[protocol]
        ...
        class_ = self.protocols[protocol]
        clientFactory = class_(self.method, rest, self.clientproto, headers,
                               s, self)
        self.reactor.connectTCP(host, port, clientFactory)

ProxyClientFactory

Con il protocollo MyProxyClientFactory registrato in MyProxyRequest, si gestisce la parte client del proxy, cioè le risposte http.
Ridefinendo ProxyClientFactory si può specificare una classe figlia di ProxyClient.

ProxyClient

Ridefinendo ProxyClient si ha accesso ai metodi per manipolare le risposte.
Vedere il codice sorgente o la documentazione.

Notare che è necessario richiamare gli handler della classe genitrice !

Esempio

Tutto quanto detto finora si traduce nel seguente script:

""" file myproxy.py """
from twisted.web import http, proxy
from twisted.internet import reactor
from twisted.python import log
import sys

""" Salvo lo stdout prima di avviare il logging di twisted """
schermo = sys.stdout

log.startLogging(open('myproxy.log', 'w'))

class MyProxyClient(proxy.ProxyClient):
	def handleHeader(self, key, value):
		s = "Ricevuto header: " + key
		s+= ", " + value
		schermo.write(s + "\n")
		# richiamare il metodo della classe genitrice
		proxy.ProxyClient.handleHeader(self, key, value)

class MyProxyClientFactory(proxy.ProxyClientFactory):
	protocol = MyProxyClient

class MyProxyRequest(proxy.ProxyRequest):
	protocols = {'http': MyProxyClientFactory}
	ports = {'http': 80}

# non è necessario:
#	def process(self):
#		proxy.ProxyRequest.process(self)

class MyProxy(proxy.Proxy):
	requestFactory = MyProxyRequest


f = http.HTTPFactory()
f.protocol = MyProxy
reactor.listenTCP(8888, f)

try:
	reactor.run()
except KeyboardInterrupt:
	reactor.stop()

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...