📄 httplib.py
字号:
# Portions Copyright (c) 2005 - 2007 Nokia Corporation
"""HTTP/1.1 client library"""
import errno
import mimetools
import socket
import e32
from urlparse import urlsplit
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
__all__ = ["HTTP", "HTTPResponse", "HTTPConnection", "HTTPSConnection",
"HTTPException", "NotConnected", "UnknownProtocol",
"UnknownTransferEncoding", "UnimplementedFileMode",
"IncompleteRead", "InvalidURL", "ImproperConnectionState",
"CannotSendRequest", "CannotSendHeader", "ResponseNotReady",
"BadStatusLine", "error"]
HTTP_PORT = 80
HTTPS_PORT = 443
_UNKNOWN = 'UNKNOWN'
# connection states
_CS_IDLE = 'Idle'
_CS_REQ_STARTED = 'Request-started'
_CS_REQ_SENT = 'Request-sent'
class HTTPMessage(mimetools.Message):
def addheader(self, key, value):
prev = self.dict.get(key)
if prev is None:
self.dict[key] = value
else:
combined = ", ".join((prev, value))
self.dict[key] = combined
def addcontinue(self, key, more):
prev = self.dict[key]
self.dict[key] = prev + "\n " + more
def readheaders(self):
self.dict = {}
self.unixfrom = ''
self.headers = list = []
self.status = ''
headerseen = ""
firstline = 1
startofline = unread = tell = None
if hasattr(self.fp, 'unread'):
unread = self.fp.unread
elif self.seekable:
tell = self.fp.tell
while 1:
if tell:
try:
startofline = tell()
except IOError:
startofline = tell = None
self.seekable = 0
line = self.fp.readline()
if not line:
self.status = 'EOF in headers'
break
if firstline and line.startswith('From '):
self.unixfrom = self.unixfrom + line
continue
firstline = 0
if headerseen and line[0] in ' \t':
list.append(line)
x = self.dict[headerseen] + "\n " + line.strip()
self.addcontinue(headerseen, line.strip())
continue
elif self.iscomment(line):
continue
elif self.islast(line):
break
headerseen = self.isheader(line)
if headerseen:
list.append(line)
self.addheader(headerseen, line[len(headerseen)+1:].strip())
continue
else:
if not self.dict:
self.status = 'No headers'
else:
self.status = 'Non-header line where header expected'
if unread:
unread(line)
elif tell:
self.fp.seek(startofline)
else:
self.status = self.status + '; bad seek'
break
class HTTPResponse:
def __init__(self, sock, debuglevel=0, strict=0):
self.fp = sock.makefile('rb', 0)
self.debuglevel = debuglevel
self.strict = strict
self.msg = None
self.version = _UNKNOWN
self.status = _UNKNOWN
self.reason = _UNKNOWN
self.chunked = _UNKNOWN
self.chunk_left = _UNKNOWN
self.length = _UNKNOWN
self.will_close = _UNKNOWN
def _read_status(self):
line = self.fp.readline()
if self.debuglevel > 0:
print "reply:", repr(line)
try:
[version, status, reason] = line.split(None, 2)
except ValueError:
try:
[version, status] = line.split(None, 1)
reason = ""
except ValueError:
version = ""
if not version.startswith('HTTP/'):
if self.strict:
self.close()
raise BadStatusLine(line)
else:
self.fp = LineAndFileWrapper(line, self.fp)
return "HTTP/0.9", 200, ""
try:
status = int(status)
if status < 100 or status > 999:
raise BadStatusLine(line)
except ValueError:
raise BadStatusLine(line)
return version, status, reason
def begin(self):
if self.msg is not None:
return
while 1:
version, status, reason = self._read_status()
if status != 100:
break
while 1:
skip = self.fp.readline().strip()
if not skip:
break
if self.debuglevel > 0:
print "header:", skip
self.status = status
self.reason = reason.strip()
if version == 'HTTP/1.0':
self.version = 10
elif version.startswith('HTTP/1.'):
self.version = 11
elif version == 'HTTP/0.9':
self.version = 9
else:
raise UnknownProtocol(version)
if self.version == 9:
self.chunked = 0
self.will_close = 1
self.msg = HTTPMessage(StringIO())
return
self.msg = HTTPMessage(self.fp, 0)
if self.debuglevel > 0:
for hdr in self.msg.headers:
print "header:", hdr,
self.msg.fp = None
tr_enc = self.msg.getheader('transfer-encoding')
if tr_enc and tr_enc.lower() == "chunked":
self.chunked = 1
self.chunk_left = None
else:
self.chunked = 0
conn = self.msg.getheader('connection')
if conn:
conn = conn.lower()
self.will_close = conn.find('close') != -1 or \
( self.version != 11 and \
not self.msg.getheader('keep-alive') )
else:
self.will_close = self.version != 11 and \
not self.msg.getheader('keep-alive')
length = self.msg.getheader('content-length')
if length and not self.chunked:
try:
self.length = int(length)
except ValueError:
self.length = None
else:
self.length = None
if (status == 204 or
status == 304 or
100 <= status < 200):
self.length = 0
if not self.will_close and \
not self.chunked and \
self.length is None:
self.will_close = 1
def close(self):
if self.fp:
self.fp.close()
self.fp = None
def isclosed(self):
return self.fp is None
def read(self, amt=None):
if self.fp is None:
return ''
if self.chunked:
return self._read_chunked(amt)
if amt is None:
if self.will_close:
s = self.fp.read()
else:
s = self._safe_read(self.length)
self.close()
return s
if self.length is not None:
if amt > self.length:
amt = self.length
self.length -= amt
s = self.fp.read(amt)
return s
def _read_chunked(self, amt):
assert self.chunked != _UNKNOWN
chunk_left = self.chunk_left
value = ''
while 1:
if chunk_left is None:
line = self.fp.readline()
i = line.find(';')
if i >= 0:
line = line[:i]
chunk_left = int(line, 16)
if chunk_left == 0:
break
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)
self.chunk_left = None
return value
else:
value += self._safe_read(chunk_left)
amt -= chunk_left
self._safe_read(2)
chunk_left = None
while 1:
line = self.fp.readline()
if line == '\r\n':
break
self.close()
return value
def _safe_read(self, amt):
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, hostname=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
if hostname is not None:
self.hostname = hostname
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):
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):
if self.sock:
self.sock.close()
self.sock = None
if self.__response:
self.__response.close()
self.__response = None
self.__state = _CS_IDLE
def send(self, str):
if self.sock is None:
if self.auto_open:
self.connect()
else:
raise NotConnected()
if self.debuglevel > 0:
print "send:", repr(str)
try:
self.sock.sendall(str)
except socket.error, v:
if v[0] == 32:
self.close()
raise
def _output(self, s):
self._buffer.append(s)
def _send_output(self):
self._buffer.extend(("", ""))
msg = "\r\n".join(self._buffer)
del self._buffer[:]
self.send(msg)
def putrequest(self, method, url, skip_host=0):
if self.__response and self.__response.isclosed():
self.__response = None
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -