Package Pyblio :: Package External :: Module HTTP
[hide private]
[frames] | no frames]

Source Code for Module Pyblio.External.HTTP

  1  import os 
  2  import struct 
  3  import socket 
  4  from twisted.web import client 
  5  from twisted.internet import reactor 
  6  from twisted.internet.protocol import ClientFactory, Protocol 
  7  from twisted.python import log 
  8   
  9  # provide SOCKS access if needed 
 10  socks = os.getenv('SOCKS') 
 11  if socks: 
 12      socks_addr, socks_port = socks.split(':') 
 13      socks_port = int(socks_port) 
 14   
15 -class SOCKS4Protocol(Protocol):
16 """Implementation of subset of SOCKS4. 17 18 Information taken from http://en.wikipedia.org/wiki/SOCKS 19 20 Once the communication is established, this class behaves as a 21 transport for the client that instanciated it. 22 """
23 - def connectionMade(self):
24 self.established = False 25 self.buf = "" 26 log.msg("SOCKS connection to %s" % self.factory.addr) 27 data = struct.pack('!BBH', 28 0x04, # SOCKS version 4 29 0x01, # request tcp connection 30 self.factory.port) 31 data += socket.inet_aton(self.factory.addr) 32 # provide a dumb username 33 data += 'pyblio\0' 34 self.transport.write(data)
35
36 - def dataReceived(self, data):
37 if not self.established: 38 self.buf += data 39 if self.buf < 8: 40 return 41 try: 42 _, status, port = struct.unpack('!BBH', self.buf[:4]) 43 except struct.error: 44 raise RuntimeError("invalid reply") 45 addr = socket.inet_ntoa(self.buf[4:]) 46 if status == 0x5a: 47 self.established = True 48 # these are here to make this behave as a transport 49 self.disconnecting = False 50 # the client will use self as its transport 51 self.p = self.factory.client.buildProtocol(addr) 52 self.p.transport = self 53 self.p.connectionMade() 54 else: 55 raise RuntimeError("SOCKS connection refused: %x" % status) 56 57 if self.buf > 8: 58 self.p.dataReceived(self.buf[8:]) 59 return 60 self.p.dataReceived(data)
61
62 - def connectionLost(self, reason):
63 log.msg("SOCKS connection lost: %s" % reason) 64 self.p.connectionLost(reason)
65
66 - def write(self, data):
67 assert self.established 68 self.transport.write(data)
69
70 - def loseConnection(self):
71 self.transport.loseConnection()
72
73 -class SOCKS4Client(ClientFactory):
74 """ A SOCKS4 connection to a server.""" 75 protocol = SOCKS4Protocol 76
77 - def __init__(self, addr, port, client):
78 self.addr = addr 79 self.port = port 80 self.client = client
81
82 - def clientConnectionFailed(self, connector, reason):
83 self.client.clientConnectionFailed(connector, reason)
84
85 - def clientConnectionLost(self, connector, reason):
86 self.client.clientConnectionLost(connector, reason)
87
88 -class HTTPRetrieve(client.HTTPClientFactory):
89 """ Cancellable HTTP client. 90 91 This HTTP getter keeps track of the running protocol 92 instances, so that their transport can be closed in the middle of 93 an operation.""" 94
95 - def __init__(self, url, *args, **kargs):
96 client.HTTPClientFactory.__init__(self, url, *args, **kargs) 97 98 self.running = [] 99 100 scheme, host, port, path = client._parse(url) 101 if socks: 102 from twisted.names.client import getHostByName 103 def connectToIP(ip): 104 self.socks = SOCKS4Client(ip, port, self) 105 reactor.connectTCP(socks_addr, socks_port, self.socks)
106 def failed(failure): 107 self.deferred.errback(failure)
108 getHostByName(host).addCallback(connectToIP).addErrback(failed) 109 else: 110 reactor.connectTCP(host, port, self) 111 return 112
113 - def buildProtocol(self, addr):
114 p = client.HTTPClientFactory.buildProtocol(self, addr) 115 self.running.append(p) 116 return p
117
118 - def cancel(self):
119 self.running[-1].transport.loseConnection() 120 return
121