Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 1 | # HTTP client class |
| 2 | # |
Guido van Rossum | 928fced | 1995-09-30 16:50:46 +0000 | [diff] [blame] | 3 | # See the following URL for a description of the HTTP/1.0 protocol: |
| 4 | # http://www.w3.org/hypertext/WWW/Protocols/ |
| 5 | # (I actually implemented it from a much earlier draft.) |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 6 | # |
| 7 | # Example: |
| 8 | # |
| 9 | # >>> from httplib import HTTP |
Guido van Rossum | 928fced | 1995-09-30 16:50:46 +0000 | [diff] [blame] | 10 | # >>> h = HTTP('www.python.org') |
| 11 | # >>> h.putrequest('GET', '/index.html') |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 12 | # >>> h.putheader('Accept', 'text/html') |
| 13 | # >>> h.putheader('Accept', 'text/plain') |
Guido van Rossum | 4cdcef7 | 1995-06-22 18:48:48 +0000 | [diff] [blame] | 14 | # >>> h.endheaders() |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 15 | # >>> errcode, errmsg, headers = h.getreply() |
| 16 | # >>> if errcode == 200: |
| 17 | # ... f = h.getfile() |
| 18 | # ... print f.read() # Print the raw HTML |
| 19 | # ... |
Guido van Rossum | 928fced | 1995-09-30 16:50:46 +0000 | [diff] [blame] | 20 | # <HEAD> |
| 21 | # <TITLE>Python Language Home Page</TITLE> |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 22 | # [...many more lines...] |
| 23 | # >>> |
| 24 | # |
| 25 | # Note that an HTTP object is used for a single request -- to issue a |
| 26 | # second request to the same server, you create a new HTTP object. |
| 27 | # (This is in accordance with the protocol, which uses a new TCP |
| 28 | # connection for each request.) |
| 29 | |
| 30 | |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 31 | import socket |
| 32 | import string |
Guido van Rossum | 65ab98c | 1995-08-07 20:13:02 +0000 | [diff] [blame] | 33 | import mimetools |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 34 | |
| 35 | HTTP_VERSION = 'HTTP/1.0' |
| 36 | HTTP_PORT = 80 |
| 37 | |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 38 | class HTTP: |
| 39 | |
Guido van Rossum | 2922c6d | 1994-05-06 14:28:19 +0000 | [diff] [blame] | 40 | def __init__(self, host = '', port = 0): |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 41 | self.debuglevel = 0 |
Guido van Rossum | 65ab98c | 1995-08-07 20:13:02 +0000 | [diff] [blame] | 42 | self.file = None |
Guido van Rossum | 2922c6d | 1994-05-06 14:28:19 +0000 | [diff] [blame] | 43 | if host: self.connect(host, port) |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 44 | |
| 45 | def set_debuglevel(self, debuglevel): |
| 46 | self.debuglevel = debuglevel |
| 47 | |
Guido van Rossum | 2922c6d | 1994-05-06 14:28:19 +0000 | [diff] [blame] | 48 | def connect(self, host, port = 0): |
| 49 | if not port: |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 50 | i = string.find(host, ':') |
| 51 | if i >= 0: |
| 52 | host, port = host[:i], host[i+1:] |
| 53 | try: port = string.atoi(port) |
Guido van Rossum | 928fced | 1995-09-30 16:50:46 +0000 | [diff] [blame] | 54 | except string.atoi_error: |
| 55 | raise socket.error, "nonnumeric port" |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 56 | if not port: port = HTTP_PORT |
| 57 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 58 | if self.debuglevel > 0: print 'connect:', (host, port) |
| 59 | self.sock.connect(host, port) |
| 60 | |
| 61 | def send(self, str): |
| 62 | if self.debuglevel > 0: print 'send:', `str` |
| 63 | self.sock.send(str) |
| 64 | |
| 65 | def putrequest(self, request, selector): |
Guido van Rossum | 4cdcef7 | 1995-06-22 18:48:48 +0000 | [diff] [blame] | 66 | if not selector: selector = '/' |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 67 | str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION) |
| 68 | self.send(str) |
| 69 | |
| 70 | def putheader(self, header, *args): |
| 71 | str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t')) |
| 72 | self.send(str) |
| 73 | |
| 74 | def endheaders(self): |
| 75 | self.send('\r\n') |
| 76 | |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 77 | def getreply(self): |
Jack Jansen | 2bb57b8 | 1996-02-14 16:06:24 +0000 | [diff] [blame] | 78 | self.file = self.sock.makefile('rb') |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 79 | line = self.file.readline() |
| 80 | if self.debuglevel > 0: print 'reply:', `line` |
Guido van Rossum | 2567dd6 | 1997-08-11 21:52:17 +0000 | [diff] [blame] | 81 | try: |
| 82 | [ver, code, msg] = string.split(line, None, 2) |
| 83 | except ValueError: |
| 84 | self.headers = None |
| 85 | return -1, line, self.headers |
| 86 | if ver[:5] != 'HTTP/': |
| 87 | self.headers = None |
| 88 | return -1, line, self.headers |
| 89 | errcode = string.atoi(code) |
| 90 | errmsg = string.strip(msg) |
Guido van Rossum | 65ab98c | 1995-08-07 20:13:02 +0000 | [diff] [blame] | 91 | self.headers = mimetools.Message(self.file, 0) |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 92 | return errcode, errmsg, self.headers |
| 93 | |
| 94 | def getfile(self): |
| 95 | return self.file |
| 96 | |
Guido van Rossum | 65ab98c | 1995-08-07 20:13:02 +0000 | [diff] [blame] | 97 | def close(self): |
| 98 | if self.file: |
| 99 | self.file.close() |
| 100 | self.file = None |
Guido van Rossum | 2567dd6 | 1997-08-11 21:52:17 +0000 | [diff] [blame] | 101 | if self.sock: |
| 102 | self.sock.close() |
| 103 | self.sock = None |
Guido van Rossum | 65ab98c | 1995-08-07 20:13:02 +0000 | [diff] [blame] | 104 | |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 105 | |
| 106 | def test(): |
| 107 | import sys |
| 108 | import getopt |
| 109 | opts, args = getopt.getopt(sys.argv[1:], 'd') |
| 110 | dl = 0 |
| 111 | for o, a in opts: |
| 112 | if o == '-d': dl = dl + 1 |
Guido van Rossum | a0dfc7a | 1995-09-07 19:28:19 +0000 | [diff] [blame] | 113 | host = 'www.python.org' |
| 114 | selector = '/' |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 115 | if args[0:]: host = args[0] |
| 116 | if args[1:]: selector = args[1] |
| 117 | h = HTTP() |
| 118 | h.set_debuglevel(dl) |
| 119 | h.connect(host) |
| 120 | h.putrequest('GET', selector) |
Guido van Rossum | a0dfc7a | 1995-09-07 19:28:19 +0000 | [diff] [blame] | 121 | h.endheaders() |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 122 | errcode, errmsg, headers = h.getreply() |
| 123 | print 'errcode =', errcode |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 124 | print 'errmsg =', errmsg |
Guido van Rossum | a0dfc7a | 1995-09-07 19:28:19 +0000 | [diff] [blame] | 125 | print |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 126 | if headers: |
| 127 | for header in headers.headers: print string.strip(header) |
Guido van Rossum | a0dfc7a | 1995-09-07 19:28:19 +0000 | [diff] [blame] | 128 | print |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 129 | print h.getfile().read() |
| 130 | |
Guido van Rossum | a0dfc7a | 1995-09-07 19:28:19 +0000 | [diff] [blame] | 131 | |
Guido van Rossum | 23acc95 | 1994-02-21 16:36:04 +0000 | [diff] [blame] | 132 | if __name__ == '__main__': |
| 133 | test() |