httplib.py

来自「mallet是自然语言处理、机器学习领域的一个开源项目。」· Python 代码 · 共 1,235 行 · 第 1/3 页

PY
1,235
字号
            if amt is None:                value += self._safe_read(chunk_left)            elif amt < chunk_left:                value += self._safe_read(amt)                self.chunk_left = chunk_left - amt                return value            elif amt == chunk_left:                value += self._safe_read(amt)                self._safe_read(2)  # toss the CRLF at the end of the chunk                self.chunk_left = None                return value            else:                value += self._safe_read(chunk_left)                amt -= chunk_left            # we read the whole chunk, get another            self._safe_read(2)      # toss the CRLF at the end of the chunk            chunk_left = None        # read and discard trailer up to the CRLF terminator        ### note: we shouldn't have any trailers!        while 1:            line = self.fp.readline()            if line == '\r\n':                break        # we read everything; close the "file"        # XXX Shouldn't the client close the file?        self.close()        return value    def _safe_read(self, amt):        """Read the number of bytes requested, compensating for partial reads.        Normally, we have a blocking socket, but a read() can be interrupted        by a signal (resulting in a partial read).        Note that we cannot distinguish between EOF and an interrupt when zero        bytes have been read. IncompleteRead() will be raised in this        situation.        This function should be used when <amt> bytes "should" be present for        reading. If the bytes are truly not available (due to EOF), then the        IncompleteRead exception can be used to detect the problem.        """        s = ''        while amt > 0:            chunk = self.fp.read(amt)            if not chunk:                raise IncompleteRead(s)            s = s + chunk            amt = amt - len(chunk)        return s    def getheader(self, name, default=None):        if self.msg is None:            raise ResponseNotReady()        return self.msg.getheader(name, default)class HTTPConnection:    _http_vsn = 11    _http_vsn_str = 'HTTP/1.1'    response_class = HTTPResponse    default_port = HTTP_PORT    auto_open = 1    debuglevel = 0    strict = 0    def __init__(self, host, port=None, strict=None):        self.sock = None        self._buffer = []        self.__response = None        self.__state = _CS_IDLE        self._set_hostport(host, port)        if strict is not None:            self.strict = strict    def _set_hostport(self, host, port):        if port is None:            i = host.find(':')            if i >= 0:                try:                    port = int(host[i+1:])                except ValueError:                    raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])                host = host[:i]            else:                port = self.default_port        self.host = host        self.port = port    def set_debuglevel(self, level):        self.debuglevel = level    def connect(self):        """Connect to the host and port specified in __init__."""        msg = "getaddrinfo returns an empty list"        for res in socket.getaddrinfo(self.host, self.port, 0,                                      socket.SOCK_STREAM):            af, socktype, proto, canonname, sa = res            try:                self.sock = socket.socket(af, socktype, proto)                if self.debuglevel > 0:                    print "connect: (%s, %s)" % (self.host, self.port)                self.sock.connect(sa)            except socket.error, msg:                if self.debuglevel > 0:                    print 'connect fail:', (self.host, self.port)                if self.sock:                    self.sock.close()                self.sock = None                continue            break        if not self.sock:            raise socket.error, msg    def close(self):        """Close the connection to the HTTP server."""        if self.sock:            self.sock.close()   # close it manually... there may be other refs            self.sock = None        if self.__response:            self.__response.close()            self.__response = None        self.__state = _CS_IDLE    def send(self, str):        """Send `str' to the server."""        if self.sock is None:            if self.auto_open:                self.connect()            else:                raise NotConnected()        # send the data to the server. if we get a broken pipe, then close        # the socket. we want to reconnect when somebody tries to send again.        #        # NOTE: we DO propagate the error, though, because we cannot simply        #       ignore the error... the caller will know if they can retry.        if self.debuglevel > 0:            print "send:", repr(str)        try:            self.sock.sendall(str)        except socket.error, v:            if v[0] == 32:      # Broken pipe                self.close()            raise    def _output(self, s):        """Add a line of output to the current request buffer.        Assumes that the line does *not* end with \\r\\n.        """        self._buffer.append(s)    def _send_output(self):        """Send the currently buffered request and clear the buffer.        Appends an extra \\r\\n to the buffer.        """        self._buffer.extend(("", ""))        msg = "\r\n".join(self._buffer)        del self._buffer[:]        self.send(msg)    def putrequest(self, method, url, skip_host=0):        """Send a request to the server.        `method' specifies an HTTP request method, e.g. 'GET'.        `url' specifies the object being requested, e.g. '/index.html'.        """        # check if a prior response has been completed        # XXX What if it hasn't?        if self.__response and self.__response.isclosed():            self.__response = None        #        # in certain cases, we cannot issue another request on this connection.        # this occurs when:        #   1) we are in the process of sending a request.   (_CS_REQ_STARTED)        #   2) a response to a previous request has signalled that it is going        #      to close the connection upon completion.        #   3) the headers for the previous response have not been read, thus        #      we cannot determine whether point (2) is true.   (_CS_REQ_SENT)        #        # if there is no prior response, then we can request at will.        #        # if point (2) is true, then we will have passed the socket to the        # response (effectively meaning, "there is no prior response"), and        # will open a new one when a new request is made.        #        # Note: if a prior response exists, then we *can* start a new request.        #       We are not allowed to begin fetching the response to this new        #       request, however, until that prior response is complete.        #        if self.__state == _CS_IDLE:            self.__state = _CS_REQ_STARTED        else:            raise CannotSendRequest()        if not url:            url = '/'        str = '%s %s %s' % (method, url, self._http_vsn_str)        self._output(str)        if self._http_vsn == 11:            # Issue some standard headers for better HTTP/1.1 compliance            if not skip_host:                # this header is issued *only* for HTTP/1.1                # connections. more specifically, this means it is                # only issued when the client uses the new                # HTTPConnection() class. backwards-compat clients                # will be using HTTP/1.0 and those clients may be                # issuing this header themselves. we should NOT issue                # it twice; some web servers (such as Apache) barf                # when they see two Host: headers                # If we need a non-standard port,include it in the                # header.  If the request is going through a proxy,                # but the host of the actual URL, not the host of the                # proxy.                netloc = ''                if url.startswith('http'):                    nil, netloc, nil, nil, nil = urlsplit(url)                if netloc:                    self.putheader('Host', netloc)                elif self.port == HTTP_PORT:                    self.putheader('Host', self.host)                else:                    self.putheader('Host', "%s:%s" % (self.host, self.port))            # note: we are assuming that clients will not attempt to set these            #       headers since *this* library must deal with the            #       consequences. this also means that when the supporting            #       libraries are updated to recognize other forms, then this            #       code should be changed (removed or updated).            # we only want a Content-Encoding of "identity" since we don't            # support encodings such as x-gzip or x-deflate.            self.putheader('Accept-Encoding', 'identity')            # we can accept "chunked" Transfer-Encodings, but no others            # NOTE: no TE header implies *only* "chunked"            #self.putheader('TE', 'chunked')            # if TE is supplied in the header, then it must appear in a            # Connection header.            #self.putheader('Connection', 'TE')        else:            # For HTTP/1.0, the server will assume "not chunked"            pass    def putheader(self, header, value):        """Send a request header line to the server.        For example: h.putheader('Accept', 'text/html')        """        if self.__state != _CS_REQ_STARTED:            raise CannotSendHeader()        str = '%s: %s' % (header, value)        self._output(str)    def endheaders(self):        """Indicate that the last header line has been sent to the server."""        if self.__state == _CS_REQ_STARTED:            self.__state = _CS_REQ_SENT        else:            raise CannotSendHeader()        self._send_output()    def request(self, method, url, body=None, headers={}):        """Send a complete request to the server."""        try:            self._send_request(method, url, body, headers)        except socket.error, v:            # trap 'Broken pipe' if we're allowed to automatically reconnect            if v[0] != 32 or not self.auto_open:                raise            # try one more time            self._send_request(method, url, body, headers)    def _send_request(self, method, url, body, headers):        # If headers already contains a host header, then define the        # optional skip_host argument to putrequest().  The check is        # harder because field names are case insensitive.        if 'Host' in (headers            or [k for k in headers.iterkeys() if k.lower() == "host"]):            self.putrequest(method, url, skip_host=1)        else:            self.putrequest(method, url)        if body:            self.putheader('Content-Length', str(len(body)))        for hdr, value in headers.items():            self.putheader(hdr, value)        self.endheaders()        if body:            self.send(body)    def getresponse(self):        "Get the response from the server."        # check if a prior response has been completed        if self.__response and self.__response.isclosed():            self.__response = None        #        # if a prior response exists, then it must be completed (otherwise, we        # cannot read this response's header to determine the connection-close        # behavior)        #        # note: if a prior response existed, but was connection-close, then the        # socket and response were made independent of this HTTPConnection        # object since a new request requires that we open a whole new        # connection        #        # this means the prior response had one of two states:        #   1) will_close: this connection was reset and the prior socket and        #                  response operate independently        #   2) persistent: the response was retained and we await its        #                  isclosed() status to become true.        #        if self.__state != _CS_REQ_SENT or self.__response:            raise ResponseNotReady()        if self.debuglevel > 0:            response = self.response_class(self.sock, self.debuglevel,                                           strict=self.strict)        else:            response = self.response_class(self.sock, strict=self.strict)        response.begin()        assert response.will_close != _UNKNOWN        self.__state = _CS_IDLE        if response.will_close:            # this effectively passes the connection to the response            self.close()        else:            # remember this, so we can tell when it is complete            self.__response = response        return response# The next several classes are used to define FakeSocket,a socket-like# interface to an SSL connection.# The primary complexity comes from faking a makefile() method.  The# standard socket makefile() implementation calls dup() on the socket# file descriptor.  As a consequence, clients can call close() on the# parent socket and its makefile children in any order.  The underlying# socket isn't closed until they are all closed.# The implementation uses reference counting to keep the socket open# until the last client calls close().  SharedSocket keeps track of# the reference counting and SharedSocketClient provides an constructor# and close() method that call incref() and decref() correctly.class SharedSocket:    def __init__(self, sock):        self.sock = sock        self._refcnt = 0    def incref(self):        self._refcnt += 1    def decref(self):        self._refcnt -= 1        assert self._refcnt >= 0        if self._refcnt == 0:            self.sock.close()    def __del__(self):        self.sock.close()class SharedSocketClient:    def __init__(self, shared):        self._closed = 0        self._shared = shared        self._shared.incref()        self._sock = shared.sock    def close(self):        if not self._closed:            self._shared.decref()            self._closed = 1            self._shared = Noneclass SSLFile(SharedSocketClient):    """File-like object wrapping an SSL socket."""    BUFSIZE = 8192    def __init__(self, sock, ssl, bufsize=None):

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?