http 1.1 客户端类库

http://svn.python.org/projects/python/trunk/Lib/httplib.py

None.gif """ HTTP/1.1 client library
None.gif

None.gif
< intro stuff goes here >
None.gif
< other stuff, too >
None.gif
None.gifHTTPConnection goes through a number of 
" states " , which define when a client
None.gifmay legally make another request or fetch the response 
for  a particular
None.gifrequest. This diagram details these state transitions:
None.gif
None.gif    (
null )
None.gif      
|
None.gif      
|  HTTPConnection()
None.gif      v
None.gif    Idle
None.gif      
|
None.gif      
|  putrequest()
None.gif      v
None.gif    Request
- started
None.gif      
|
None.gif      
|  ( putheader() ) *   endheaders()
None.gif      v
None.gif    Request
- sent
None.gif      
|
None.gif      
|  response  =  getresponse()
None.gif      v
None.gif    Unread
- response   [Response - headers - read]
None.gif      
| \____________________
None.gif      
|                       |
None.gif      
|  response.read()      |  putrequest()
None.gif      v                     v
None.gif    Idle                  Req
- started - unread - response
None.gif                     ______
/|
None.gif                   
/          |
None.gif   response.read() 
|          |  ( putheader() ) *   endheaders()
None.gif                   v        v
None.gif       Request
- started    Req - sent - unread - response
None.gif                            
|
None.gif                            
|  response.read()
None.gif                            v
None.gif                          Request
- sent
None.gif
None.gifThis diagram presents the following rules:
ExpandedBlockStart.gifContractedBlock.gif  
--  a second request may not be started until  dot.gif {response-headers-read}
ExpandedBlockStart.gifContractedBlock.gif  
--  a response [ object ] cannot be retrieved until  dot.gif {request-sent}
None.gif  
--  there  is  no differentiation between an unread response body and a
None.gif     partially read response body
None.gif
None.gifNote: 
this  enforcement  is  applied by the HTTPConnection  class . The
None.gif      HTTPResponse 
class  does not enforce  this  state machine, which
None.gif      implies sophisticated clients may accelerate the request
/ response
None.gif      pipeline. Caution should be taken, though: accelerating the states
None.gif      beyond the above pattern may imply knowledge of the server
' s
None.gif
      connection - close behavior  for  certain requests. For example, it
None.gif      
is  impossible to tell whether the server will close the connection
None.gif      UNTIL the response headers have been read; 
this  means that further
None.gif      requests cannot be placed into the pipeline until it 
is  known that
None.gif      the server will NOT be closing the connection.
None.gif
None.gifLogical State                  __state            __response
None.gif
-------------                    -------              ----------
None.gifIdle                           _CS_IDLE           None
None.gifRequest
- started                _CS_REQ_STARTED    None
None.gifRequest
- sent                   _CS_REQ_SENT       None
None.gifUnread
- response                _CS_IDLE            < response_class >
None.gifReq
- started - unread - response    _CS_REQ_STARTED     < response_class >
None.gifReq
- sent - unread - response       _CS_REQ_SENT        < response_class >
None.gif
"""
None.gif

None.gifimport errno
None.gifimport mimetools
None.gifimport socket
None.giffrom urlparse import urlsplit
None.gif
None.gif
try :
None.gif    from cStringIO import StringIO
None.gifexcept ImportError:
None.gif    from StringIO import StringIO
None.gif
None.gif__all__ 
=  [ " HTTP " " HTTPResponse " " HTTPConnection " " HTTPSConnection " ,
None.gif           
" HTTPException " " NotConnected " " UnknownProtocol " ,
None.gif           
" UnknownTransferEncoding " " UnimplementedFileMode " ,
None.gif           
" IncompleteRead " " InvalidURL " " ImproperConnectionState " ,
None.gif           
" CannotSendRequest " " CannotSendHeader " " ResponseNotReady " ,
None.gif           
" BadStatusLine " " error " " responses " ]
None.gif
None.gifHTTP_PORT 
=   80
None.gifHTTPS_PORT 
=   443
None.gif
None.gif_UNKNOWN 
=   ' UNKNOWN '
None.gif
None.gif# connection states
None.gif_CS_IDLE 
=   ' Idle '
None.gif_CS_REQ_STARTED 
=   ' Request-started '
None.gif_CS_REQ_SENT 
=   ' Request-sent '
None.gif
None.gif# status codes
None.gif# informational
None.gifCONTINUE 
=   100
None.gifSWITCHING_PROTOCOLS 
=   101
None.gifPROCESSING 
=   102
None.gif
None.gif# successful
None.gifOK 
=   200
None.gifCREATED 
=   201
None.gifACCEPTED 
=   202
None.gifNON_AUTHORITATIVE_INFORMATION 
=   203
None.gifNO_CONTENT 
=   204
None.gifRESET_CONTENT 
=   205
None.gifPARTIAL_CONTENT 
=   206
None.gifMULTI_STATUS 
=   207
None.gifIM_USED 
=   226
None.gif
None.gif# redirection
None.gifMULTIPLE_CHOICES 
=   300
None.gifMOVED_PERMANENTLY 
=   301
None.gifFOUND 
=   302
None.gifSEE_OTHER 
=   303
None.gifNOT_MODIFIED 
=   304
None.gifUSE_PROXY 
=   305
None.gifTEMPORARY_REDIRECT 
=   307
None.gif
None.gif# client error
None.gifBAD_REQUEST 
=   400
None.gifUNAUTHORIZED 
=   401
None.gifPAYMENT_REQUIRED 
=   402
None.gifFORBIDDEN 
=   403
None.gifNOT_FOUND 
=   404
None.gifMETHOD_NOT_ALLOWED 
=   405
None.gifNOT_ACCEPTABLE 
=   406
None.gifPROXY_AUTHENTICATION_REQUIRED 
=   407
None.gifREQUEST_TIMEOUT 
=   408
None.gifCONFLICT 
=   409
None.gifGONE 
=   410
None.gifLENGTH_REQUIRED 
=   411
None.gifPRECONDITION_FAILED 
=   412
None.gifREQUEST_ENTITY_TOO_LARGE 
=   413
None.gifREQUEST_URI_TOO_LONG 
=   414
None.gifUNSUPPORTED_MEDIA_TYPE 
=   415
None.gifREQUESTED_RANGE_NOT_SATISFIABLE 
=   416
None.gifEXPECTATION_FAILED 
=   417
None.gifUNPROCESSABLE_ENTITY 
=   422
None.gifLOCKED 
=   423
None.gifFAILED_DEPENDENCY 
=   424
None.gifUPGRADE_REQUIRED 
=   426
None.gif
None.gif# server error
None.gifINTERNAL_SERVER_ERROR 
=   500
None.gifNOT_IMPLEMENTED 
=   501
None.gifBAD_GATEWAY 
=   502
None.gifSERVICE_UNAVAILABLE 
=   503
None.gifGATEWAY_TIMEOUT 
=   504
None.gifHTTP_VERSION_NOT_SUPPORTED 
=   505
None.gifINSUFFICIENT_STORAGE 
=   507
None.gifNOT_EXTENDED 
=   510
None.gif
None.gif# Mapping status codes to official W3C names
ExpandedBlockStart.gifContractedBlock.gifresponses 
=   dot.gif {
InBlock.gif    
100'Continue',
InBlock.gif    
101'Switching Protocols',
InBlock.gif
InBlock.gif    
200'OK',
InBlock.gif    
201'Created',
InBlock.gif    
202'Accepted',
InBlock.gif    
203'Non-Authoritative Information',
InBlock.gif    
204'No Content',
InBlock.gif    
205'Reset Content',
InBlock.gif    
206'Partial Content',
InBlock.gif
InBlock.gif    
300'Multiple Choices',
InBlock.gif    
301'Moved Permanently',
InBlock.gif    
302'Found',
InBlock.gif    
303'See Other',
InBlock.gif    
304'Not Modified',
InBlock.gif    
305'Use Proxy',
InBlock.gif    
306'(Unused)',
InBlock.gif    
307'Temporary Redirect',
InBlock.gif
InBlock.gif    
400'Bad Request',
InBlock.gif    
401'Unauthorized',
InBlock.gif    
402'Payment Required',
InBlock.gif    
403'Forbidden',
InBlock.gif    
404'Not Found',
InBlock.gif    
405'Method Not Allowed',
InBlock.gif    
406'Not Acceptable',
InBlock.gif    
407'Proxy Authentication Required',
InBlock.gif    
408'Request Timeout',
InBlock.gif    
409'Conflict',
InBlock.gif    
410'Gone',
InBlock.gif    
411'Length Required',
InBlock.gif    
412'Precondition Failed',
InBlock.gif    
413'Request Entity Too Large',
InBlock.gif    
414'Request-URI Too Long',
InBlock.gif    
415'Unsupported Media Type',
InBlock.gif    
416'Requested Range Not Satisfiable',
InBlock.gif    
417'Expectation Failed',
InBlock.gif
InBlock.gif    
500'Internal Server Error',
InBlock.gif    
501'Not Implemented',
InBlock.gif    
502'Bad Gateway',
InBlock.gif    
503'Service Unavailable',
InBlock.gif    
504'Gateway Timeout',
InBlock.gif    
505'HTTP Version Not Supported',
ExpandedBlockEnd.gif}

