blob: 2faf3189fad3c5c9213a5b8471d04b460e0a9d4c [file] [log] [blame]
Greg Stein5e0fa402000-06-26 08:28:01 +00001"""HTTP/1.1 client library
Guido van Rossum41999c11997-12-09 00:12:23 +00002
Greg Stein5e0fa402000-06-26 08:28:01 +00003<intro stuff goes here>
4<other stuff, too>
Guido van Rossum41999c11997-12-09 00:12:23 +00005
Greg Stein5e0fa402000-06-26 08:28:01 +00006HTTPConnection go through a number of "states", which defines when a client
7may legally make another request or fetch the response for a particular
8request. This diagram details these state transitions:
Guido van Rossum41999c11997-12-09 00:12:23 +00009
Greg Stein5e0fa402000-06-26 08:28:01 +000010 (null)
11 |
12 | HTTPConnection()
13 v
14 Idle
15 |
16 | putrequest()
17 v
18 Request-started
19 |
20 | ( putheader() )* endheaders()
21 v
22 Request-sent
23 |
24 | response = getresponse()
25 v
26 Unread-response [Response-headers-read]
27 |\____________________
Tim Peters5ceadc82001-01-13 19:16:21 +000028 | |
29 | response.read() | putrequest()
30 v v
31 Idle Req-started-unread-response
32 ______/|
33 / |
34 response.read() | | ( putheader() )* endheaders()
35 v v
36 Request-started Req-sent-unread-response
37 |
38 | response.read()
39 v
40 Request-sent
Greg Stein5e0fa402000-06-26 08:28:01 +000041
42This diagram presents the following rules:
43 -- a second request may not be started until {response-headers-read}
44 -- a response [object] cannot be retrieved until {request-sent}
45 -- there is no differentiation between an unread response body and a
46 partially read response body
47
48Note: this enforcement is applied by the HTTPConnection class. The
49 HTTPResponse class does not enforce this state machine, which
50 implies sophisticated clients may accelerate the request/response
51 pipeline. Caution should be taken, though: accelerating the states
52 beyond the above pattern may imply knowledge of the server's
53 connection-close behavior for certain requests. For example, it
54 is impossible to tell whether the server will close the connection
55 UNTIL the response headers have been read; this means that further
56 requests cannot be placed into the pipeline until it is known that
57 the server will NOT be closing the connection.
58
59Logical State __state __response
60------------- ------- ----------
61Idle _CS_IDLE None
62Request-started _CS_REQ_STARTED None
63Request-sent _CS_REQ_SENT None
64Unread-response _CS_IDLE <response_class>
65Req-started-unread-response _CS_REQ_STARTED <response_class>
66Req-sent-unread-response _CS_REQ_SENT <response_class>
Guido van Rossum41999c11997-12-09 00:12:23 +000067"""
Guido van Rossum23acc951994-02-21 16:36:04 +000068
Jeremy Hylton6459c8d2001-10-11 17:47:22 +000069import errno
Guido van Rossum65ab98c1995-08-07 20:13:02 +000070import mimetools
Jeremy Hylton6459c8d2001-10-11 17:47:22 +000071import socket
Jeremy Hylton8acf1e02002-03-08 19:35:51 +000072from urlparse import urlsplit
Guido van Rossum23acc951994-02-21 16:36:04 +000073
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000074try:
Greg Steindd6eefb2000-07-18 09:09:48 +000075 from cStringIO import StringIO
Greg Stein5e0fa402000-06-26 08:28:01 +000076except ImportError:
Greg Steindd6eefb2000-07-18 09:09:48 +000077 from StringIO import StringIO
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000078
Skip Montanaro951a8842001-06-01 16:25:38 +000079__all__ = ["HTTP", "HTTPResponse", "HTTPConnection", "HTTPSConnection",
80 "HTTPException", "NotConnected", "UnknownProtocol",
81 "UnknownTransferEncoding", "IllegalKeywordArgument",
Skip Montanarof3f87f72002-03-24 16:56:45 +000082 "UnimplementedFileMode", "IncompleteRead", "InvalidURL",
Skip Montanaro951a8842001-06-01 16:25:38 +000083 "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader",
84 "ResponseNotReady", "BadStatusLine", "error"]
Skip Montanaro2dd42762001-01-23 15:35:05 +000085
Guido van Rossum23acc951994-02-21 16:36:04 +000086HTTP_PORT = 80
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000087HTTPS_PORT = 443
88
Greg Stein5e0fa402000-06-26 08:28:01 +000089_UNKNOWN = 'UNKNOWN'
90
91# connection states
92_CS_IDLE = 'Idle'
93_CS_REQ_STARTED = 'Request-started'
94_CS_REQ_SENT = 'Request-sent'
95
96
97class HTTPResponse:
Jeremy Hylton30f86742000-09-18 22:50:38 +000098 def __init__(self, sock, debuglevel=0):
Greg Steindd6eefb2000-07-18 09:09:48 +000099 self.fp = sock.makefile('rb', 0)
Jeremy Hylton30f86742000-09-18 22:50:38 +0000100 self.debuglevel = debuglevel
Greg Stein5e0fa402000-06-26 08:28:01 +0000101
Greg Steindd6eefb2000-07-18 09:09:48 +0000102 self.msg = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000103
Greg Steindd6eefb2000-07-18 09:09:48 +0000104 # from the Status-Line of the response
Tim Peters07e99cb2001-01-14 23:47:14 +0000105 self.version = _UNKNOWN # HTTP-Version
106 self.status = _UNKNOWN # Status-Code
107 self.reason = _UNKNOWN # Reason-Phrase
Greg Stein5e0fa402000-06-26 08:28:01 +0000108
Tim Peters07e99cb2001-01-14 23:47:14 +0000109 self.chunked = _UNKNOWN # is "chunked" being used?
110 self.chunk_left = _UNKNOWN # bytes left to read in current chunk
111 self.length = _UNKNOWN # number of bytes left in response
112 self.will_close = _UNKNOWN # conn will close at end of response
Greg Stein5e0fa402000-06-26 08:28:01 +0000113
Greg Steindd6eefb2000-07-18 09:09:48 +0000114 def begin(self):
115 if self.msg is not None:
116 # we've already started reading the response
117 return
Greg Stein5e0fa402000-06-26 08:28:01 +0000118
Greg Stein5e0fa402000-06-26 08:28:01 +0000119 line = self.fp.readline()
Jeremy Hylton30f86742000-09-18 22:50:38 +0000120 if self.debuglevel > 0:
121 print "reply:", repr(line)
Greg Steindd6eefb2000-07-18 09:09:48 +0000122 try:
Guido van Rossum34735a62000-12-15 15:09:42 +0000123 [version, status, reason] = line.split(None, 2)
Greg Steindd6eefb2000-07-18 09:09:48 +0000124 except ValueError:
125 try:
Guido van Rossum34735a62000-12-15 15:09:42 +0000126 [version, status] = line.split(None, 1)
Greg Steindd6eefb2000-07-18 09:09:48 +0000127 reason = ""
128 except ValueError:
Jeremy Hylton110941a2000-10-12 19:58:36 +0000129 version = "HTTP/0.9"
130 status = "200"
131 reason = ""
Greg Steindd6eefb2000-07-18 09:09:48 +0000132 if version[:5] != 'HTTP/':
133 self.close()
134 raise BadStatusLine(line)
Greg Stein5e0fa402000-06-26 08:28:01 +0000135
Jeremy Hylton23d40472001-04-13 14:57:08 +0000136 # The status code is a three-digit number
137 try:
138 self.status = status = int(status)
139 if status < 100 or status > 999:
140 raise BadStatusLine(line)
141 except ValueError:
142 raise BadStatusLine(line)
Guido van Rossum34735a62000-12-15 15:09:42 +0000143 self.reason = reason.strip()
Greg Stein5e0fa402000-06-26 08:28:01 +0000144
Greg Steindd6eefb2000-07-18 09:09:48 +0000145 if version == 'HTTP/1.0':
146 self.version = 10
Jeremy Hylton110941a2000-10-12 19:58:36 +0000147 elif version.startswith('HTTP/1.'):
Tim Peters07e99cb2001-01-14 23:47:14 +0000148 self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
Jeremy Hylton110941a2000-10-12 19:58:36 +0000149 elif version == 'HTTP/0.9':
150 self.version = 9
Greg Steindd6eefb2000-07-18 09:09:48 +0000151 else:
152 raise UnknownProtocol(version)
Greg Stein5e0fa402000-06-26 08:28:01 +0000153
Jeremy Hylton110941a2000-10-12 19:58:36 +0000154 if self.version == 9:
155 self.msg = mimetools.Message(StringIO())
156 return
157
Greg Steindd6eefb2000-07-18 09:09:48 +0000158 self.msg = mimetools.Message(self.fp, 0)
Jeremy Hylton30f86742000-09-18 22:50:38 +0000159 if self.debuglevel > 0:
160 for hdr in self.msg.headers:
161 print "header:", hdr,
Greg Stein5e0fa402000-06-26 08:28:01 +0000162
Greg Steindd6eefb2000-07-18 09:09:48 +0000163 # don't let the msg keep an fp
164 self.msg.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000165
Greg Steindd6eefb2000-07-18 09:09:48 +0000166 # are we using the chunked-style of transfer encoding?
167 tr_enc = self.msg.getheader('transfer-encoding')
168 if tr_enc:
Guido van Rossum34735a62000-12-15 15:09:42 +0000169 if tr_enc.lower() != 'chunked':
Greg Steindd6eefb2000-07-18 09:09:48 +0000170 raise UnknownTransferEncoding()
171 self.chunked = 1
172 self.chunk_left = None
173 else:
174 self.chunked = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000175
Greg Steindd6eefb2000-07-18 09:09:48 +0000176 # will the connection close at the end of the response?
177 conn = self.msg.getheader('connection')
178 if conn:
Guido van Rossum34735a62000-12-15 15:09:42 +0000179 conn = conn.lower()
Greg Steindd6eefb2000-07-18 09:09:48 +0000180 # a "Connection: close" will always close the connection. if we
181 # don't see that and this is not HTTP/1.1, then the connection will
182 # close unless we see a Keep-Alive header.
Guido van Rossum34735a62000-12-15 15:09:42 +0000183 self.will_close = conn.find('close') != -1 or \
Greg Steindd6eefb2000-07-18 09:09:48 +0000184 ( self.version != 11 and \
185 not self.msg.getheader('keep-alive') )
186 else:
187 # for HTTP/1.1, the connection will always remain open
188 # otherwise, it will remain open IFF we see a Keep-Alive header
189 self.will_close = self.version != 11 and \
190 not self.msg.getheader('keep-alive')
Greg Stein5e0fa402000-06-26 08:28:01 +0000191
Greg Steindd6eefb2000-07-18 09:09:48 +0000192 # do we have a Content-Length?
193 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
194 length = self.msg.getheader('content-length')
195 if length and not self.chunked:
Jeremy Hylton30a81812000-09-14 20:34:27 +0000196 try:
197 self.length = int(length)
198 except ValueError:
199 self.length = None
Greg Steindd6eefb2000-07-18 09:09:48 +0000200 else:
201 self.length = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000202
Greg Steindd6eefb2000-07-18 09:09:48 +0000203 # does the body have a fixed length? (of zero)
Tim Peters07e99cb2001-01-14 23:47:14 +0000204 if (status == 204 or # No Content
205 status == 304 or # Not Modified
206 100 <= status < 200): # 1xx codes
Greg Steindd6eefb2000-07-18 09:09:48 +0000207 self.length = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000208
Greg Steindd6eefb2000-07-18 09:09:48 +0000209 # if the connection remains open, and we aren't using chunked, and
210 # a content-length was not provided, then assume that the connection
211 # WILL close.
212 if not self.will_close and \
213 not self.chunked and \
214 self.length is None:
215 self.will_close = 1
Greg Stein5e0fa402000-06-26 08:28:01 +0000216
Greg Steindd6eefb2000-07-18 09:09:48 +0000217 def close(self):
218 if self.fp:
219 self.fp.close()
220 self.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000221
Greg Steindd6eefb2000-07-18 09:09:48 +0000222 def isclosed(self):
223 # NOTE: it is possible that we will not ever call self.close(). This
224 # case occurs when will_close is TRUE, length is None, and we
225 # read up to the last byte, but NOT past it.
226 #
227 # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
228 # called, meaning self.isclosed() is meaningful.
229 return self.fp is None
230
231 def read(self, amt=None):
232 if self.fp is None:
233 return ''
234
235 if self.chunked:
236 chunk_left = self.chunk_left
237 value = ''
238 while 1:
239 if chunk_left is None:
240 line = self.fp.readline()
Guido van Rossum34735a62000-12-15 15:09:42 +0000241 i = line.find(';')
Greg Steindd6eefb2000-07-18 09:09:48 +0000242 if i >= 0:
Tim Peters07e99cb2001-01-14 23:47:14 +0000243 line = line[:i] # strip chunk-extensions
Guido van Rossum34735a62000-12-15 15:09:42 +0000244 chunk_left = int(line, 16)
Greg Steindd6eefb2000-07-18 09:09:48 +0000245 if chunk_left == 0:
246 break
247 if amt is None:
248 value = value + self._safe_read(chunk_left)
249 elif amt < chunk_left:
250 value = value + self._safe_read(amt)
251 self.chunk_left = chunk_left - amt
252 return value
253 elif amt == chunk_left:
254 value = value + self._safe_read(amt)
Tim Peters07e99cb2001-01-14 23:47:14 +0000255 self._safe_read(2) # toss the CRLF at the end of the chunk
Greg Steindd6eefb2000-07-18 09:09:48 +0000256 self.chunk_left = None
257 return value
258 else:
259 value = value + self._safe_read(chunk_left)
260 amt = amt - chunk_left
261
262 # we read the whole chunk, get another
Tim Peters07e99cb2001-01-14 23:47:14 +0000263 self._safe_read(2) # toss the CRLF at the end of the chunk
Greg Steindd6eefb2000-07-18 09:09:48 +0000264 chunk_left = None
265
266 # read and discard trailer up to the CRLF terminator
267 ### note: we shouldn't have any trailers!
268 while 1:
269 line = self.fp.readline()
270 if line == '\r\n':
271 break
272
273 # we read everything; close the "file"
274 self.close()
275
276 return value
277
278 elif amt is None:
279 # unbounded read
280 if self.will_close:
281 s = self.fp.read()
282 else:
283 s = self._safe_read(self.length)
Tim Peters07e99cb2001-01-14 23:47:14 +0000284 self.close() # we read everything
Greg Steindd6eefb2000-07-18 09:09:48 +0000285 return s
286
287 if self.length is not None:
288 if amt > self.length:
289 # clip the read to the "end of response"
290 amt = self.length
291 self.length = self.length - amt
292
293 # we do not use _safe_read() here because this may be a .will_close
294 # connection, and the user is reading more bytes than will be provided
295 # (for example, reading in 1k chunks)
296 s = self.fp.read(amt)
297
Greg Steindd6eefb2000-07-18 09:09:48 +0000298 return s
299
300 def _safe_read(self, amt):
301 """Read the number of bytes requested, compensating for partial reads.
302
303 Normally, we have a blocking socket, but a read() can be interrupted
304 by a signal (resulting in a partial read).
305
306 Note that we cannot distinguish between EOF and an interrupt when zero
307 bytes have been read. IncompleteRead() will be raised in this
308 situation.
309
310 This function should be used when <amt> bytes "should" be present for
311 reading. If the bytes are truly not available (due to EOF), then the
312 IncompleteRead exception can be used to detect the problem.
313 """
314 s = ''
315 while amt > 0:
316 chunk = self.fp.read(amt)
317 if not chunk:
318 raise IncompleteRead(s)
319 s = s + chunk
320 amt = amt - len(chunk)
321 return s
322
323 def getheader(self, name, default=None):
324 if self.msg is None:
325 raise ResponseNotReady()
326 return self.msg.getheader(name, default)
Greg Stein5e0fa402000-06-26 08:28:01 +0000327
328
329class HTTPConnection:
330
Greg Steindd6eefb2000-07-18 09:09:48 +0000331 _http_vsn = 11
332 _http_vsn_str = 'HTTP/1.1'
Greg Stein5e0fa402000-06-26 08:28:01 +0000333
Greg Steindd6eefb2000-07-18 09:09:48 +0000334 response_class = HTTPResponse
335 default_port = HTTP_PORT
336 auto_open = 1
Jeremy Hylton30f86742000-09-18 22:50:38 +0000337 debuglevel = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000338
Greg Steindd6eefb2000-07-18 09:09:48 +0000339 def __init__(self, host, port=None):
340 self.sock = None
341 self.__response = None
342 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000343
Greg Steindd6eefb2000-07-18 09:09:48 +0000344 self._set_hostport(host, port)
Greg Stein5e0fa402000-06-26 08:28:01 +0000345
Greg Steindd6eefb2000-07-18 09:09:48 +0000346 def _set_hostport(self, host, port):
347 if port is None:
Guido van Rossum34735a62000-12-15 15:09:42 +0000348 i = host.find(':')
Greg Steindd6eefb2000-07-18 09:09:48 +0000349 if i >= 0:
Skip Montanaro9d389972002-03-24 16:53:50 +0000350 try:
351 port = int(host[i+1:])
352 except ValueError:
353 raise InvalidURL, "nonnumeric port: '%s'"%host[i+1:]
Greg Steindd6eefb2000-07-18 09:09:48 +0000354 host = host[:i]
355 else:
356 port = self.default_port
357 self.host = host
358 self.port = port
Greg Stein5e0fa402000-06-26 08:28:01 +0000359
Jeremy Hylton30f86742000-09-18 22:50:38 +0000360 def set_debuglevel(self, level):
361 self.debuglevel = level
362
Greg Steindd6eefb2000-07-18 09:09:48 +0000363 def connect(self):
364 """Connect to the host and port specified in __init__."""
Martin v. Löwis2ad25692001-07-31 08:40:21 +0000365 msg = "getaddrinfo returns an empty list"
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000366 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
367 af, socktype, proto, canonname, sa = res
368 try:
369 self.sock = socket.socket(af, socktype, proto)
370 if self.debuglevel > 0:
371 print "connect: (%s, %s)" % (self.host, self.port)
372 self.sock.connect(sa)
373 except socket.error, msg:
374 if self.debuglevel > 0:
375 print 'connect fail:', (self.host, self.port)
Martin v. Löwis322c0d12001-10-07 08:53:32 +0000376 if self.sock:
377 self.sock.close()
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000378 self.sock = None
379 continue
380 break
381 if not self.sock:
382 raise socket.error, msg
Greg Stein5e0fa402000-06-26 08:28:01 +0000383
Greg Steindd6eefb2000-07-18 09:09:48 +0000384 def close(self):
385 """Close the connection to the HTTP server."""
386 if self.sock:
Tim Peters07e99cb2001-01-14 23:47:14 +0000387 self.sock.close() # close it manually... there may be other refs
Greg Steindd6eefb2000-07-18 09:09:48 +0000388 self.sock = None
389 if self.__response:
390 self.__response.close()
391 self.__response = None
392 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000393
Greg Steindd6eefb2000-07-18 09:09:48 +0000394 def send(self, str):
395 """Send `str' to the server."""
396 if self.sock is None:
397 if self.auto_open:
398 self.connect()
399 else:
400 raise NotConnected()
Greg Stein5e0fa402000-06-26 08:28:01 +0000401
Greg Steindd6eefb2000-07-18 09:09:48 +0000402 # send the data to the server. if we get a broken pipe, then close
403 # the socket. we want to reconnect when somebody tries to send again.
404 #
405 # NOTE: we DO propagate the error, though, because we cannot simply
406 # ignore the error... the caller will know if they can retry.
Jeremy Hylton30f86742000-09-18 22:50:38 +0000407 if self.debuglevel > 0:
408 print "send:", repr(str)
Greg Steindd6eefb2000-07-18 09:09:48 +0000409 try:
Martin v. Löwise12454f2002-02-16 23:06:19 +0000410 self.sock.sendall(str)
Greg Steindd6eefb2000-07-18 09:09:48 +0000411 except socket.error, v:
Tim Peters07e99cb2001-01-14 23:47:14 +0000412 if v[0] == 32: # Broken pipe
Greg Steindd6eefb2000-07-18 09:09:48 +0000413 self.close()
414 raise
Greg Stein5e0fa402000-06-26 08:28:01 +0000415
Jeremy Hylton3921ff62002-03-09 06:07:23 +0000416 def putrequest(self, method, url, skip_host=0):
Greg Steindd6eefb2000-07-18 09:09:48 +0000417 """Send a request to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000418
Greg Steindd6eefb2000-07-18 09:09:48 +0000419 `method' specifies an HTTP request method, e.g. 'GET'.
420 `url' specifies the object being requested, e.g. '/index.html'.
421 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000422
Greg Steindd6eefb2000-07-18 09:09:48 +0000423 # check if a prior response has been completed
424 if self.__response and self.__response.isclosed():
425 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000426
Greg Steindd6eefb2000-07-18 09:09:48 +0000427 #
428 # in certain cases, we cannot issue another request on this connection.
429 # this occurs when:
430 # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
431 # 2) a response to a previous request has signalled that it is going
432 # to close the connection upon completion.
433 # 3) the headers for the previous response have not been read, thus
434 # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
435 #
436 # if there is no prior response, then we can request at will.
437 #
438 # if point (2) is true, then we will have passed the socket to the
439 # response (effectively meaning, "there is no prior response"), and
440 # will open a new one when a new request is made.
441 #
442 # Note: if a prior response exists, then we *can* start a new request.
443 # We are not allowed to begin fetching the response to this new
444 # request, however, until that prior response is complete.
445 #
446 if self.__state == _CS_IDLE:
447 self.__state = _CS_REQ_STARTED
448 else:
449 raise CannotSendRequest()
Greg Stein5e0fa402000-06-26 08:28:01 +0000450
Greg Steindd6eefb2000-07-18 09:09:48 +0000451 if not url:
452 url = '/'
453 str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000454
Greg Steindd6eefb2000-07-18 09:09:48 +0000455 try:
456 self.send(str)
457 except socket.error, v:
458 # trap 'Broken pipe' if we're allowed to automatically reconnect
459 if v[0] != 32 or not self.auto_open:
460 raise
461 # try one more time (the socket was closed; this will reopen)
462 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000463
Greg Steindd6eefb2000-07-18 09:09:48 +0000464 if self._http_vsn == 11:
465 # Issue some standard headers for better HTTP/1.1 compliance
Greg Stein5e0fa402000-06-26 08:28:01 +0000466
Jeremy Hylton3921ff62002-03-09 06:07:23 +0000467 if not skip_host:
468 # this header is issued *only* for HTTP/1.1
469 # connections. more specifically, this means it is
470 # only issued when the client uses the new
471 # HTTPConnection() class. backwards-compat clients
472 # will be using HTTP/1.0 and those clients may be
473 # issuing this header themselves. we should NOT issue
474 # it twice; some web servers (such as Apache) barf
475 # when they see two Host: headers
Guido van Rossumf6922aa2001-01-14 21:03:01 +0000476
Jeremy Hylton3921ff62002-03-09 06:07:23 +0000477 # If we need a non-standard port,include it in the
478 # header. If the request is going through a proxy,
479 # but the host of the actual URL, not the host of the
480 # proxy.
Jeremy Hylton8acf1e02002-03-08 19:35:51 +0000481
Jeremy Hylton3921ff62002-03-09 06:07:23 +0000482 netloc = ''
483 if url.startswith('http'):
484 nil, netloc, nil, nil, nil = urlsplit(url)
485
486 if netloc:
487 self.putheader('Host', netloc)
488 elif self.port == HTTP_PORT:
489 self.putheader('Host', self.host)
490 else:
491 self.putheader('Host', "%s:%s" % (self.host, self.port))
Greg Stein5e0fa402000-06-26 08:28:01 +0000492
Greg Steindd6eefb2000-07-18 09:09:48 +0000493 # note: we are assuming that clients will not attempt to set these
494 # headers since *this* library must deal with the
495 # consequences. this also means that when the supporting
496 # libraries are updated to recognize other forms, then this
497 # code should be changed (removed or updated).
Greg Stein5e0fa402000-06-26 08:28:01 +0000498
Greg Steindd6eefb2000-07-18 09:09:48 +0000499 # we only want a Content-Encoding of "identity" since we don't
500 # support encodings such as x-gzip or x-deflate.
501 self.putheader('Accept-Encoding', 'identity')
Greg Stein5e0fa402000-06-26 08:28:01 +0000502
Greg Steindd6eefb2000-07-18 09:09:48 +0000503 # we can accept "chunked" Transfer-Encodings, but no others
504 # NOTE: no TE header implies *only* "chunked"
505 #self.putheader('TE', 'chunked')
Greg Stein5e0fa402000-06-26 08:28:01 +0000506
Greg Steindd6eefb2000-07-18 09:09:48 +0000507 # if TE is supplied in the header, then it must appear in a
508 # Connection header.
509 #self.putheader('Connection', 'TE')
Greg Stein5e0fa402000-06-26 08:28:01 +0000510
Greg Steindd6eefb2000-07-18 09:09:48 +0000511 else:
512 # For HTTP/1.0, the server will assume "not chunked"
513 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000514
Greg Steindd6eefb2000-07-18 09:09:48 +0000515 def putheader(self, header, value):
516 """Send a request header line to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000517
Greg Steindd6eefb2000-07-18 09:09:48 +0000518 For example: h.putheader('Accept', 'text/html')
519 """
520 if self.__state != _CS_REQ_STARTED:
521 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000522
Greg Steindd6eefb2000-07-18 09:09:48 +0000523 str = '%s: %s\r\n' % (header, value)
524 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000525
Greg Steindd6eefb2000-07-18 09:09:48 +0000526 def endheaders(self):
527 """Indicate that the last header line has been sent to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000528
Greg Steindd6eefb2000-07-18 09:09:48 +0000529 if self.__state == _CS_REQ_STARTED:
530 self.__state = _CS_REQ_SENT
531 else:
532 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000533
Greg Steindd6eefb2000-07-18 09:09:48 +0000534 self.send('\r\n')
Greg Stein5e0fa402000-06-26 08:28:01 +0000535
Greg Steindd6eefb2000-07-18 09:09:48 +0000536 def request(self, method, url, body=None, headers={}):
537 """Send a complete request to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000538
Greg Steindd6eefb2000-07-18 09:09:48 +0000539 try:
540 self._send_request(method, url, body, headers)
541 except socket.error, v:
542 # trap 'Broken pipe' if we're allowed to automatically reconnect
543 if v[0] != 32 or not self.auto_open:
544 raise
545 # try one more time
546 self._send_request(method, url, body, headers)
Greg Stein5e0fa402000-06-26 08:28:01 +0000547
Greg Steindd6eefb2000-07-18 09:09:48 +0000548 def _send_request(self, method, url, body, headers):
Jeremy Hylton3921ff62002-03-09 06:07:23 +0000549 # If headers already contains a host header, then define the
550 # optional skip_host argument to putrequest(). The check is
551 # harder because field names are case insensitive.
552 if (headers.has_key('Host')
553 or [k for k in headers.iterkeys() if k.lower() == "host"]):
554 self.putrequest(method, url, skip_host=1)
555 else:
556 self.putrequest(method, url)
Greg Stein5e0fa402000-06-26 08:28:01 +0000557
Greg Steindd6eefb2000-07-18 09:09:48 +0000558 if body:
559 self.putheader('Content-Length', str(len(body)))
560 for hdr, value in headers.items():
561 self.putheader(hdr, value)
562 self.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000563
Greg Steindd6eefb2000-07-18 09:09:48 +0000564 if body:
565 self.send(body)
Greg Stein5e0fa402000-06-26 08:28:01 +0000566
Greg Steindd6eefb2000-07-18 09:09:48 +0000567 def getresponse(self):
568 "Get the response from the server."
Greg Stein5e0fa402000-06-26 08:28:01 +0000569
Greg Steindd6eefb2000-07-18 09:09:48 +0000570 # check if a prior response has been completed
571 if self.__response and self.__response.isclosed():
572 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000573
Greg Steindd6eefb2000-07-18 09:09:48 +0000574 #
575 # if a prior response exists, then it must be completed (otherwise, we
576 # cannot read this response's header to determine the connection-close
577 # behavior)
578 #
579 # note: if a prior response existed, but was connection-close, then the
580 # socket and response were made independent of this HTTPConnection
581 # object since a new request requires that we open a whole new
582 # connection
583 #
584 # this means the prior response had one of two states:
585 # 1) will_close: this connection was reset and the prior socket and
586 # response operate independently
587 # 2) persistent: the response was retained and we await its
588 # isclosed() status to become true.
589 #
590 if self.__state != _CS_REQ_SENT or self.__response:
591 raise ResponseNotReady()
Greg Stein5e0fa402000-06-26 08:28:01 +0000592
Jeremy Hylton30f86742000-09-18 22:50:38 +0000593 if self.debuglevel > 0:
594 response = self.response_class(self.sock, self.debuglevel)
595 else:
596 response = self.response_class(self.sock)
Greg Stein5e0fa402000-06-26 08:28:01 +0000597
Greg Steindd6eefb2000-07-18 09:09:48 +0000598 response.begin()
599 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000600
Greg Steindd6eefb2000-07-18 09:09:48 +0000601 if response.will_close:
602 # this effectively passes the connection to the response
603 self.close()
604 else:
605 # remember this, so we can tell when it is complete
606 self.__response = response
Greg Stein5e0fa402000-06-26 08:28:01 +0000607
Greg Steindd6eefb2000-07-18 09:09:48 +0000608 return response
Greg Stein5e0fa402000-06-26 08:28:01 +0000609
610
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000611class FakeSocket:
Greg Steindd6eefb2000-07-18 09:09:48 +0000612 def __init__(self, sock, ssl):
613 self.__sock = sock
614 self.__ssl = ssl
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000615
Jeremy Hylton4d746fc2000-08-23 20:34:17 +0000616 def makefile(self, mode, bufsize=None):
617 """Return a readable file-like object with data from socket.
618
619 This method offers only partial support for the makefile
620 interface of a real socket. It only supports modes 'r' and
621 'rb' and the bufsize argument is ignored.
622
Tim Peters5ceadc82001-01-13 19:16:21 +0000623 The returned object contains *all* of the file data
Jeremy Hylton4d746fc2000-08-23 20:34:17 +0000624 """
Greg Steindd6eefb2000-07-18 09:09:48 +0000625 if mode != 'r' and mode != 'rb':
626 raise UnimplementedFileMode()
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000627
Jeremy Hylton42dd01a2001-02-01 23:35:20 +0000628 msgbuf = []
Greg Steindd6eefb2000-07-18 09:09:48 +0000629 while 1:
630 try:
Jeremy Hylton42dd01a2001-02-01 23:35:20 +0000631 buf = self.__ssl.read()
Jeremy Hylton6459c8d2001-10-11 17:47:22 +0000632 except socket.sslerror, err:
633 if (err[0] == socket.SSL_ERROR_WANT_READ
Neal Norwitz22c5d772002-02-11 17:59:51 +0000634 or err[0] == socket.SSL_ERROR_WANT_WRITE):
Jeremy Hylton6459c8d2001-10-11 17:47:22 +0000635 continue
636 if err[0] == socket.SSL_ERROR_ZERO_RETURN:
637 break
638 raise
639 except socket.error, err:
Tim Petersf3623f32001-10-11 18:15:51 +0000640 if err[0] == errno.EINTR:
Jeremy Hylton6459c8d2001-10-11 17:47:22 +0000641 continue
642 raise
Jeremy Hylton42dd01a2001-02-01 23:35:20 +0000643 if buf == '':
644 break
645 msgbuf.append(buf)
646 return StringIO("".join(msgbuf))
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000647
Greg Steindd6eefb2000-07-18 09:09:48 +0000648 def send(self, stuff, flags = 0):
649 return self.__ssl.write(stuff)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000650
Andrew M. Kuchlinga3c0b932002-03-18 22:51:48 +0000651 def sendall(self, stuff, flags = 0):
652 return self.__ssl.write(stuff)
653
Greg Steindd6eefb2000-07-18 09:09:48 +0000654 def recv(self, len = 1024, flags = 0):
655 return self.__ssl.read(len)
Guido van Rossum23acc951994-02-21 16:36:04 +0000656
Greg Steindd6eefb2000-07-18 09:09:48 +0000657 def __getattr__(self, attr):
658 return getattr(self.__sock, attr)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000659
Guido van Rossum23acc951994-02-21 16:36:04 +0000660
Greg Stein5e0fa402000-06-26 08:28:01 +0000661class HTTPSConnection(HTTPConnection):
Greg Steindd6eefb2000-07-18 09:09:48 +0000662 "This class allows communication via SSL."
Greg Stein5e0fa402000-06-26 08:28:01 +0000663
Greg Steindd6eefb2000-07-18 09:09:48 +0000664 default_port = HTTPS_PORT
Greg Stein5e0fa402000-06-26 08:28:01 +0000665
Greg Steindd6eefb2000-07-18 09:09:48 +0000666 def __init__(self, host, port=None, **x509):
667 keys = x509.keys()
668 try:
669 keys.remove('key_file')
670 except ValueError:
671 pass
672 try:
673 keys.remove('cert_file')
674 except ValueError:
675 pass
676 if keys:
677 raise IllegalKeywordArgument()
678 HTTPConnection.__init__(self, host, port)
679 self.key_file = x509.get('key_file')
680 self.cert_file = x509.get('cert_file')
Greg Stein5e0fa402000-06-26 08:28:01 +0000681
Greg Steindd6eefb2000-07-18 09:09:48 +0000682 def connect(self):
683 "Connect to a host on a given (SSL) port."
Greg Stein5e0fa402000-06-26 08:28:01 +0000684
Greg Steindd6eefb2000-07-18 09:09:48 +0000685 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
686 sock.connect((self.host, self.port))
Guido van Rossum0aee7222000-12-11 20:32:20 +0000687 realsock = sock
688 if hasattr(sock, "_sock"):
689 realsock = sock._sock
690 ssl = socket.ssl(realsock, self.key_file, self.cert_file)
Greg Steindd6eefb2000-07-18 09:09:48 +0000691 self.sock = FakeSocket(sock, ssl)
Greg Stein5e0fa402000-06-26 08:28:01 +0000692
693
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000694class HTTP:
Greg Steindd6eefb2000-07-18 09:09:48 +0000695 "Compatibility class with httplib.py from 1.5."
Greg Stein5e0fa402000-06-26 08:28:01 +0000696
Greg Steindd6eefb2000-07-18 09:09:48 +0000697 _http_vsn = 10
698 _http_vsn_str = 'HTTP/1.0'
Greg Stein5e0fa402000-06-26 08:28:01 +0000699
Greg Steindd6eefb2000-07-18 09:09:48 +0000700 debuglevel = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000701
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000702 _connection_class = HTTPConnection
703
Greg Stein81937a42001-08-18 09:20:23 +0000704 def __init__(self, host='', port=None):
Greg Steindd6eefb2000-07-18 09:09:48 +0000705 "Provide a default host, since the superclass requires one."
Greg Stein5e0fa402000-06-26 08:28:01 +0000706
Greg Steindd6eefb2000-07-18 09:09:48 +0000707 # some joker passed 0 explicitly, meaning default port
708 if port == 0:
709 port = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000710
Greg Steindd6eefb2000-07-18 09:09:48 +0000711 # Note that we may pass an empty string as the host; this will throw
712 # an error when we attempt to connect. Presumably, the client code
713 # will call connect before then, with a proper host.
Greg Stein81937a42001-08-18 09:20:23 +0000714 self._setup(self._connection_class(host, port))
Greg Stein5e0fa402000-06-26 08:28:01 +0000715
Greg Stein81937a42001-08-18 09:20:23 +0000716 def _setup(self, conn):
717 self._conn = conn
718
719 # set up delegation to flesh out interface
720 self.send = conn.send
721 self.putrequest = conn.putrequest
722 self.endheaders = conn.endheaders
723 self.set_debuglevel = conn.set_debuglevel
724
725 conn._http_vsn = self._http_vsn
726 conn._http_vsn_str = self._http_vsn_str
Greg Stein5e0fa402000-06-26 08:28:01 +0000727
Greg Steindd6eefb2000-07-18 09:09:48 +0000728 self.file = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000729
Greg Steindd6eefb2000-07-18 09:09:48 +0000730 def connect(self, host=None, port=None):
731 "Accept arguments to set the host/port, since the superclass doesn't."
Greg Stein5e0fa402000-06-26 08:28:01 +0000732
Greg Steindd6eefb2000-07-18 09:09:48 +0000733 if host is not None:
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000734 self._conn._set_hostport(host, port)
735 self._conn.connect()
Greg Stein5e0fa402000-06-26 08:28:01 +0000736
Greg Steindd6eefb2000-07-18 09:09:48 +0000737 def getfile(self):
738 "Provide a getfile, since the superclass' does not use this concept."
739 return self.file
Greg Stein5e0fa402000-06-26 08:28:01 +0000740
Greg Steindd6eefb2000-07-18 09:09:48 +0000741 def putheader(self, header, *values):
742 "The superclass allows only one value argument."
Guido van Rossum34735a62000-12-15 15:09:42 +0000743 self._conn.putheader(header, '\r\n\t'.join(values))
Greg Stein5e0fa402000-06-26 08:28:01 +0000744
Greg Steindd6eefb2000-07-18 09:09:48 +0000745 def getreply(self):
746 """Compat definition since superclass does not define it.
Greg Stein5e0fa402000-06-26 08:28:01 +0000747
Greg Steindd6eefb2000-07-18 09:09:48 +0000748 Returns a tuple consisting of:
749 - server status code (e.g. '200' if all goes well)
750 - server "reason" corresponding to status code
751 - any RFC822 headers in the response from the server
752 """
753 try:
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000754 response = self._conn.getresponse()
Greg Steindd6eefb2000-07-18 09:09:48 +0000755 except BadStatusLine, e:
756 ### hmm. if getresponse() ever closes the socket on a bad request,
757 ### then we are going to have problems with self.sock
Greg Stein5e0fa402000-06-26 08:28:01 +0000758
Greg Steindd6eefb2000-07-18 09:09:48 +0000759 ### should we keep this behavior? do people use it?
760 # keep the socket open (as a file), and return it
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000761 self.file = self._conn.sock.makefile('rb', 0)
Greg Stein5e0fa402000-06-26 08:28:01 +0000762
Greg Steindd6eefb2000-07-18 09:09:48 +0000763 # close our socket -- we want to restart after any protocol error
764 self.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000765
Greg Steindd6eefb2000-07-18 09:09:48 +0000766 self.headers = None
767 return -1, e.line, None
Greg Stein5e0fa402000-06-26 08:28:01 +0000768
Greg Steindd6eefb2000-07-18 09:09:48 +0000769 self.headers = response.msg
770 self.file = response.fp
771 return response.status, response.reason, response.msg
Greg Stein5e0fa402000-06-26 08:28:01 +0000772
Greg Steindd6eefb2000-07-18 09:09:48 +0000773 def close(self):
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000774 self._conn.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000775
Greg Steindd6eefb2000-07-18 09:09:48 +0000776 # note that self.file == response.fp, which gets closed by the
777 # superclass. just clear the object ref here.
778 ### hmm. messy. if status==-1, then self.file is owned by us.
779 ### well... we aren't explicitly closing, but losing this ref will
780 ### do it
781 self.file = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000782
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000783if hasattr(socket, 'ssl'):
784 class HTTPS(HTTP):
785 """Compatibility with 1.5 httplib interface
786
787 Python 1.5.2 did not have an HTTPS class, but it defined an
788 interface for sending http requests that is also useful for
Tim Peters5ceadc82001-01-13 19:16:21 +0000789 https.
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000790 """
791
Martin v. Löwisd7bf9742000-09-21 22:09:47 +0000792 _connection_class = HTTPSConnection
Tim Peters5ceadc82001-01-13 19:16:21 +0000793
Greg Stein81937a42001-08-18 09:20:23 +0000794 def __init__(self, host='', port=None, **x509):
795 # provide a default host, pass the X509 cert info
796
797 # urf. compensate for bad input.
798 if port == 0:
799 port = None
800 self._setup(self._connection_class(host, port, **x509))
801
802 # we never actually use these for anything, but we keep them
803 # here for compatibility with post-1.5.2 CVS.
804 self.key_file = x509.get('key_file')
805 self.cert_file = x509.get('cert_file')
806
Greg Stein5e0fa402000-06-26 08:28:01 +0000807
808class HTTPException(Exception):
Greg Steindd6eefb2000-07-18 09:09:48 +0000809 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000810
811class NotConnected(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000812 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000813
Skip Montanaro9d389972002-03-24 16:53:50 +0000814class InvalidURL(HTTPException):
815 pass
816
Greg Stein5e0fa402000-06-26 08:28:01 +0000817class UnknownProtocol(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000818 def __init__(self, version):
819 self.version = version
Greg Stein5e0fa402000-06-26 08:28:01 +0000820
821class UnknownTransferEncoding(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000822 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000823
824class IllegalKeywordArgument(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000825 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000826
827class UnimplementedFileMode(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000828 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000829
830class IncompleteRead(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000831 def __init__(self, partial):
832 self.partial = partial
Greg Stein5e0fa402000-06-26 08:28:01 +0000833
834class ImproperConnectionState(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000835 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000836
837class CannotSendRequest(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000838 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000839
840class CannotSendHeader(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000841 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000842
843class ResponseNotReady(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000844 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000845
846class BadStatusLine(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000847 def __init__(self, line):
848 self.line = line
Greg Stein5e0fa402000-06-26 08:28:01 +0000849
850# for backwards compatibility
851error = HTTPException
852
853
854#
855# snarfed from httplib.py for now...
856#
Guido van Rossum23acc951994-02-21 16:36:04 +0000857def test():
Guido van Rossum41999c11997-12-09 00:12:23 +0000858 """Test this module.
859
860 The test consists of retrieving and displaying the Python
861 home page, along with the error code and error string returned
862 by the www.python.org server.
Guido van Rossum41999c11997-12-09 00:12:23 +0000863 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000864
Guido van Rossum41999c11997-12-09 00:12:23 +0000865 import sys
866 import getopt
867 opts, args = getopt.getopt(sys.argv[1:], 'd')
868 dl = 0
869 for o, a in opts:
870 if o == '-d': dl = dl + 1
871 host = 'www.python.org'
872 selector = '/'
873 if args[0:]: host = args[0]
874 if args[1:]: selector = args[1]
875 h = HTTP()
876 h.set_debuglevel(dl)
877 h.connect(host)
878 h.putrequest('GET', selector)
879 h.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000880 status, reason, headers = h.getreply()
881 print 'status =', status
882 print 'reason =', reason
Guido van Rossum41999c11997-12-09 00:12:23 +0000883 print
884 if headers:
Guido van Rossum34735a62000-12-15 15:09:42 +0000885 for header in headers.headers: print header.strip()
Guido van Rossum41999c11997-12-09 00:12:23 +0000886 print
887 print h.getfile().read()
Greg Stein5e0fa402000-06-26 08:28:01 +0000888
Jeremy Hylton8acf1e02002-03-08 19:35:51 +0000889 # minimal test that code to extract host from url works
890 class HTTP11(HTTP):
891 _http_vsn = 11
892 _http_vsn_str = 'HTTP/1.1'
893
894 h = HTTP11('www.python.org')
895 h.putrequest('GET', 'http://www.python.org/~jeremy/')
896 h.endheaders()
897 h.getreply()
898 h.close()
899
Greg Stein5e0fa402000-06-26 08:28:01 +0000900 if hasattr(socket, 'ssl'):
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000901 host = 'sourceforge.net'
Jeremy Hylton42dd01a2001-02-01 23:35:20 +0000902 selector = '/projects/python'
Greg Steindd6eefb2000-07-18 09:09:48 +0000903 hs = HTTPS()
904 hs.connect(host)
905 hs.putrequest('GET', selector)
906 hs.endheaders()
907 status, reason, headers = hs.getreply()
908 print 'status =', status
909 print 'reason =', reason
910 print
911 if headers:
Guido van Rossum34735a62000-12-15 15:09:42 +0000912 for header in headers.headers: print header.strip()
Greg Steindd6eefb2000-07-18 09:09:48 +0000913 print
914 print hs.getfile().read()
Guido van Rossum23acc951994-02-21 16:36:04 +0000915
Guido van Rossuma0dfc7a1995-09-07 19:28:19 +0000916
Guido van Rossum23acc951994-02-21 16:36:04 +0000917if __name__ == '__main__':
Guido van Rossum41999c11997-12-09 00:12:23 +0000918 test()