home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / BitTorrent / HTTPHandler.py < prev    next >
Encoding:
Python Source  |  2003-10-04  |  5.9 KB  |  176 lines

  1. # Written by Bram Cohen
  2. # see LICENSE.txt for license information
  3.  
  4. from cStringIO import StringIO
  5. from sys import stdout
  6. import time
  7. from gzip import GzipFile
  8.  
  9. DEBUG = False
  10.  
  11. weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  12.  
  13. months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  14.     'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  15.  
  16. class HTTPConnection:
  17.     def __init__(self, handler, connection):
  18.         self.handler = handler
  19.         self.connection = connection
  20.         self.buf = ''
  21.         self.closed = False
  22.         self.done = False
  23.         self.donereading = False
  24.         self.next_func = self.read_type
  25.  
  26.     def get_ip(self):
  27.         return self.connection.get_ip()
  28.  
  29.     def data_came_in(self, data):
  30.         if self.donereading or self.next_func is None:
  31.             return True
  32.         self.buf += data
  33.         while True:
  34.             try:
  35.                 i = self.buf.index('\n')
  36.             except ValueError:
  37.                 return True
  38.             val = self.buf[:i]
  39.             self.buf = self.buf[i+1:]
  40.             self.next_func = self.next_func(val)
  41.             if self.donereading:
  42.                 return True
  43.             if self.next_func is None or self.closed:
  44.                 return False
  45.  
  46.     def read_type(self, data):
  47.         self.header = data.strip()
  48.         words = data.split()
  49.         if len(words) == 3:
  50.             self.command, self.path, garbage = words
  51.             self.pre1 = False
  52.         elif len(words) == 2:
  53.             self.command, self.path = words
  54.             self.pre1 = True
  55.             if self.command != 'GET':
  56.                 return None
  57.         else:
  58.             return None
  59.         if self.command not in ('HEAD', 'GET'):
  60.             return None
  61.         self.headers = {}
  62.         return self.read_header
  63.  
  64.     def read_header(self, data):
  65.         data = data.strip()
  66.         if data == '':
  67.             self.donereading = True
  68.             # check for Accept-Encoding: header, pick a 
  69.             if self.headers.has_key('accept-encoding'):
  70.                 ae = self.headers['accept-encoding']
  71.                 if DEBUG:
  72.                     print "Got Accept-Encoding: " + ae + "\n"
  73.             else:
  74.                 #identity assumed if no header
  75.                 ae = 'identity'
  76.             # this eventually needs to support multple acceptable types
  77.             # q-values and all that fancy HTTP crap
  78.             # for now assume we're only communicating with our own client
  79.             if ae.find('gzip') != -1:
  80.                 self.encoding = 'gzip'
  81.             else:
  82.                 #default to identity. 
  83.                 self.encoding = 'identity'
  84.             r = self.handler.getfunc(self, self.path, self.headers)
  85.             if r is not None:
  86.                 self.answer(r)
  87.             return None
  88.         try:
  89.             i = data.index(':')
  90.         except ValueError:
  91.             return None
  92.         self.headers[data[:i].strip().lower()] = data[i+1:].strip()
  93.         if DEBUG:
  94.             print data[:i].strip() + ": " + data[i+1:].strip()
  95.         return self.read_header
  96.  
  97.     def answer(self, (responsecode, responsestring, headers, data)):
  98.         if self.closed:
  99.             return
  100.         if self.encoding == 'gzip':
  101.             #transform data using gzip compression
  102.             #this is nasty but i'm unsure of a better way at the moment
  103.             compressed = StringIO()
  104.             gz = GzipFile(fileobj = compressed, mode = 'wb', compresslevel = 9)
  105.             gz.write(data)
  106.             gz.close()
  107.             compressed.seek(0,0) 
  108.             cdata = compressed.read()
  109.             compressed.close()
  110.             if len(cdata) >= len(data):
  111.                 self.encoding = 'identity'
  112.             else:
  113.                 if DEBUG:
  114.                    print "Compressed: %i  Uncompressed: %i\n" % (len(cdata),len(data))
  115.                 data = cdata
  116.                 headers['Content-Encoding'] = 'gzip'
  117.  
  118.         # i'm abusing the identd field here, but this should be ok
  119.         if self.encoding == 'identity':
  120.             ident = '-'
  121.         else:
  122.             ident = self.encoding
  123.         username = '-'
  124.         referer = self.headers.get('referer','-')
  125.         useragent = self.headers.get('user-agent','-')
  126.         year, month, day, hour, minute, second, a, b, c = time.localtime(time.time())
  127.         print '%s %s %s [%02d/%3s/%04d:%02d:%02d:%02d] "%s" %i %i "%s" "%s"' % (
  128.             self.connection.get_ip(), ident, username, day, months[month], year, hour,
  129.             minute, second, self.header, responsecode, len(data), referer, useragent)
  130.         t = time.time()
  131.         if t - self.handler.lastflush > self.handler.minflush:
  132.             self.handler.lastflush = t
  133.             stdout.flush()
  134.  
  135.         self.done = True
  136.         r = StringIO()
  137.         r.write('HTTP/1.0 ' + str(responsecode) + ' ' + 
  138.             responsestring + '\r\n')
  139.         if not self.pre1:
  140.             headers['Content-Length'] = len(data)
  141.             for key, value in headers.items():
  142.                 r.write(key + ': ' + str(value) + '\r\n')
  143.             r.write('\r\n')
  144.         if self.command != 'HEAD':
  145.             r.write(data)
  146.         self.connection.write(r.getvalue())
  147.         if self.connection.is_flushed():
  148.             self.connection.shutdown(1)
  149.  
  150. class HTTPHandler:
  151.     def __init__(self, getfunc, minflush):
  152.         self.connections = {}
  153.         self.getfunc = getfunc
  154.         self.minflush = minflush
  155.         self.lastflush = time.time()
  156.  
  157.     def external_connection_made(self, connection):
  158.         self.connections[connection] = HTTPConnection(self, connection)
  159.  
  160.     def connection_flushed(self, connection):
  161.         if self.connections[connection].done:
  162.             connection.shutdown(1)
  163.  
  164.     def connection_lost(self, connection):
  165.         ec = self.connections[connection]
  166.         ec.closed = True
  167.         del ec.connection
  168.         del ec.next_func
  169.         del self.connections[connection]
  170.  
  171.     def data_came_in(self, connection, data):
  172.         c = self.connections[connection]
  173.         if not c.data_came_in(data) and not c.closed:
  174.             c.connection.shutdown(1)
  175.  
  176.