None.gif
None.gif# maximal amount of data to read at one time 
in  _safe_read
None.gifMAXAMOUNT 
=   1048576
None.gif
None.gif
class  HTTPMessage(mimetools.Message):
None.gif
None.gif    def addheader(self, key, value):
None.gif        
""" Add header for field key handling repeats. """
None.gif        prev 
=  self.dict. get (key)
None.gif        
if  prev  is  None:
None.gif            self.dict[key] 
=  value
None.gif        
else :
None.gif            combined 
=   " " .join((prev, value))
None.gif            self.dict[key] 
=  combined
None.gif
None.gif    def addcontinue(self, key, more):
None.gif        
""" Add more field data from a continuation line. """
None.gif        prev 
=  self.dict[key]
None.gif        self.dict[key] 
=  prev  +   " \n  "   +  more
None.gif
None.gif    def readheaders(self):
None.gif        
""" Read header lines.
None.gif

None.gif        Read header lines up to the entirely blank line that terminates them.
None.gif        The (normally blank) line that ends the headers 
is  skipped, but not
None.gif        included 
in  the returned list.  If a non - header line ends the headers,
None.gif        (which 
is  an error), an attempt  is  made to backspace over it; it  is
None.gif        never included 
in  the returned list.
None.gif
None.gif        The variable self.status 
is   set  to the empty  string   if  all went well,
None.gif        otherwise it 
is  an error message.  The variable self.headers  is  a
None.gif        completely uninterpreted list of lines contained 
in  the header (so
None.gif        printing them will reproduce the header exactly 
as  it appears  in  the
None.gif        file).
None.gif
None.gif        If multiple header fields with the same name occur, they are combined
None.gif        according to the rules 
in  RFC  2616  sec  4.2 :
None.gif
None.gif        Appending each subsequent field
- value to the first, each separated
None.gif        by a comma. The order 
in  which header fields with the same field - name
None.gif        are received 
is  significant to the interpretation of the combined
None.gif        field value.
None.gif        
"""
None.gif
        # XXX The implementation overrides the readheaders() method of
None.gif        # rfc822.Message.  The 
base   class  design isn ' t amenable to
None.gif
        # customized behavior here so the method here  is  a copy of the
None.gif        # 
base   class  code with a few small changes.
None.gif
ExpandedBlockStart.gifContractedBlock.gif        self.dict 
=   dot.gif {}
None.gif        self.unixfrom 
=   ''
None.gif        self.headers 
=  hlist  =  []
None.gif        self.status 
=   ''
None.gif        headerseen 
=   ""
None.gif        firstline 
=   1
None.gif        startofline 
=  unread  =  tell  =  None
None.gif        
if  hasattr(self.fp,  ' unread ' ):
None.gif            unread 
=  self.fp.unread
None.gif        elif self.seekable:
None.gif            tell 
=  self.fp.tell
None.gif        
while  True:
None.gif            
if  tell:
None.gif                
try :
None.gif                    startofline 
=  tell()
None.gif                except IOError:
None.gif                    startofline 
=  tell  =  None
None.gif                    self.seekable 
=   0
None.gif            line 
=  self.fp.readline()
None.gif            
if  not line:
None.gif                self.status 
=   ' EOF in headers '
None.gif                
break
None.gif            # Skip unix From name time lines
None.gif            
if  firstline and line.startswith( ' From  ' ):
None.gif                self.unixfrom 
=  self.unixfrom  +  line
None.gif                
continue
None.gif            firstline 
=   0
None.gif            
if  headerseen and line[ 0 in   '  \t ' :
None.gif                # XXX Not sure 
if  continuation lines are handled properly
None.gif                # 
for  http and / or  for  repeating headers
None.gif                # It
' s a continuation line.
None.gif
                hlist.append(line)
None.gif                self.addcontinue(headerseen, line.strip())
None.gif                
continue
None.gif            elif self.iscomment(line):
None.gif                # It
' s a comment.  Ignore it.
None.gif
                 continue
None.gif            elif self.islast(line):
None.gif                # Note
!  No pushback here !   The delimiter line gets eaten.
None.gif                
break
None.gif            headerseen 
=  self.isheader(line)
None.gif            
if  headerseen:
None.gif                # It
' s a legal header line, save it.
None.gif
                hlist.append(line)
None.gif                self.addheader(headerseen, line[len(headerseen)
+ 1 :].strip())
None.gif                
continue
None.gif            
else :
None.gif                # It
' s not a header line; throw it back and stop here.
None.gif
                 if  not self.dict:
None.gif                    self.status 
=   ' No headers '
None.gif                
else :
None.gif                    self.status 
=   ' Non-header line where header expected '
None.gif                # Try to undo the read.
None.gif                
if  unread:
None.gif                    unread(line)
None.gif                elif tell:
None.gif                    self.fp.seek(startofline)
None.gif                
else :
None.gif                    self.status 
=  self.status  +   ' ; bad seek '
None.gif                
break
None.gif
None.gif
class  HTTPResponse:
None.gif
None.gif    # strict: If 
true , raise BadStatusLine  if  the status line can ' t be
None.gif
    # parsed  as  a valid HTTP / 1.0  or  1.1  status line.  By  default  it  is
None.gif    # 
false  because it prevents clients from talking to HTTP / 0.9
None.gif    # servers.  Note that a response with a sufficiently corrupted
None.gif    # status line will look like an HTTP
/ 0.9  response.
None.gif
None.gif    # See RFC 
2616  sec  19.6  and RFC  1945  sec  6   for  details.
None.gif
None.gif    def __init__(self, sock, debuglevel
= 0 , strict = 0 , method = None):
None.gif        self.fp 
=  sock.makefile( ' rb ' 0 )
None.gif        self.debuglevel 
=  debuglevel
None.gif        self.strict 
=  strict
None.gif        self._method 
=  method
None.gif
None.gif        self.msg 
=  None
None.gif
None.gif        # from the Status
- Line of the response
None.gif        self.version 
=  _UNKNOWN # HTTP - Version
None.gif        self.status 
=  _UNKNOWN  # Status - Code
None.gif        self.reason 
=  _UNKNOWN  # Reason - Phrase
None.gif
None.gif        self.chunked 
=  _UNKNOWN         #  is   " chunked "  being used ?
None.gif        self.chunk_left 
=  _UNKNOWN      # bytes left to read  in  current chunk
None.gif        self.length 
=  _UNKNOWN          # number of bytes left  in  response
None.gif        self.will_close 
=  _UNKNOWN      # conn will close at end of response
None.gif
None.gif    def _read_status(self):
None.gif        # Initialize with Simple
- Response defaults
None.gif        line 
=  self.fp.readline()
None.gif        
if  self.debuglevel  >   0 :
None.gif            print 
" reply: " , repr(line)
None.gif        
if  not line:
None.gif            # Presumably, the server closed the connection before
None.gif            # sending a valid response.
None.gif            raise BadStatusLine(line)
None.gif        
try :
None.gif            [version, status, reason] 
=  line.split(None,  2 )
None.gif        except ValueError:
None.gif            
try :
None.gif                [version, status] 
=  line.split(None,  1 )
None.gif                reason 
=   ""
None.gif            except ValueError:
None.gif                # empty version will cause next test to fail and status
None.gif                # will be treated 
as   0.9  response.
None.gif                version 
=   ""
None.gif        
if  not version.startswith( ' HTTP/ ' ):
None.gif            
if  self.strict:
None.gif                self.close()
None.gif                raise BadStatusLine(line)
None.gif            
else :
None.gif                # assume it
' s a Simple-Response from an 0.9 server
None.gif
                self.fp  =  LineAndFileWrapper(line, self.fp)
None.gif                
return   " HTTP/0.9 " 200 ""
None.gif
None.gif        # The status code 
is  a three - digit number
None.gif        
try :
None.gif            status 
=   int (status)
None.gif            
if  status  <   100  or status  >   999 :
None.gif                raise BadStatusLine(line)
None.gif        except ValueError:
None.gif            raise BadStatusLine(line)
None.gif        
return  version, status, reason
None.gif
None.gif    def begin(self):
None.gif        
if  self.msg  is  not None:
None.gif            # we
' ve already started reading the response
None.gif
             return
None.gif
None.gif        # read until we 
get  a non - 100  response
None.gif        
while  True:
None.gif            version, status, reason 
=  self._read_status()
None.gif            
if  status  !=  CONTINUE:
None.gif                
break
None.gif            # skip the header from the 
100  response
None.gif            
while  True:
None.gif                skip 
=  self.fp.readline().strip()
None.gif                
if  not skip:
None.gif                    
break
None.gif                
if  self.debuglevel  >   0 :
None.gif                    print 
" header: " , skip
None.gif
None.gif        self.status 
=  status
None.gif        self.reason 
=  reason.strip()
None.gif        
if  version  ==   ' HTTP/1.0 ' :
None.gif            self.version 
=   10
None.gif        elif version.startswith(
' HTTP/1. ' ):
None.gif            self.version 
=   11    # use HTTP / 1.1  code  for  HTTP / 1 .x where x >= 1
None.gif        elif version 
==   ' HTTP/0.9 ' :
None.gif            self.version 
=   9
None.gif        
else :
None.gif            raise UnknownProtocol(version)
None.gif
None.gif        
if  self.version  ==   9 :
None.gif            self.length 
=  None
None.gif            self.chunked 
=   0
None.gif            self.will_close 
=   1
None.gif            self.msg 
=  HTTPMessage(StringIO())
None.gif            
return
None.gif
None.gif        self.msg 
=  HTTPMessage(self.fp,  0 )
None.gif        
if  self.debuglevel  >   0 :
None.gif            
for  hdr  in  self.msg.headers:
None.gif                print 
" header: " , hdr,
None.gif
None.gif        # don
' t let the msg keep an fp
None.gif
        self.msg.fp  =  None
None.gif
None.gif        # are we 
using  the chunked - style of transfer encoding ?
None.gif        tr_enc 
=  self.msg.getheader( ' transfer-encoding ' )
None.gif        
if  tr_enc and tr_enc.lower()  ==   " chunked " :
None.gif            self.chunked 
=   1
None.gif            self.chunk_left 
=  None
None.gif        
else :
None.gif            self.chunked 
=   0
None.gif
None.gif        # will the connection close at the end of the response
?
None.gif        self.will_close 
=  self._check_close()
None.gif
None.gif        # 
do  we have a Content - Length ?
None.gif        # NOTE: RFC 
2616 , S4. 4 , # 3  says we ignore  this   if  tr_enc  is   " chunked "
None.gif        length 
=  self.msg.getheader( ' content-length ' )
None.gif        
if  length and not self.chunked:
None.gif            
try :
None.gif                self.length 
=   int (length)
None.gif            except ValueError:
None.gif                self.length 
=  None
None.gif        
else :
None.gif            self.length 
=  None
None.gif
None.gif        # does the body have a 
fixed  length ?  (of zero)
None.gif        
if  (status  ==  NO_CONTENT or status  ==  NOT_MODIFIED or
None.gif            
100   <=  status  <   200  or      # 1xx codes
None.gif            self._method 
==   ' HEAD ' ):
None.gif            self.length 
=   0
None.gif
None.gif        # 
if  the connection remains open, and we aren ' t using chunked, and
None.gif
        # a content - length was not provided, then assume that the connection
None.gif        # WILL close.
None.gif        
if  not self.will_close and \
None.gif           not self.chunked and \
None.gif           self.length 
is  None:
None.gif            self.will_close 
=   1
None.gif
None.gif    def _check_close(self):
None.gif        conn 
=  self.msg.getheader( ' connection ' )
None.gif        
if  self.version  ==   11 :
None.gif            # An HTTP
/ 1.1  proxy  is  assumed to stay open unless
None.gif            # explicitly closed.
None.gif            conn 
=  self.msg.getheader( ' connection ' )
None.gif            
if  conn and  " close "   in  conn.lower():
None.gif                
return  True
None.gif            
return  False
None.gif
None.gif        # Some HTTP
/ 1.0  implementations have support  for  persistent
None.gif        # connections, 
using  rules different than HTTP / 1.1 .
None.gif
None.gif        # For older HTTP, Keep
- Alive indiciates persistent connection.
None.gif        
if  self.msg.getheader( ' keep-alive ' ):
None.gif            
return  False
None.gif
None.gif        # At least Akamai returns a 
" Connection: Keep-Alive "  header,
None.gif        # which was supposed to be sent by the client.
None.gif        
if  conn and  " keep-alive "   in  conn.lower():
None.gif            
return  False
None.gif
None.gif        # Proxy
- Connection  is  a netscape hack.
None.gif        pconn 
=  self.msg.getheader( ' proxy-connection ' )
None.gif        
if  pconn and  " keep-alive "   in  pconn.lower():
None.gif            
return  False
None.gif
None.gif        # otherwise, assume it will close
None.gif        
return  True
None.gif
None.gif    def close(self):
None.gif        
if  self.fp:
None.gif            self.fp.close()
None.gif            self.fp 
=  None
None.gif
None.gif    def isclosed(self):
None.gif        # NOTE: it 
is  possible that we will not ever call self.close(). This
None.gif        #       
case  occurs when will_close  is  TRUE, length  is  None, and we
None.gif        #       read up to the last 
byte , but NOT past it.
None.gif        #
None.gif        # IMPLIES: 
if  will_close  is  FALSE, then self.close() will ALWAYS be
None.gif        #          called, meaning self.isclosed() 
is  meaningful.
None.gif        
return  self.fp  is  None
None.gif
None.gif    # XXX It would be nice to have readline and __iter__ 
for   this , too.
None.gif
None.gif    def read(self, amt
= None):
None.gif        
if  self.fp  is  None:
None.gif            
return   ''
None.gif
None.gif        
if  self.chunked:
None.gif            
return  self._read_chunked(amt)
None.gif
None.gif        
if  amt  is  None:
None.gif            # unbounded read
None.gif            
if  self.length  is  None:
None.gif                s 
=  self.fp.read()
None.gif            
else :
None.gif                s 
=  self._safe_read(self.length)
None.gif                self.length 
=   0
None.gif            self.close()        # we read everything
None.gif            
return  s
None.gif
None.gif        
if  self.length  is  not None:
None.gif            
if  amt  >  self.length:
None.gif                # clip the read to the 
" end of response "
None.gif                amt 
=  self.length
None.gif
None.gif        # we 
do  not use _safe_read() here because  this  may be a .will_close
None.gif        # connection, and the user 
is  reading more bytes than will be provided
None.gif        # (
for  example, reading  in  1k chunks)
None.gif        s 
=  self.fp.read(amt)
None.gif        
if  self.length  is  not None:
None.gif            self.length 
-=  len(s)
None.gif
None.gif        
return  s
None.gif
None.gif    def _read_chunked(self, amt):
None.gif        assert self.chunked 
!=  _UNKNOWN
None.gif        chunk_left 
=  self.chunk_left
None.gif        value 
=   ''
None.gif
None.gif        # XXX This accumulates chunks by repeated 
string  concatenation,
None.gif        # which 
is  not efficient  as  the number or size of chunks gets big.
None.gif        
while  True:
None.gif            
if  chunk_left  is  None:
None.gif                line 
=  self.fp.readline()
None.gif                i 
=  line.find( ' ; ' )
None.gif                
if  i  >=   0 :
None.gif                    line 
=  line[:i] # strip chunk - extensions
None.gif                chunk_left 
=   int (line,  16 )
None.gif                
if  chunk_left  ==   0 :
None.gif                    
break
None.gif            
if  amt  is  None:
None.gif                value 
+=  self._safe_read(chunk_left)
None.gif            elif amt 
<  chunk_left:
None.gif                value 
+=  self._safe_read(amt)
None.gif                self.chunk_left 
=  chunk_left  -  amt
None.gif                
return  value
None.gif            elif amt 
==  chunk_left:
None.gif                value 
+=  self._safe_read(amt)
None.gif                self._safe_read(
2 )  # toss the CRLF at the end of the chunk
None.gif                self.chunk_left 
=  None
None.gif                
return  value
None.gif            
else :
None.gif                value 
+=  self._safe_read(chunk_left)
None.gif                amt 
-=  chunk_left
None.gif
None.gif            # we read the whole chunk, 
get  another
None.gif            self._safe_read(
2 )      # toss the CRLF at the end of the chunk
None.gif            chunk_left 
=  None
None.gif
None.gif        # read and discard trailer up to the CRLF terminator
None.gif        ### note: we shouldn
' t have any trailers!
None.gif
         while  True:
