home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / iria107a.lzh / script / httplib.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2000-11-17  |  28.1 KB  |  739 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.0)
  3.  
  4. '''HTTP/1.1 client library
  5.  
  6. <intro stuff goes here>
  7. <other stuff, too>
  8.  
  9. HTTPConnection go through a number of "states", which defines when a client
  10. may legally make another request or fetch the response for a particular
  11. request. This diagram details these state transitions:
  12.  
  13.     (null)
  14.       |
  15.       | HTTPConnection()
  16.       v
  17.     Idle
  18.       |
  19.       | putrequest()
  20.       v
  21.     Request-started
  22.       |
  23.       | ( putheader() )*  endheaders()
  24.       v
  25.     Request-sent
  26.       |
  27.       | response = getresponse()
  28.       v
  29.     Unread-response   [Response-headers-read]
  30.       |\\____________________
  31.       |                           | response.read()      | putrequest()
  32.       v                      v
  33.     Idle                   Req-started-unread-response
  34.                      _______/|
  35.                     /        |
  36.    response.read() |         | ( putheader() )*  endheaders()
  37.                    v         v
  38.        Request-started     Req-sent-unread-response
  39.                              |
  40.                              | response.read()
  41.                              v
  42.                            Request-sent
  43.  
  44. This diagram presents the following rules:
  45.   -- a second request may not be started until {response-headers-read}
  46.   -- a response [object] cannot be retrieved until {request-sent}
  47.   -- there is no differentiation between an unread response body and a
  48.      partially read response body
  49.  
  50. Note: this enforcement is applied by the HTTPConnection class. The
  51.       HTTPResponse class does not enforce this state machine, which
  52.       implies sophisticated clients may accelerate the request/response
  53.       pipeline. Caution should be taken, though: accelerating the states
  54.       beyond the above pattern may imply knowledge of the server\'s
  55.       connection-close behavior for certain requests. For example, it
  56.       is impossible to tell whether the server will close the connection
  57.       UNTIL the response headers have been read; this means that further
  58.       requests cannot be placed into the pipeline until it is known that
  59.       the server will NOT be closing the connection.
  60.  
  61. Logical State                  __state            __response
  62. -------------                  -------            ----------
  63. Idle                           _CS_IDLE           None
  64. Request-started                _CS_REQ_STARTED    None
  65. Request-sent                   _CS_REQ_SENT       None
  66. Unread-response                _CS_IDLE           <response_class>
  67. Req-started-unread-response    _CS_REQ_STARTED    <response_class>
  68. Req-sent-unread-response       _CS_REQ_SENT       <response_class>
  69. '''
  70. import socket
  71. import string
  72. import mimetools
  73.  
  74. try:
  75.     from cStringIO import StringIO
  76. except ImportError:
  77.     from StringIO import StringIO
  78.  
  79. HTTP_PORT = 80
  80. HTTPS_PORT = 443
  81. _UNKNOWN = 'UNKNOWN'
  82. _CS_IDLE = 'Idle'
  83. _CS_REQ_STARTED = 'Request-started'
  84. _CS_REQ_SENT = 'Request-sent'
  85.  
  86. class HTTPResponse:
  87.     
  88.     def __init__(self, sock, debuglevel = 0):
  89.         self.fp = sock.makefile('rb', 0)
  90.         self.debuglevel = debuglevel
  91.         self.msg = None
  92.         self.version = _UNKNOWN
  93.         self.status = _UNKNOWN
  94.         self.reason = _UNKNOWN
  95.         self.chunked = _UNKNOWN
  96.         self.chunk_left = _UNKNOWN
  97.         self.length = _UNKNOWN
  98.         self.will_close = _UNKNOWN
  99.  
  100.     
  101.     def begin(self):
  102.         if self.msg is not None:
  103.             return None
  104.         
  105.         line = self.fp.readline()
  106.         if self.debuglevel > 0:
  107.             print 'reply:', repr(line)
  108.         
  109.         
  110.         try:
  111.             (version, status, reason) = string.split(line, None, 2)
  112.         except ValueError:
  113.             
  114.             try:
  115.                 (version, status) = string.split(line, None, 1)
  116.                 reason = ''
  117.             except ValueError:
  118.                 version = 'HTTP/0.9'
  119.                 status = '200'
  120.                 reason = ''
  121.  
  122.  
  123.         if version[:5] != 'HTTP/':
  124.             self.close()
  125.             raise BadStatusLine(line)
  126.         
  127.         self.status = status = int(status)
  128.         self.reason = string.strip(reason)
  129.         if version == 'HTTP/1.0':
  130.             self.version = 10
  131.         elif version.startswith('HTTP/1.'):
  132.             self.version = 11
  133.         elif version == 'HTTP/0.9':
  134.             self.version = 9
  135.         else:
  136.             raise UnknownProtocol(version)
  137.         if self.version == 9:
  138.             self.msg = mimetools.Message(StringIO())
  139.             return None
  140.         
  141.         self.msg = mimetools.Message(self.fp, 0)
  142.         self.msg.fp = None
  143.         tr_enc = self.msg.getheader('transfer-encoding')
  144.         conn = self.msg.getheader('connection')
  145.         if conn:
  146.             conn = string.lower(conn)
  147.             if string.find(conn, 'close') != -1 and self.version != 11:
  148.                 pass
  149.             self.will_close = not self.msg.getheader('keep-alive')
  150.         elif self.version != 11:
  151.             pass
  152.         self.will_close = not self.msg.getheader('keep-alive')
  153.         length = self.msg.getheader('content-length')
  154.         if length and not (self.chunked):
  155.             
  156.             try:
  157.                 self.length = int(length)
  158.             except ValueError:
  159.                 self.length = None
  160.  
  161.         else:
  162.             self.length = None
  163.         if not status == 204 and status == 304:
  164.             if status <= status:
  165.                 pass
  166.             elif status < 200:
  167.                 self.length = 0
  168.             
  169.         if not (self.will_close) and not (self.chunked) and self.length is None:
  170.             self.will_close = 1
  171.         
  172.  
  173.     
  174.     def close(self):
  175.         if self.fp:
  176.             self.fp.close()
  177.             self.fp = None
  178.         
  179.  
  180.     
  181.     def isclosed(self):
  182.         return self.fp is None
  183.  
  184.     
  185.     def read(self, amt = None):
  186.         if self.fp is None:
  187.             return ''
  188.         
  189.         if self.chunked:
  190.             chunk_left = self.chunk_left
  191.             value = ''
  192.             while 1:
  193.                 if chunk_left is None:
  194.                     line = self.fp.readline()
  195.                     i = string.find(line, ';')
  196.                     if i >= 0:
  197.                         line = line[:i]
  198.                     
  199.                     chunk_left = string.atoi(line, 16)
  200.                     if chunk_left == 0:
  201.                         break
  202.                     
  203.                 
  204.                 if amt is None:
  205.                     value = value + self._safe_read(chunk_left)
  206.                 elif amt < chunk_left:
  207.                     value = value + self._safe_read(amt)
  208.                     self.chunk_left = chunk_left - amt
  209.                     return value
  210.                 elif amt == chunk_left:
  211.                     value = value + self._safe_read(amt)
  212.                     self._safe_read(2)
  213.                     self.chunk_left = None
  214.                     return value
  215.                 else:
  216.                     value = value + self._safe_read(chunk_left)
  217.                     amt = amt - chunk_left
  218.                 self._safe_read(2)
  219.                 chunk_left = None
  220.             while 1:
  221.                 line = self.fp.readline()
  222.                 if line == '\r\n':
  223.                     break
  224.                 
  225.             self.close()
  226.             return value
  227.         elif amt is None:
  228.             if self.will_close:
  229.                 s = self.fp.read()
  230.             else:
  231.                 s = self._safe_read(self.length)
  232.             self.close()
  233.             return s
  234.         
  235.         if self.length is not None:
  236.             if amt > self.length:
  237.                 amt = self.length
  238.             
  239.             self.length = self.length - amt
  240.         
  241.         s = self.fp.read(amt)
  242.         return s
  243.  
  244.     
  245.     def _safe_read(self, amt):
  246.         '''Read the number of bytes requested, compensating for partial reads.
  247.  
  248.         Normally, we have a blocking socket, but a read() can be interrupted
  249.         by a signal (resulting in a partial read).
  250.  
  251.         Note that we cannot distinguish between EOF and an interrupt when zero
  252.         bytes have been read. IncompleteRead() will be raised in this
  253.         situation.
  254.  
  255.         This function should be used when <amt> bytes "should" be present for
  256.         reading. If the bytes are truly not available (due to EOF), then the
  257.         IncompleteRead exception can be used to detect the problem.
  258.         '''
  259.         s = ''
  260.         while amt > 0:
  261.             chunk = self.fp.read(amt)
  262.             if not chunk:
  263.                 raise IncompleteRead(s)
  264.             
  265.             s = s + chunk
  266.             amt = amt - len(chunk)
  267.         return s
  268.  
  269.     
  270.     def getheader(self, name, default = None):
  271.         if self.msg is None:
  272.             raise ResponseNotReady()
  273.         
  274.         return self.msg.getheader(name, default)
  275.  
  276.  
  277.  
  278. class HTTPConnection:
  279.     _http_vsn = 11
  280.     _http_vsn_str = 'HTTP/1.1'
  281.     response_class = HTTPResponse
  282.     default_port = HTTP_PORT
  283.     auto_open = 1
  284.     debuglevel = 0
  285.     
  286.     def __init__(self, host, port = None):
  287.         self.sock = None
  288.         self._HTTPConnection__response = None
  289.         self._HTTPConnection__state = _CS_IDLE
  290.         self._set_hostport(host, port)
  291.  
  292.     
  293.     def _set_hostport(self, host, port):
  294.         if port is None:
  295.             i = string.find(host, ':')
  296.             if i >= 0:
  297.                 port = int(host[i + 1:])
  298.                 host = host[:i]
  299.             else:
  300.                 port = self.default_port
  301.         
  302.         self.host = host
  303.         self.port = port
  304.  
  305.     
  306.     def set_debuglevel(self, level):
  307.         self.debuglevel = level
  308.  
  309.     
  310.     def connect(self):
  311.         '''Connect to the host and port specified in __init__.'''
  312.         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  313.         if self.debuglevel > 0:
  314.             print 'connect: (%s, %s)' % (self.host, self.port)
  315.         
  316.         self.sock.connect((self.host, self.port))
  317.  
  318.     
  319.     def close(self):
  320.         '''Close the connection to the HTTP server.'''
  321.         if self.sock:
  322.             self.sock.close()
  323.             self.sock = None
  324.         
  325.         if self._HTTPConnection__response:
  326.             self._HTTPConnection__response.close()
  327.             self._HTTPConnection__response = None
  328.         
  329.         self._HTTPConnection__state = _CS_IDLE
  330.  
  331.     
  332.     def send(self, str):
  333.         """Send `str' to the server."""
  334.         if self.sock is None:
  335.             if self.auto_open:
  336.                 self.connect()
  337.             else:
  338.                 raise NotConnected()
  339.         
  340.         if self.debuglevel > 0:
  341.             print 'send:', repr(str)
  342.         
  343.         
  344.         try:
  345.             self.sock.send(str)
  346.         except socket.error:
  347.             v = None
  348.             if v[0] == 32:
  349.                 self.close()
  350.             
  351.             raise 
  352.  
  353.  
  354.     
  355.     def putrequest(self, method, url):
  356.         """Send a request to the server.
  357.  
  358.         `method' specifies an HTTP request method, e.g. 'GET'.
  359.         `url' specifies the object being requested, e.g. '/index.html'.
  360.         """
  361.         if self._HTTPConnection__response and self._HTTPConnection__response.isclosed():
  362.             self._HTTPConnection__response = None
  363.         
  364.         if self._HTTPConnection__state == _CS_IDLE:
  365.             self._HTTPConnection__state = _CS_REQ_STARTED
  366.         else:
  367.             raise CannotSendRequest()
  368.         if not url:
  369.             url = '/'
  370.         
  371.         str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
  372.         
  373.         try:
  374.             self.send(str)
  375.         except socket.error:
  376.             v = None
  377.             if v[0] != 32 or not (self.auto_open):
  378.                 raise 
  379.             
  380.             self.send(str)
  381.  
  382.         if self._http_vsn == 11:
  383.             self.putheader('Host', self.host)
  384.             self.putheader('Accept-Encoding', 'identity')
  385.         
  386.  
  387.     
  388.     def putheader(self, header, value):
  389.         """Send a request header line to the server.
  390.  
  391.         For example: h.putheader('Accept', 'text/html')
  392.         """
  393.         if self._HTTPConnection__state != _CS_REQ_STARTED:
  394.             raise CannotSendHeader()
  395.         
  396.         str = '%s: %s\r\n' % (header, value)
  397.         self.send(str)
  398.  
  399.     
  400.     def endheaders(self):
  401.         '''Indicate that the last header line has been sent to the server.'''
  402.         if self._HTTPConnection__state == _CS_REQ_STARTED:
  403.             self._HTTPConnection__state = _CS_REQ_SENT
  404.         else:
  405.             raise CannotSendHeader()
  406.         self.send('\r\n')
  407.  
  408.     
  409.     def request(self, method, url, body = None, headers = { }):
  410.         '''Send a complete request to the server.'''
  411.         
  412.         try:
  413.             self._send_request(method, url, body, headers)
  414.         except socket.error:
  415.             v = None
  416.             if v[0] != 32 or not (self.auto_open):
  417.                 raise 
  418.             
  419.             self._send_request(method, url, body, headers)
  420.  
  421.  
  422.     
  423.     def _send_request(self, method, url, body, headers):
  424.         self.putrequest(method, url)
  425.         if body:
  426.             self.putheader('Content-Length', str(len(body)))
  427.         
  428.         for hdr, value in headers.items():
  429.             self.putheader(hdr, value)
  430.         
  431.         self.endheaders()
  432.  
  433.     
  434.     def getresponse(self):
  435.         '''Get the response from the server.'''
  436.         if self._HTTPConnection__response and self._HTTPConnection__response.isclosed():
  437.             self._HTTPConnection__response = None
  438.         
  439.         if self._HTTPConnection__state != _CS_REQ_SENT or self._HTTPConnection__response:
  440.             raise ResponseNotReady()
  441.         
  442.         if self.debuglevel > 0:
  443.             response = self.response_class(self.sock, self.debuglevel)
  444.         else:
  445.             response = self.response_class(self.sock)
  446.         response.begin()
  447.         self._HTTPConnection__state = _CS_IDLE
  448.         if response.will_close:
  449.             self.close()
  450.         else:
  451.             self._HTTPConnection__response = response
  452.         return response
  453.  
  454.  
  455.  
  456. class FakeSocket:
  457.     
  458.     def __init__(self, sock, ssl):
  459.         self._FakeSocket__sock = sock
  460.         self._FakeSocket__ssl = ssl
  461.  
  462.     
  463.     def makefile(self, mode, bufsize = None):
  464.         """Return a readable file-like object with data from socket.
  465.  
  466.         This method offers only partial support for the makefile
  467.         interface of a real socket.  It only supports modes 'r' and
  468.         'rb' and the bufsize argument is ignored.
  469.  
  470.         The returned object contains *all* of the file data 
  471.         """
  472.         if mode != 'r' and mode != 'rb':
  473.             raise UnimplementedFileMode()
  474.         
  475.         msgbuf = ''
  476.         while 1:
  477.             
  478.             try:
  479.                 msgbuf = msgbuf + self._FakeSocket__ssl.read()
  480.             except socket.sslerror:
  481.                 msg = None
  482.                 break
  483.  
  484.         return StringIO(msgbuf)
  485.  
  486.     
  487.     def send(self, stuff, flags = 0):
  488.         return self._FakeSocket__ssl.write(stuff)
  489.  
  490.     
  491.     def recv(self, len = 1024, flags = 0):
  492.         return self._FakeSocket__ssl.read(len)
  493.  
  494.     
  495.     def __getattr__(self, attr):
  496.         return getattr(self._FakeSocket__sock, attr)
  497.  
  498.  
  499.  
  500. class HTTPSConnection(HTTPConnection):
  501.     '''This class allows communication via SSL.'''
  502.     default_port = HTTPS_PORT
  503.     
  504.     def __init__(self, host, port = None, **x509):
  505.         keys = x509.keys()
  506.         
  507.         try:
  508.             keys.remove('key_file')
  509.         except ValueError:
  510.             pass
  511.  
  512.         
  513.         try:
  514.             keys.remove('cert_file')
  515.         except ValueError:
  516.             pass
  517.  
  518.         if keys:
  519.             raise IllegalKeywordArgument()
  520.         
  521.         HTTPConnection.__init__(self, host, port)
  522.         self.key_file = x509.get('key_file')
  523.         self.cert_file = x509.get('cert_file')
  524.  
  525.     
  526.     def connect(self):
  527.         '''Connect to a host on a given (SSL) port.'''
  528.         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  529.         sock.connect((self.host, self.port))
  530.         ssl = socket.ssl(sock, self.key_file, self.cert_file)
  531.         self.sock = FakeSocket(sock, ssl)
  532.  
  533.  
  534.  
  535. class HTTP:
  536.     '''Compatibility class with httplib.py from 1.5.'''
  537.     _http_vsn = 10
  538.     _http_vsn_str = 'HTTP/1.0'
  539.     debuglevel = 0
  540.     _connection_class = HTTPConnection
  541.     
  542.     def __init__(self, host = '', port = None, **x509):
  543.         '''Provide a default host, since the superclass requires one.'''
  544.         if port == 0:
  545.             port = None
  546.         
  547.         self._conn = self._connection_class(host, port)
  548.         self.send = self._conn.send
  549.         self.putrequest = self._conn.putrequest
  550.         self.endheaders = self._conn.endheaders
  551.         self._conn._http_vsn = self._http_vsn
  552.         self._conn._http_vsn_str = self._http_vsn_str
  553.         self.key_file = x509.get('key_file')
  554.         self.cert_file = x509.get('cert_file')
  555.         self.file = None
  556.  
  557.     
  558.     def connect(self, host = None, port = None):
  559.         """Accept arguments to set the host/port, since the superclass doesn't."""
  560.         if host is not None:
  561.             self._conn._set_hostport(host, port)
  562.         
  563.         self._conn.connect()
  564.  
  565.     
  566.     def set_debuglevel(self, debuglevel):
  567.         self._conn.set_debuglevel(debuglevel)
  568.  
  569.     
  570.     def getfile(self):
  571.         """Provide a getfile, since the superclass' does not use this concept."""
  572.         return self.file
  573.  
  574.     
  575.     def putheader(self, header, *values):
  576.         '''The superclass allows only one value argument.'''
  577.         self._conn.putheader(header, string.joinfields(values, '\r\n\t'))
  578.  
  579.     
  580.     def getreply(self):
  581.         '''Compat definition since superclass does not define it.
  582.  
  583.         Returns a tuple consisting of:
  584.         - server status code (e.g. \'200\' if all goes well)
  585.         - server "reason" corresponding to status code
  586.         - any RFC822 headers in the response from the server
  587.         '''
  588.         
  589.         try:
  590.             response = self._conn.getresponse()
  591.         except BadStatusLine:
  592.             e = None
  593.             self.file = self._conn.sock.makefile('rb', 0)
  594.             self.close()
  595.             self.headers = None
  596.             return (-1, e.line, None)
  597.  
  598.         self.headers = response.msg
  599.         self.file = response.fp
  600.         return (response.status, response.reason, response.msg)
  601.  
  602.     
  603.     def close(self):
  604.         self._conn.close()
  605.         self.file = None
  606.  
  607.  
  608. if hasattr(socket, 'ssl'):
  609.     
  610.     class HTTPS(HTTP):
  611.         '''Compatibility with 1.5 httplib interface
  612.  
  613.         Python 1.5.2 did not have an HTTPS class, but it defined an
  614.         interface for sending http requests that is also useful for
  615.         https. 
  616.         '''
  617.         _connection_class = HTTPSConnection
  618.  
  619.  
  620.  
  621. class HTTPException(Exception):
  622.     pass
  623.  
  624.  
  625. class NotConnected(HTTPException):
  626.     pass
  627.  
  628.  
  629. class UnknownProtocol(HTTPException):
  630.     
  631.     def __init__(self, version):
  632.         self.version = version
  633.  
  634.  
  635.  
  636. class UnknownTransferEncoding(HTTPException):
  637.     pass
  638.  
  639.  
  640. class IllegalKeywordArgument(HTTPException):
  641.     pass
  642.  
  643.  
  644. class UnimplementedFileMode(HTTPException):
  645.     pass
  646.  
  647.  
  648. class IncompleteRead(HTTPException):
  649.     
  650.     def __init__(self, partial):
  651.         self.partial = partial
  652.  
  653.  
  654.  
  655. class ImproperConnectionState(HTTPException):
  656.     pass
  657.  
  658.  
  659. class CannotSendRequest(ImproperConnectionState):
  660.     pass
  661.  
  662.  
  663. class CannotSendHeader(ImproperConnectionState):
  664.     pass
  665.  
  666.  
  667. class ResponseNotReady(ImproperConnectionState):
  668.     pass
  669.  
  670.  
  671. class BadStatusLine(HTTPException):
  672.     
  673.     def __init__(self, line):
  674.         self.line = line
  675.  
  676.  
  677. error = HTTPException
  678.  
  679. def test():
  680.     '''Test this module.
  681.  
  682.     The test consists of retrieving and displaying the Python
  683.     home page, along with the error code and error string returned
  684.     by the www.python.org server.
  685.     '''
  686.     import sys
  687.     import getopt
  688.     (opts, args) = getopt.getopt(sys.argv[1:], 'd')
  689.     dl = 0
  690.     for o, a in opts:
  691.         pass
  692.     
  693.     host = 'www.python.org'
  694.     selector = '/'
  695.     if args[0:]:
  696.         host = args[0]
  697.     
  698.     if args[1:]:
  699.         selector = args[1]
  700.     
  701.     h = HTTP()
  702.     h.set_debuglevel(dl)
  703.     h.connect(host)
  704.     h.putrequest('GET', selector)
  705.     h.endheaders()
  706.     (status, reason, headers) = h.getreply()
  707.     print 'status =', status
  708.     print 'reason =', reason
  709.     print 
  710.     if headers:
  711.         for header in headers.headers:
  712.             print string.strip(header)
  713.         
  714.     
  715.     print 
  716.     print h.getfile().read()
  717.     if hasattr(socket, 'ssl'):
  718.         host = 'sourceforge.net'
  719.         hs = HTTPS()
  720.         hs.connect(host)
  721.         hs.putrequest('GET', selector)
  722.         hs.endheaders()
  723.         (status, reason, headers) = hs.getreply()
  724.         print 'status =', status
  725.         print 'reason =', reason
  726.         print 
  727.         if headers:
  728.             for header in headers.headers:
  729.                 print string.strip(header)
  730.             
  731.         
  732.         print 
  733.         print hs.getfile().read()
  734.     
  735.  
  736. if __name__ == '__main__':
  737.     test()
  738.  
  739.