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 + -
显示快捷键?