None.gif            line 
=  self.fp.readline()
None.gif            
if  line  ==   ' \r\n ' :
None.gif                
break
None.gif
None.gif        # we read everything; close the 
" file "
None.gif        self.close()
None.gif
None.gif        
return  value
None.gif
None.gif    def _safe_read(self, amt):
None.gif        
""" Read the number of bytes requested, compensating for partial reads.
None.gif

None.gif        Normally, we have a blocking socket, but a read() can be interrupted
None.gif        by a signal (resulting 
in  a partial read).
None.gif
None.gif        Note that we cannot distinguish between EOF and an interrupt when zero
None.gif        bytes have been read. IncompleteRead() will be raised 
in   this
None.gif        situation.
None.gif
None.gif        This function should be used when 
< amt >  bytes  " should "  be present  for
None.gif        reading. If the bytes are truly not available (due to EOF), then the
None.gif        IncompleteRead exception can be used to detect the problem.
None.gif        
"""
None.gif
        s  =  []
None.gif        
while  amt  >   0 :
None.gif            chunk 
=  self.fp.read(min(amt, MAXAMOUNT))
None.gif            
if  not chunk:
None.gif                raise IncompleteRead(s)
None.gif            s.append(chunk)
None.gif            amt 
-=  len(chunk)
None.gif        
return   '' .join(s)
None.gif
None.gif    def getheader(self, name, 
default = None):
None.gif        
if  self.msg  is  None:
None.gif            raise ResponseNotReady()
None.gif        
return  self.msg.getheader(name,  default )
None.gif
None.gif    def getheaders(self):
None.gif        
""" Return list of (header, value) tuples. """
None.gif        
if  self.msg  is  None:
None.gif            raise ResponseNotReady()
None.gif        
return  self.msg.items()
None.gif
None.gif
None.gif
class  HTTPConnection:
None.gif
None.gif    _http_vsn 
=   11
None.gif    _http_vsn_str 
=   ' HTTP/1.1 '
None.gif
None.gif    response_class 
=  HTTPResponse
None.gif    default_port 
=  HTTP_PORT
None.gif    auto_open 
=   1
None.gif    debuglevel 
=   0
None.gif    strict 
=   0
None.gif
None.gif    def __init__(self, host, port
= None, strict = None, timeout = None):
None.gif        self.timeout 
=  timeout
None.gif        self.sock 
=  None
None.gif        self._buffer 
=  []
None.gif        self.__response 
=  None
None.gif        self.__state 
=  _CS_IDLE
None.gif        self._method 
=  None
None.gif
None.gif        self._set_hostport(host, port)
None.gif        
if  strict  is  not None:
None.gif            self.strict 
=  strict
None.gif
None.gif    def _set_hostport(self, host, port):
None.gif        
if  port  is  None:
None.gif            i 
=  host.rfind( ' : ' )
None.gif            j 
=  host.rfind( ' ] ' )         # ipv6 addresses have [dot.gif]
None.gif            
if  i  >  j:
None.gif                
try :
None.gif                    port 
=   int (host[i + 1 :])
None.gif                except ValueError:
None.gif                    raise InvalidURL(
" nonnumeric port: '%s' "   %  host[i + 1 :])
None.gif                host 
=  host[:i]
None.gif            
else :
None.gif                port 
=  self.default_port
None.gif            
if  host and host[ 0 ==   ' [ '  and host[ - 1 ==   ' ] ' :
None.gif                host 
=  host[ 1 : - 1 ]
None.gif        self.host 
=  host
None.gif        self.port 
=  port
None.gif
None.gif    def set_debuglevel(self, level):
None.gif        self.debuglevel 
=  level
None.gif
None.gif    def connect(self):
None.gif        
""" Connect to the host and port specified in __init__. """
None.gif        self.sock 
=  socket.create_connection((self.host,self.port),
None.gif                                             self.timeout)
None.gif
None.gif    def close(self):
None.gif        
""" Close the connection to the HTTP server. """
None.gif        
if  self.sock:
None.gif            self.sock.close()   # close it manuallydot.gif there may be other refs
None.gif            self.sock 
=  None
None.gif        
if  self.__response:
None.gif            self.__response.close()
None.gif            self.__response 
=  None
None.gif        self.__state 
=  _CS_IDLE
None.gif
None.gif    def send(self, str):
None.gif        
""" Send `str' to the server. """
None.gif        
if  self.sock  is  None:
None.gif            
if  self.auto_open:
None.gif                self.connect()
None.gif            
else :
None.gif                raise NotConnected()
None.gif
None.gif        # send the data to the server. 
if  we  get  a broken pipe, then close
None.gif        # the socket. we want to reconnect when somebody tries to send again.
None.gif        #
None.gif        # NOTE: we DO propagate the error, though, because we cannot simply
None.gif        #       ignore the errordot.gif the caller will know 
if  they can retry.
None.gif        
if  self.debuglevel  >   0 :
None.gif            print 
" send: " , repr(str)
None.gif        
try :
None.gif            blocksize
= 8192
None.gif            
if  hasattr(str, ' read ' ) :
None.gif                
if  self.debuglevel  >   0 : print  " sendIng a read()able "
None.gif                data
= str.read(blocksize)
None.gif                
while  data:
None.gif                    self.sock.sendall(data)
None.gif                    data
= str.read(blocksize)
None.gif            
else :
None.gif                self.sock.sendall(str)
None.gif        except socket.error, v:
None.gif            
if  v[ 0 ==   32 :      # Broken pipe
None.gif                self.close()
None.gif            raise
None.gif
None.gif    def _output(self, s):
None.gif        
""" Add a line of output to the current request buffer.
None.gif

None.gif        Assumes that the line does 
* not *  end with \\r\\n.
None.gif        
"""
None.gif
        self._buffer.append(s)
None.gif
None.gif    def _send_output(self):
None.gif        
""" Send the currently buffered request and clear the buffer.
None.gif

None.gif        Appends an extra \\r\\n to the buffer.
None.gif        
"""
None.gif
        self._buffer.extend(( "" "" ))
None.gif        msg 
=   " \r\n " .join(self._buffer)
None.gif        del self._buffer[:]
None.gif        self.send(msg)
None.gif
None.gif    def putrequest(self, method, url, skip_host
= 0 , skip_accept_encoding = 0 ):
None.gif        
""" Send a request to the server.
None.gif

None.gif        `method
'  specifies an HTTP request method, e.g.  ' GET ' .
None.gif
        `url '  specifies the object being requested, e.g.  ' / index.html ' .
None.gif
        `skip_host '  if True does not add automatically a  ' Host: '  header
None.gif
        `skip_accept_encoding '  if True does not add automatically an
None.gif
            ' Accept-Encoding: '  header
None.gif        
"""
None.gif

None.gif        # 
if  a prior response has been completed, then forget about it.
None.gif        
if  self.__response and self.__response.isclosed():
None.gif            self.__response 
=  None
None.gif
None.gif
None.gif        # 
in  certain cases, we cannot issue another request on  this  connection.
None.gif        # 
this  occurs when:
None.gif        #   
1 ) we are  in  the process of sending a request.   (_CS_REQ_STARTED)
None.gif        #   
2 ) a response to a previous request has signalled that it  is  going
None.gif        #      to close the connection upon completion.
None.gif        #   
3 ) the headers  for  the previous response have not been read, thus
None.gif        #      we cannot determine whether point (
2 is   true .   (_CS_REQ_SENT)
None.gif        #
None.gif        # 
if  there  is  no prior response, then we can request at will.
None.gif        #
None.gif        # 
if  point ( 2 is   true , then we will have passed the socket to the
None.gif        # response (effectively meaning, 
" there is no prior response " ), and
None.gif        # will open a 
new  one when a  new  request  is  made.
None.gif        #
None.gif        # Note: 
if  a prior response exists, then we  * can *  start a  new  request.
None.gif        #       We are not allowed to begin fetching the response to 
this   new
None.gif        #       request, however, until that prior response 
is  complete.
None.gif        #
None.gif        
if  self.__state  ==  _CS_IDLE:
None.gif            self.__state 
=  _CS_REQ_STARTED
None.gif        
else :
None.gif            raise CannotSendRequest()
None.gif
None.gif        # Save the method we use, we need it later 
in  the response phase
None.gif        self._method 
=  method
None.gif        
if  not url:
None.gif            url 
=   ' / '
None.gif        str 
=   ' %s %s %s '   %  (method, url, self._http_vsn_str)
None.gif
None.gif        self._output(str)
None.gif
None.gif        
if  self._http_vsn  ==   11 :
None.gif            # Issue some standard headers 
for  better HTTP / 1.1  compliance
None.gif
None.gif            
if  not skip_host:
None.gif                # 
this  header  is  issued  * only *   for  HTTP / 1.1
None.gif                # connections. more specifically, 
this  means it  is
None.gif                # only issued when the client uses the 
new
None.gif                # HTTPConnection() 
class . backwards - compat clients
None.gif                # will be 
using  HTTP / 1.0  and those clients may be
None.gif                # issuing 
this  header themselves. we should NOT issue
None.gif                # it twice; some web servers (such 
as  Apache) barf
None.gif                # when they see two Host: headers
None.gif
None.gif                # If we need a non
- standard port,include it  in  the
None.gif                # header.  If the request 
is  going through a proxy,
None.gif                # but the host of the actual URL, not the host of the
None.gif                # proxy.
None.gif
None.gif                netloc 
=   ''
None.gif                
if  url.startswith( ' http ' ):
None.gif                    nil, netloc, nil, nil, nil 
=  urlsplit(url)
None.gif
None.gif                
if  netloc:
None.gif                    
try :
None.gif                        netloc_enc 
=  netloc.encode( " ascii " )
None.gif                    except UnicodeEncodeError:
None.gif                        netloc_enc 
=  netloc.encode( " idna " )
None.gif                    self.putheader(
' Host ' , netloc_enc)
None.gif                
else :
None.gif                    
try :
None.gif                        host_enc 
=  self.host.encode( " ascii " )
None.gif                    except UnicodeEncodeError:
None.gif                        host_enc 
=  self.host.encode( " idna " )
None.gif                    
if  self.port  ==  HTTP_PORT:
None.gif                        self.putheader(
' Host ' , host_enc)
None.gif                    
else :
None.gif                        self.putheader(
' Host ' " %s:%s "   %  (host_enc, self.port))
None.gif
None.gif            # note: we are assuming that clients will not attempt to 
set  these
None.gif            #       headers since 
* this *  library must deal with the
None.gif            #       consequences. 
this  also means that when the supporting
None.gif            #       libraries are updated to recognize other forms, then 
this
None.gif            #       code should be changed (removed or updated).
None.gif
None.gif            # we only want a Content
- Encoding of  " identity "  since we don ' t
None.gif
            # support encodings such  as  x - gzip or x - deflate.
None.gif            
if  not skip_accept_encoding:
None.gif                self.putheader(
' Accept-Encoding ' ' identity ' )
None.gif
None.gif            # we can accept 
" chunked "  Transfer - Encodings, but no others
None.gif            # NOTE: no TE header implies 
* only *   " chunked "
None.gif            #self.putheader(
' TE ' ' chunked ' )
None.gif
None.gif            # 
if  TE  is  supplied  in  the header, then it must appear  in  a
None.gif            # Connection header.
None.gif            #self.putheader(
' Connection ' ' TE ' )
None.gif
None.gif        
else :
None.gif            # For HTTP
/ 1.0 , the server will assume  " not chunked "
None.gif            pass
None.gif
None.gif    def putheader(self, header, value):
None.gif        
""" Send a request header line to the server.
None.gif

None.gif        For example: h.putheader(
' Accept ' ' text/html ' )
None.gif        
"""
None.gif
         if  self.__state  !=  _CS_REQ_STARTED:
None.gif            raise CannotSendHeader()
None.gif
None.gif        str 
=   ' %s: %s '   %  (header, value)
None.gif        self._output(str)
None.gif
None.gif    def endheaders(self):
None.gif        
""" Indicate that the last header line has been sent to the server. """
None.gif
None.gif        
if  self.__state  ==  _CS_REQ_STARTED:
None.gif            self.__state 
=  _CS_REQ_SENT
None.gif        
else :
None.gif            raise CannotSendHeader()
None.gif
None.gif        self._send_output()
None.gif
ExpandedBlockStart.gifContractedBlock.gif    def request(self, method, url, body
= None, headers = dot.gif {} ):
None.gif        
""" Send a complete request to the server. """
None.gif
None.gif        
try :
None.gif            self._send_request(method, url, body, headers)
None.gif        except socket.error, v:
None.gif            # trap 
' Broken pipe '   if  we ' re allowed to automatically reconnect
None.gif
             if  v[ 0 !=   32  or not self.auto_open:
None.gif                raise
None.gif            # 
try  one more time
None.gif            self._send_request(method, url, body, headers)
None.gif
None.gif    def _send_request(self, method, url, body, headers):
None.gif        # honour explicitly requested Host: and Accept
- Encoding headers
None.gif        header_names 
=  dict.fromkeys([k.lower()  for  k  in  headers])
ExpandedBlockStart.gifContractedBlock.gif        skips 
=   dot.gif {}
None.gif        
if   ' host '   in  header_names:
None.gif            skips[
' skip_host ' =   1
None.gif        
if   ' accept-encoding '   in  header_names:
None.gif            skips[
' skip_accept_encoding ' =   1
None.gif
None.gif        self.putrequest(method, url, 
** skips)
None.gif
None.gif        
if  body and ( ' content-length '  not  in  header_names):
None.gif            thelen
= None
None.gif            
try :
None.gif                thelen
= str(len(body))
None.gif            except TypeError, te:
None.gif                # If 
this   is  a file - like  object try  to
None.gif                # fstat its file descriptor
None.gif                import os
None.gif                
try :
None.gif                    thelen 
=  str(os.fstat(body.fileno()).st_size)
None.gif                except (AttributeError, OSError):
None.gif                    # Don
' t send a length if this failed
None.gif
                     if  self.debuglevel  >   0 : print  " Cannot stat!! "
None.gif
None.gif            
if  thelen  is  not None:
None.gif                self.putheader(
' Content-Length ' ,thelen)
None.gif        
for  hdr, value  in  headers.iteritems():
None.gif            self.putheader(hdr, value)
None.gif        self.endheaders()
None.gif
None.gif        
if  body:
None.gif            self.send(body)
None.gif
None.gif    def getresponse(self):
None.gif        
" Get the response from the server. "
None.gif
None.gif        # 
if  a prior response has been completed, then forget about it.
None.gif        
if  self.__response and self.__response.isclosed():
None.gif            self.__response 
=  None
None.gif
None.gif        #
None.gif        # 
if  a prior response exists, then it must be completed (otherwise, we
None.gif        # cannot read 
this  response ' s header to determine the connection-close
None.gif
        # behavior)
None.gif        #
None.gif        # note: 
if  a prior response existed, but was connection - close, then the
None.gif        # socket and response were made independent of 
this  HTTPConnection
None.gif        # 
object  since a  new  request requires that we open a whole  new
None.gif        # connection
None.gif        #
None.gif        # 
this  means the prior response had one of two states:
None.gif        #   
1 ) will_close:  this  connection was reset and the prior socket and
None.gif        #                  response operate independently
None.gif        #   
2 ) persistent: the response was retained and we await its
None.gif        #                  isclosed() status to become 
true .
None.gif        #
None.gif        
if  self.__state  !=  _CS_REQ_SENT or self.__response:
None.gif            raise ResponseNotReady()
None.gif
None.gif        
if  self.debuglevel  >   0 :
None.gif            response 
=  self.response_class(self.sock, self.debuglevel,
None.gif                                           strict
= self.strict,
None.gif                                           method
= self._method)
None.gif        
else :
None.gif            response 
=  self.response_class(self.sock, strict = self.strict,
None.gif                                           method
= self._method)
None.gif
None.gif        response.begin()
None.gif        assert response.will_close 
!=  _UNKNOWN
None.gif        self.__state 
=  _CS_IDLE
None.gif
None.gif        
if  response.will_close:
None.gif            # 
this  effectively passes the connection to the response
None.gif            self.close()
None.gif        
else :
None.gif            # remember 
this , so we can tell when it  is  complete
None.gif            self.__response 
=  response
None.gif
None.gif        
return  response
None.gif
None.gif# The next several classes are used to define FakeSocket, a socket
- like
None.gif
interface  to an SSL connection.
None.gif
None.gif# The primary complexity comes from faking a makefile() method.  The
None.gif# standard socket makefile() implementation calls dup() on the socket
None.gif# file descriptor.  As a consequence, clients can call close() on the
None.gif# parent socket and its makefile children 
in  any order.  The underlying
None.gif# socket isn
' t closed until they are all closed.
None.gif

None.gif# The implementation uses reference counting to keep the socket open
None.gif# until the last client calls close().  SharedSocket keeps track of
None.gif# the reference counting and SharedSocketClient provides an constructor
None.gif# and close() method that call incref() and decref() correctly.
None.gif
None.gif
class  SharedSocket:
None.gif
None.gif    def __init__(self, sock):
None.gif        self.sock 
=  sock
None.gif        self._refcnt 
=   0
None.gif
None.gif    def incref(self):
None.gif        self._refcnt 
+=   1
None.gif
None.gif    def decref(self):
None.gif        self._refcnt 
-=   1
None.gif        assert self._refcnt 
>=   0
None.gif        
if  self._refcnt  ==   0 :
None.gif            self.sock.close()
None.gif
None.gif    def __del__(self):
None.gif        self.sock.close()
None.gif
None.gif
class  SharedSocketClient:
None.gif
None.gif    def __init__(self, shared):
None.gif        self._closed 
=   0
None.gif        self._shared 
=  shared
None.gif        self._shared.incref()
None.gif        self._sock 
=  shared.sock
None.gif
None.gif    def close(self):
None.gif        
if  not self._closed:
None.gif            self._shared.decref()
None.gif            self._closed 
=   1
None.gif            self._shared 
=  None
None.gif
None.gif
class  SSLFile(SharedSocketClient):
None.gif    
""" File-like object wrapping an SSL socket. """
None.gif
None.gif    BUFSIZE 
=   8192
None.gif
None.gif    def __init__(self, sock, ssl, bufsize
= None):
None.gif        SharedSocketClient.__init__(self, sock)
None.gif        self._ssl 
=  ssl
None.gif        self._buf 
=   ''
None.gif        self._bufsize 
=  bufsize or self.__class__.BUFSIZE
None.gif
None.gif    def _read(self):
None.gif        buf 
=   ''
None.gif        # put 
in  a loop so that we retry on transient errors
None.gif        
while  True:
None.gif            
try :
None.gif                buf 
=  self._ssl.read(self._bufsize)
None.gif            except socket.sslerror, err:
None.gif                
if  (err[ 0 ==  socket.SSL_ERROR_WANT_READ
None.gif                    or err[
0 ==  socket.SSL_ERROR_WANT_WRITE):
None.gif                    
continue
None.gif                
if  (err[ 0 ==  socket.SSL_ERROR_ZERO_RETURN
None.gif                    or err[
0 ==  socket.SSL_ERROR_EOF):
None.gif                    
break
None.gif                raise
None.gif            except socket.error, err:
None.gif                
if  err[ 0 ==  errno.EINTR:
None.gif                    
continue
None.gif                
if  err[ 0 ==  errno.EBADF:
None.gif                    # XXX socket was closed
?
None.gif                    
break
None.gif                raise
None.gif            
else :
None.gif                
break
None.gif        
return  buf
None.gif
None.gif    def read(self, size
= None):
None.gif        L 
=  [self._buf]
None.gif        avail 
=  len(self._buf)
None.gif        
while  size  is  None or avail  <  size:
None.gif            s 
=  self._read()
None.gif            
if  s  ==   '' :
None.gif                
break
None.gif            L.append(s)
None.gif            avail 
+=  len(s)
None.gif        all 
=   "" .join(L)
None.gif        
if  size  is  None:
None.gif            self._buf 
=   ''
None.gif            
return  all
None.gif        
else :
None.gif            self._buf 
=  all[size:]
None.gif            
return  all[:size]
None.gif
None.gif    def readline(self):
None.gif        L 
=  [self._buf]
None.gif        self._buf 
=   ''
None.gif        
while   1 :
None.gif            i 
=  L[ - 1 ].find( " \n " )
None.gif            
if  i  >=   0 :
None.gif                
break
None.gif            s 
=  self._read()
None.gif            
if  s  ==   '' :
None.gif                
break
None.gif            L.append(s)
None.gif        
if  i  ==   - 1 :
None.gif            # loop exited because there 
is  no more data
None.gif            
return   "" .join(L)
None.gif        
else :
None.gif            all 
=   "" .join(L)
None.gif            # XXX could 
do  enough bookkeeping not to  do  a 2nd search
None.gif            i 
=  all.find( " \n " +   1
None.gif            line 
=  all[:i]
None.gif            self._buf 
=  all[i:]
None.gif            
return  line
None.gif
None.gif    def readlines(self, sizehint
= 0 ):
None.gif        total 
=   0
None.gif        list 
=  []
None.gif        
while  True:
None.gif            line 
=  self.readline()
None.gif            
if  not line:
None.gif                
break
None.gif            list.append(line)
None.gif            total 
+=  len(line)
None.gif            
if  sizehint and total  >=  sizehint:
None.gif                
break
None.gif        
return  list
None.gif
None.gif    def fileno(self):
None.gif        
return  self._sock.fileno()
None.gif
None.gif    def __iter__(self):
None.gif        
return  self
None.gif
None.gif    def next(self):
None.gif        line 
=  self.readline()
None.gif        
if  not line:
None.gif            raise StopIteration
None.gif        
return  line
None.gif
None.gif
class  FakeSocket(SharedSocketClient):
None.gif
None.gif    
class  _closedsocket:
None.gif        def __getattr__(self, name):
None.gif            raise error(
9 ' Bad file descriptor ' )
None.gif
None.gif    def __init__(self, sock, ssl):
None.gif        sock 
=  SharedSocket(sock)
None.gif        SharedSocketClient.__init__(self, sock)
None.gif        self._ssl 
=  ssl
None.gif
None.gif    def close(self):
None.gif        SharedSocketClient.close(self)
None.gif        self._sock 
=  self.__class__._closedsocket()
None.gif
None.gif    def makefile(self, mode, bufsize
= None):
None.gif        
if  mode  !=   ' r '  and mode  !=   ' rb ' :
None.gif            raise UnimplementedFileMode()
None.gif        
return  SSLFile(self._shared, self._ssl, bufsize)
None.gif
None.gif    def send(self, stuff, flags 
=   0 ):
None.gif        
return  self._ssl.write(stuff)
None.gif
None.gif    sendall 
=  send
None.gif
None.gif    def recv(self, len 
=   1024 , flags  =   0 ):
None.gif        
return  self._ssl.read(len)
None.gif
None.gif    def __getattr__(self, attr):
None.gif        
return  getattr(self._sock, attr)
None.gif
None.gif
None.gif
class  HTTPSConnection(HTTPConnection):
None.gif    
" This class allows communication via SSL. "
None.gif
None.gif    default_port 
=  HTTPS_PORT
None.gif
None.gif    def __init__(self, host, port
= None, key_file = None, cert_file = None,
None.gif                 strict
= None):
None.gif        HTTPConnection.__init__(self, host, port, strict)
None.gif        self.key_file 
=  key_file
None.gif        self.cert_file 
=  cert_file
None.gif
None.gif    def connect(self):
None.gif        
" Connect to a host on a given (SSL) port. "
None.gif
None.gif        sock 
=  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
None.gif        sock.connect((self.host, self.port))
None.gif        ssl 
=  socket.ssl(sock, self.key_file, self.cert_file)
None.gif        self.sock 
=  FakeSocket(sock, ssl)
None.gif
None.gif
None.gif
class  HTTP:
None.gif    
" Compatibility class with httplib.py from 1.5. "
None.gif
None.gif    _http_vsn 
=   10
None.gif    _http_vsn_str 
=   ' HTTP/1.0 '
None.gif
None.gif    debuglevel 
=   0
None.gif
None.gif    _connection_class 
=  HTTPConnection
None.gif
None.gif    def __init__(self, host
= '' , port = None, strict = None):
None.gif        
" Provide a default host, since the superclass requires one. "
None.gif
None.gif        # some joker passed 
0  explicitly, meaning  default  port
None.gif        
if  port  ==   0 :
None.gif            port 
=  None
None.gif
None.gif        # Note that we may pass an empty 
string   as  the host;  this  will  throw
None.gif        # an error when we attempt to connect. Presumably, the client code
None.gif        # will call connect before then, with a proper host.
None.gif        self._setup(self._connection_class(host, port, strict))
None.gif
None.gif    def _setup(self, conn):
None.gif        self._conn 
=  conn
None.gif
None.gif        # 
set  up delegation to flesh  out   interface
None.gif        self.send 
=  conn.send
None.gif        self.putrequest 
=  conn.putrequest
None.gif        self.endheaders 
=  conn.endheaders
None.gif        self.set_debuglevel 
=  conn.set_debuglevel
None.gif
None.gif        conn._http_vsn 
=  self._http_vsn
None.gif        conn._http_vsn_str 
=  self._http_vsn_str
None.gif
None.gif        self.file 
=  None
None.gif
None.gif    def connect(self, host
= None, port = None):
None.gif        
" Accept arguments to set the host/port, since the superclass doesn't. "
None.gif
None.gif        
if  host  is  not None:
None.gif            self._conn._set_hostport(host, port)
None.gif        self._conn.connect()
None.gif
None.gif    def getfile(self):
None.gif        
" Provide a getfile, since the superclass' does not use this concept. "
None.gif        
return  self.file
None.gif
None.gif    def putheader(self, header, 
* values):
None.gif        
" The superclass allows only one value argument. "
None.gif        self._conn.putheader(header, 
' \r\n\t ' .join(values))
None.gif
None.gif    def getreply(self):
None.gif        
""" Compat definition since superclass does not define it.
None.gif

None.gif        Returns a tuple consisting of:
None.gif        
-  server status code (e.g.  ' 200 '   if  all goes well)
None.gif        
-  server  " reason "  corresponding to status code
None.gif        
-  any RFC822 headers  in  the response from the server
None.gif        
"""
None.gif
         try :
None.gif            response 
=  self._conn.getresponse()
None.gif        except BadStatusLine, e:
None.gif            ### hmm. 
if  getresponse() ever closes the socket on a bad request,
None.gif            ### then we are going to have problems with self.sock
None.gif
None.gif            ### should we keep 
this  behavior ?   do  people use it ?
None.gif            # keep the socket open (
as  a file), and  return  it
None.gif            self.file 
=  self._conn.sock.makefile( ' rb ' 0 )
None.gif
None.gif            # close our socket 
--  we want to restart after any protocol error
None.gif            self.close()
None.gif
None.gif            self.headers 
=  None
None.gif            
return   - 1 , e.line, None
None.gif
None.gif        self.headers 
=  response.msg
None.gif        self.file 
=  response.fp
None.gif        
return  response.status, response.reason, response.msg
None.gif
None.gif    def close(self):
None.gif        self._conn.close()
None.gif
None.gif        # note that self.file 
==  response.fp, which gets closed by the
None.gif        # superclass. just clear the 
object   ref  here.
None.gif        ### hmm. messy. 
if  status ==- 1 , then self.file  is  owned by us.
None.gif        ### welldot.gif we aren
' t explicitly closing, but losing this ref will
None.gif
        ###  do  it
None.gif        self.file 
=  None
None.gif
None.gif
if  hasattr(socket,  ' ssl ' ):
None.gif    
class  HTTPS(HTTP):
None.gif        
""" Compatibility with 1.5 httplib interface
None.gif

None.gif        Python 
1.5 . 2  did not have an HTTPS  class , but it defined an
None.gif        
interface   for  sending http requests that  is  also useful  for
None.gif        https.
None.gif        
"""
None.gif

None.gif        _connection_class 
=  HTTPSConnection
None.gif
None.gif        def __init__(self, host
= '' , port = None, key_file = None, cert_file = None,
None.gif                     strict
= None):
None.gif            # provide a 
default  host, pass the X509 cert info
None.gif
None.gif            # urf. compensate 
for  bad input.
None.gif            
if  port  ==   0 :
None.gif                port 
=  None
None.gif            self._setup(self._connection_class(host, port, key_file,
None.gif                                               cert_file, strict))
None.gif
None.gif            # we never actually use these 
for  anything, but we keep them
None.gif            # here 
for  compatibility with post - 1.5 . 2  CVS.
None.gif            self.key_file 
=  key_file
None.gif            self.cert_file 
=  cert_file
None.gif
None.gif
None.gif
class  HTTPException(Exception):
None.gif    # Subclasses that define an __init__ must call Exception.__init__
None.gif    # or define self.args.  Otherwise, str() will fail.
None.gif    pass
None.gif
None.gif
class  NotConnected(HTTPException):
None.gif    pass
None.gif
None.gif
class  InvalidURL(HTTPException):
None.gif    pass
None.gif
None.gif
class  UnknownProtocol(HTTPException):
None.gif    def __init__(self, version):
None.gif        self.args 
=  version,
None.gif        self.version 
=  version
None.gif
None.gif
class  UnknownTransferEncoding(HTTPException):
None.gif    pass
None.gif
None.gif
class  UnimplementedFileMode(HTTPException):
None.gif    pass
None.gif
None.gif
class  IncompleteRead(HTTPException):
None.gif    def __init__(self, partial):
None.gif        self.args 
=  partial,
None.gif        self.partial 
=  partial
None.gif
None.gif
class  ImproperConnectionState(HTTPException):
None.gif    pass
None.gif
None.gif
class  CannotSendRequest(ImproperConnectionState):
None.gif    pass
None.gif
None.gif
class  CannotSendHeader(ImproperConnectionState):
None.gif    pass
None.gif
None.gif
class  ResponseNotReady(ImproperConnectionState):
None.gif    pass
None.gif
None.gif
class  BadStatusLine(HTTPException):
None.gif    def __init__(self, line):
None.gif        self.args 
=  line,
None.gif        self.line 
=  line
None.gif
None.gif
for  backwards compatibility
None.giferror 
=  HTTPException
None.gif
None.gif
class  LineAndFileWrapper:
None.gif    
""" A limited file-like object for HTTP/0.9 responses. """
None.gif
None.gif    # The status
- line parsing code calls readline(), which normally
None.gif    # 
get  the HTTP status line.  For a  0.9  response, however,  this   is
None.gif    # actually the first line of the body
!   Clients need to  get  a
None.gif    # readable file 
object  that contains that line.
None.gif
None.gif    def __init__(self, line, file):
None.gif        self._line 
=  line
None.gif        self._file 
=  file
None.gif        self._line_consumed 
=   0
None.gif        self._line_offset 
=   0
None.gif        self._line_left 
=  len(line)
None.gif
None.gif    def __getattr__(self, attr):
None.gif        
return  getattr(self._file, attr)
None.gif
None.gif    def _done(self):
None.gif        # called when the last 
byte   is  read from the line.  After the
None.gif        # call, all read methods are delegated to the underlying file
None.gif        # 
object .
None.gif        self._line_consumed 
=   1
None.gif        self.read 
=  self._file.read
None.gif        self.readline 
=  self._file.readline
None.gif        self.readlines 
=  self._file.readlines
None.gif
None.gif    def read(self, amt
= None):
None.gif        
if  self._line_consumed:
None.gif            
return  self._file.read(amt)
None.gif        assert self._line_left
None.gif        
if  amt  is  None or amt  >  self._line_left:
None.gif            s 
=  self._line[self._line_offset:]
None.gif            self._done()
None.gif            
if  amt  is  None:
None.gif                
return  s  +  self._file.read()
None.gif            
else :
None.gif                
return  s  +  self._file.read(amt  -  len(s))
None.gif        
else :
None.gif            assert amt 
<=  self._line_left
None.gif            i 
=  self._line_offset
None.gif            j 
=  i  +  amt
None.gif            s 
=  self._line[i:j]
None.gif            self._line_offset 
=  j
None.gif            self._line_left 
-=  amt
None.gif            
if  self._line_left  ==   0 :
None.gif                self._done()
None.gif            
return  s
None.gif
None.gif    def readline(self):
None.gif        
if  self._line_consumed:
None.gif            
return  self._file.readline()
None.gif        assert self._line_left
None.gif        s 
=  self._line[self._line_offset:]
None.gif        self._done()
None.gif        
return  s
None.gif
None.gif    def readlines(self, size
= None):
None.gif        
if  self._line_consumed:
None.gif            
return  self._file.readlines(size)
None.gif        assert self._line_left
None.gif        L 
=  [self._line[self._line_offset:]]
None.gif        self._done()
None.gif        
if  size  is  None:
None.gif            
return  L  +  self._file.readlines()
None.gif        
else :
None.gif            
return  L  +  self._file.readlines(size)
None.gif
None.gifdef test():
None.gif    
""" Test this module.
None.gif

None.gif    A hodge podge of tests collected here, because they have too many
None.gif    external dependencies 
for  the regular test suite.
None.gif    
"""
None.gif

None.gif    import sys
None.gif    import getopt
None.gif    opts, args 
=  getopt.getopt(sys.argv[ 1 :],  ' d ' )
None.gif    dl 
=   0
None.gif    
for  o, a  in  opts:
None.gif        
if  o  ==   ' -d ' : dl  =  dl  +   1
None.gif    host 
=   ' www.python.org '
None.gif    selector 
=   ' / '
None.gif    
if  args[ 0 :]: host  =  args[ 0 ]
None.gif    
if  args[ 1 :]: selector  =  args[ 1 ]
None.gif    h 
=  HTTP()
None.gif    h.set_debuglevel(dl)
None.gif    h.connect(host)
None.gif    h.putrequest(
' GET ' , selector)
None.gif    h.endheaders()
None.gif    status, reason, headers 
=  h.getreply()
None.gif    print 
' status = ' , status
None.gif    print 
' reason = ' , reason
None.gif    print 
" read " , len(h.getfile().read())
None.gif    print
None.gif    
if  headers:
None.gif        
for  header  in  headers.headers: print header.strip()
None.gif    print
None.gif
None.gif    # minimal test that code to extract host from url works
None.gif    
class  HTTP11(HTTP):
None.gif        _http_vsn 
=   11
None.gif        _http_vsn_str 
=   ' HTTP/1.1 '
None.gif
None.gif    h 
=  HTTP11( ' www.python.org ' )
None.gif    h.putrequest(
' GET ' ' http://www.python.org/~jeremy/ ' )
None.gif    h.endheaders()
None.gif    h.getreply()
None.gif    h.close()
None.gif
None.gif    
if  hasattr(socket,  ' ssl ' ):
None.gif
None.gif        
for  host, selector  in  (( ' sourceforge.net ' ' /projects/python ' ),
None.gif                               ):
None.gif            print 
" https://%s%s "   %  (host, selector)
None.gif            hs 
=  HTTPS()
None.gif            hs.set_debuglevel(dl)
None.gif            hs.connect(host)
None.gif            hs.putrequest(
' GET ' , selector)
None.gif            hs.endheaders()
None.gif            status, reason, headers 
=  hs.getreply()
None.gif            print 
' status = ' , status
None.gif            print 
' reason = ' , reason
None.gif            print 
" read " , len(hs.getfile().read())
None.gif            print
None.gif            
if  headers:
None.gif                
for  header  in  headers.headers: print header.strip()
None.gif            print
None.gif
None.gif
if  __name__  ==   ' __main__ ' :
None.gif    test()
None.gif
None.gif

转载于:https://www.cnblogs.com/snowball/archive/2007/05/09/740389.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值