Ditched '_find_SET()', since it was a no-value-added wrapper around
[python/dscho.git] / Lib / httplib.py
bloba43addeb4983503ff59966ce5e51fefda2cce5ef
1 """HTTP client class
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.)
7 Example:
9 >>> from httplib import HTTP
10 >>> h = HTTP('www.python.org')
11 >>> h.putrequest('GET', '/index.html')
12 >>> h.putheader('Accept', 'text/html')
13 >>> h.putheader('Accept', 'text/plain')
14 >>> h.endheaders()
15 >>> errcode, errmsg, headers = h.getreply()
16 >>> if errcode == 200:
17 ... f = h.getfile()
18 ... print f.read() # Print the raw HTML
19 ...
20 <HEAD>
21 <TITLE>Python Language Home Page</TITLE>
22 [...many more lines...]
23 >>>
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 """
31 import os
32 import socket
33 import string
34 import mimetools
36 try:
37 from cStringIO import StringIO
38 except:
39 from StringIO import StringIO
41 HTTP_VERSION = 'HTTP/1.0'
42 HTTP_PORT = 80
43 HTTPS_PORT = 443
45 class FakeSocket:
46 def __init__(self, sock, ssl):
47 self.__sock = sock
48 self.__ssl = ssl
49 return
51 def makefile(self, mode): # hopefully, never have to write
52 msgbuf = ""
53 while 1:
54 try:
55 msgbuf = msgbuf + self.__ssl.read()
56 except socket.sslerror, msg:
57 break
58 return StringIO(msgbuf)
60 def send(self, stuff, flags = 0):
61 return self.__ssl.write(stuff)
63 def recv(self, len = 1024, flags = 0):
64 return self.__ssl.read(len)
66 def __getattr__(self, attr):
67 return getattr(self.__sock, attr)
69 class HTTP:
70 """This class manages a connection to an HTTP server."""
72 def __init__(self, host = '', port = 0, **x509):
73 """Initialize a new instance.
75 If specified, `host' is the name of the remote host to which
76 to connect. If specified, `port' specifies the port to which
77 to connect. By default, httplib.HTTP_PORT is used.
79 """
80 self.key_file = x509.get('key_file')
81 self.cert_file = x509.get('cert_file')
82 self.debuglevel = 0
83 self.file = None
84 if host: self.connect(host, port)
86 def set_debuglevel(self, debuglevel):
87 """Set the debug output level.
89 A non-false value results in debug messages for connection and
90 for all messages sent to and received from the server.
92 """
93 self.debuglevel = debuglevel
95 def connect(self, host, port = 0):
96 """Connect to a host on a given port.
98 Note: This method is automatically invoked by __init__,
99 if a host is specified during instantiation.
102 if not port:
103 i = string.find(host, ':')
104 if i >= 0:
105 host, port = host[:i], host[i+1:]
106 try: port = string.atoi(port)
107 except string.atoi_error:
108 raise socket.error, "nonnumeric port"
109 if not port: port = HTTP_PORT
110 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
111 if self.debuglevel > 0: print 'connect:', (host, port)
112 self.sock.connect(host, port)
114 def send(self, str):
115 """Send `str' to the server."""
116 if self.debuglevel > 0: print 'send:', `str`
117 self.sock.send(str)
119 def putrequest(self, request, selector):
120 """Send a request to the server.
122 `request' specifies an HTTP request method, e.g. 'GET'.
123 `selector' specifies the object being requested, e.g.
124 '/index.html'.
127 if not selector: selector = '/'
128 str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION)
129 self.send(str)
131 def putheader(self, header, *args):
132 """Send a request header line to the server.
134 For example: h.putheader('Accept', 'text/html')
137 str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t'))
138 self.send(str)
140 def endheaders(self):
141 """Indicate that the last header line has been sent to the server."""
142 self.send('\r\n')
144 def getreply(self):
145 """Get a reply from the server.
147 Returns a tuple consisting of:
148 - server response code (e.g. '200' if all goes well)
149 - server response string corresponding to response code
150 - any RFC822 headers in the response from the server
153 self.file = self.sock.makefile('rb')
154 line = self.file.readline()
155 if self.debuglevel > 0: print 'reply:', `line`
156 try:
157 [ver, code, msg] = string.split(line, None, 2)
158 except ValueError:
159 try:
160 [ver, code] = string.split(line, None, 1)
161 msg = ""
162 except ValueError:
163 self.headers = None
164 return -1, line, self.headers
165 if ver[:5] != 'HTTP/':
166 self.headers = None
167 return -1, line, self.headers
168 errcode = string.atoi(code)
169 errmsg = string.strip(msg)
170 self.headers = mimetools.Message(self.file, 0)
171 return errcode, errmsg, self.headers
173 def getfile(self):
174 """Get a file object from which to receive data from the HTTP server.
176 NOTE: This method must not be invoked until getreplies
177 has been invoked.
180 return self.file
182 def close(self):
183 """Close the connection to the HTTP server."""
184 if self.file:
185 self.file.close()
186 self.file = None
187 if self.sock:
188 self.sock.close()
189 self.sock = None
191 if hasattr(socket, "ssl"):
192 class HTTPS(HTTP):
193 """This class allows communication via SSL."""
195 def connect(self, host, port = 0):
196 """Connect to a host on a given port.
198 Note: This method is automatically invoked by __init__,
199 if a host is specified during instantiation.
202 if not port:
203 i = string.find(host, ':')
204 if i >= 0:
205 host, port = host[:i], host[i+1:]
206 try: port = string.atoi(port)
207 except string.atoi_error:
208 raise socket.error, "nonnumeric port"
209 if not port: port = HTTPS_PORT
210 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
211 if self.debuglevel > 0: print 'connect:', (host, port)
212 sock.connect(host, port)
213 ssl = socket.ssl(sock, self.key_file, self.cert_file)
214 self.sock = FakeSocket(sock, ssl)
217 def test():
218 """Test this module.
220 The test consists of retrieving and displaying the Python
221 home page, along with the error code and error string returned
222 by the www.python.org server.
225 import sys
226 import getopt
227 opts, args = getopt.getopt(sys.argv[1:], 'd')
228 dl = 0
229 for o, a in opts:
230 if o == '-d': dl = dl + 1
231 print "testing HTTP..."
232 host = 'www.python.org'
233 selector = '/'
234 if args[0:]: host = args[0]
235 if args[1:]: selector = args[1]
236 h = HTTP()
237 h.set_debuglevel(dl)
238 h.connect(host)
239 h.putrequest('GET', selector)
240 h.endheaders()
241 errcode, errmsg, headers = h.getreply()
242 print 'errcode =', errcode
243 print 'errmsg =', errmsg
244 print
245 if headers:
246 for header in headers.headers: print string.strip(header)
247 print
248 print h.getfile().read()
249 if hasattr(socket, "ssl"):
250 print "-"*40
251 print "testing HTTPS..."
252 host = 'synergy.as.cmu.edu'
253 selector = '/~geek/'
254 if args[0:]: host = args[0]
255 if args[1:]: selector = args[1]
256 h = HTTPS()
257 h.set_debuglevel(dl)
258 h.connect(host)
259 h.putrequest('GET', selector)
260 h.endheaders()
261 errcode, errmsg, headers = h.getreply()
262 print 'errcode =', errcode
263 print 'errmsg =', errmsg
264 print
265 if headers:
266 for header in headers.headers: print string.strip(header)
267 print
268 print h.getfile().read()
271 if __name__ == '__main__':
272 test()