diff options
Diffstat (limited to 'Lib/httplib.py')
-rw-r--r-- | Lib/httplib.py | 292 |
1 files changed, 174 insertions, 118 deletions
diff --git a/Lib/httplib.py b/Lib/httplib.py index fa7d2b7..7081bd1 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1,32 +1,32 @@ -# HTTP client class -# -# See the following URL for a description of the HTTP/1.0 protocol: -# http://www.w3.org/hypertext/WWW/Protocols/ -# (I actually implemented it from a much earlier draft.) -# -# Example: -# -# >>> from httplib import HTTP -# >>> h = HTTP('www.python.org') -# >>> h.putrequest('GET', '/index.html') -# >>> h.putheader('Accept', 'text/html') -# >>> h.putheader('Accept', 'text/plain') -# >>> h.endheaders() -# >>> errcode, errmsg, headers = h.getreply() -# >>> if errcode == 200: -# ... f = h.getfile() -# ... print f.read() # Print the raw HTML -# ... -# <HEAD> -# <TITLE>Python Language Home Page</TITLE> -# [...many more lines...] -# >>> -# -# Note that an HTTP object is used for a single request -- to issue a -# second request to the same server, you create a new HTTP object. -# (This is in accordance with the protocol, which uses a new TCP -# connection for each request.) - +"""HTTP client class + +See the following URL for a description of the HTTP/1.0 protocol: +http://www.w3.org/hypertext/WWW/Protocols/ +(I actually implemented it from a much earlier draft.) + +Example: + +>>> from httplib import HTTP +>>> h = HTTP('www.python.org') +>>> h.putrequest('GET', '/index.html') +>>> h.putheader('Accept', 'text/html') +>>> h.putheader('Accept', 'text/plain') +>>> h.endheaders() +>>> errcode, errmsg, headers = h.getreply() +>>> if errcode == 200: +... f = h.getfile() +... print f.read() # Print the raw HTML +... +<HEAD> +<TITLE>Python Language Home Page</TITLE> +[...many more lines...] +>>> + +Note that an HTTP object is used for a single request -- to issue a +second request to the same server, you create a new HTTP object. +(This is in accordance with the protocol, which uses a new TCP +connection for each request.) +""" import socket import string @@ -36,98 +36,154 @@ HTTP_VERSION = 'HTTP/1.0' HTTP_PORT = 80 class HTTP: - - def __init__(self, host = '', port = 0): - self.debuglevel = 0 - self.file = None - if host: self.connect(host, port) - - def set_debuglevel(self, debuglevel): - self.debuglevel = debuglevel - - def connect(self, host, port = 0): - if not port: - i = string.find(host, ':') - if i >= 0: - host, port = host[:i], host[i+1:] - try: port = string.atoi(port) - except string.atoi_error: - raise socket.error, "nonnumeric port" - if not port: port = HTTP_PORT - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - if self.debuglevel > 0: print 'connect:', (host, port) - self.sock.connect(host, port) - - def send(self, str): - if self.debuglevel > 0: print 'send:', `str` - self.sock.send(str) - - def putrequest(self, request, selector): - if not selector: selector = '/' - str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION) - self.send(str) - - def putheader(self, header, *args): - str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t')) - self.send(str) - - def endheaders(self): - self.send('\r\n') - - def getreply(self): - self.file = self.sock.makefile('rb') - line = self.file.readline() - if self.debuglevel > 0: print 'reply:', `line` - try: - [ver, code, msg] = string.split(line, None, 2) - except ValueError: - self.headers = None - return -1, line, self.headers - if ver[:5] != 'HTTP/': - self.headers = None - return -1, line, self.headers - errcode = string.atoi(code) - errmsg = string.strip(msg) - self.headers = mimetools.Message(self.file, 0) - return errcode, errmsg, self.headers - - def getfile(self): - return self.file - - def close(self): - if self.file: - self.file.close() - self.file = None - if self.sock: - self.sock.close() - self.sock = None + """This class manages a connection to an HTTP server.""" + + def __init__(self, host = '', port = 0): + """Initialize a new instance. + + If specified, `host' is the name of the remote host to which + to connect. If specified, `port' specifies the port to which + to connect. By default, httplib.HTTP_PORT is used. + + """ + self.debuglevel = 0 + self.file = None + if host: self.connect(host, port) + + def set_debuglevel(self, debuglevel): + """Set the debug output level. + + A non-false value results in debug messages for connection and + for all messages sent to and received from the server. + + """ + self.debuglevel = debuglevel + + def connect(self, host, port = 0): + """Connect to a host on a given port. + + Note: This method is automatically invoked by __init__, + if a host is specified during instantiation. + + """ + if not port: + i = string.find(host, ':') + if i >= 0: + host, port = host[:i], host[i+1:] + try: port = string.atoi(port) + except string.atoi_error: + raise socket.error, "nonnumeric port" + if not port: port = HTTP_PORT + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if self.debuglevel > 0: print 'connect:', (host, port) + self.sock.connect(host, port) + + def send(self, str): + """Send `str' to the server.""" + if self.debuglevel > 0: print 'send:', `str` + self.sock.send(str) + + def putrequest(self, request, selector): + """Send a request to the server. + + `request' specifies an HTTP request method, e.g. 'GET'. + `selector' specifies the object being requested, e.g. + '/index.html'. + + """ + if not selector: selector = '/' + str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION) + self.send(str) + + def putheader(self, header, *args): + """Send a request header line to the server. + + For example: h.putheader('Accept', 'text/html') + + """ + str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t')) + self.send(str) + + def endheaders(self): + """Indicate that the last header line has been sent to the server.""" + self.send('\r\n') + + def getreply(self): + """Get a reply from the server. + + Returns a tuple consisting of: + - server response code (e.g. '200' if all goes well) + - server response string corresponding to response code + - any RFC822 headers in the response from the server + + """ + self.file = self.sock.makefile('rb') + line = self.file.readline() + if self.debuglevel > 0: print 'reply:', `line` + try: + [ver, code, msg] = string.split(line, None, 2) + except ValueError: + self.headers = None + return -1, line, self.headers + if ver[:5] != 'HTTP/': + self.headers = None + return -1, line, self.headers + errcode = string.atoi(code) + errmsg = string.strip(msg) + self.headers = mimetools.Message(self.file, 0) + return errcode, errmsg, self.headers + + def getfile(self): + """Get a file object from which to receive data from the HTTP server. + + NOTE: This method must not be invoked until getreplies + has been invoked. + + """ + return self.file + + def close(self): + """Close the connection to the HTTP server.""" + if self.file: + self.file.close() + self.file = None + if self.sock: + self.sock.close() + self.sock = None def test(): - import sys - import getopt - opts, args = getopt.getopt(sys.argv[1:], 'd') - dl = 0 - for o, a in opts: - if o == '-d': dl = dl + 1 - host = 'www.python.org' - selector = '/' - if args[0:]: host = args[0] - if args[1:]: selector = args[1] - h = HTTP() - h.set_debuglevel(dl) - h.connect(host) - h.putrequest('GET', selector) - h.endheaders() - errcode, errmsg, headers = h.getreply() - print 'errcode =', errcode - print 'errmsg =', errmsg - print - if headers: - for header in headers.headers: print string.strip(header) - print - print h.getfile().read() + """Test this module. + + The test consists of retrieving and displaying the Python + home page, along with the error code and error string returned + by the www.python.org server. + + """ + import sys + import getopt + opts, args = getopt.getopt(sys.argv[1:], 'd') + dl = 0 + for o, a in opts: + if o == '-d': dl = dl + 1 + host = 'www.python.org' + selector = '/' + if args[0:]: host = args[0] + if args[1:]: selector = args[1] + h = HTTP() + h.set_debuglevel(dl) + h.connect(host) + h.putrequest('GET', selector) + h.endheaders() + errcode, errmsg, headers = h.getreply() + print 'errcode =', errcode + print 'errmsg =', errmsg + print + if headers: + for header in headers.headers: print string.strip(header) + print + print h.getfile().read() if __name__ == '__main__': - test() + test() |