blob: 395ffbf978681839dffceace2f0c30ab762b8163 [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 |\____________________
28 | \
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
41
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
Guido van Rossum23acc951994-02-21 16:36:04 +000069import socket
70import string
Guido van Rossum65ab98c1995-08-07 20:13:02 +000071import mimetools
Guido van Rossum23acc951994-02-21 16:36:04 +000072
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000073try:
Greg Steindd6eefb2000-07-18 09:09:48 +000074 from cStringIO import StringIO
Greg Stein5e0fa402000-06-26 08:28:01 +000075except ImportError:
Greg Steindd6eefb2000-07-18 09:09:48 +000076 from StringIO import StringIO
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000077
Guido van Rossum23acc951994-02-21 16:36:04 +000078HTTP_PORT = 80
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000079HTTPS_PORT = 443
80
Greg Stein5e0fa402000-06-26 08:28:01 +000081_UNKNOWN = 'UNKNOWN'
82
83# connection states
84_CS_IDLE = 'Idle'
85_CS_REQ_STARTED = 'Request-started'
86_CS_REQ_SENT = 'Request-sent'
87
88
89class HTTPResponse:
Greg Steindd6eefb2000-07-18 09:09:48 +000090 def __init__(self, sock):
91 self.fp = sock.makefile('rb', 0)
Greg Stein5e0fa402000-06-26 08:28:01 +000092
Greg Steindd6eefb2000-07-18 09:09:48 +000093 self.msg = None
Greg Stein5e0fa402000-06-26 08:28:01 +000094
Greg Steindd6eefb2000-07-18 09:09:48 +000095 # from the Status-Line of the response
96 self.version = _UNKNOWN # HTTP-Version
97 self.status = _UNKNOWN # Status-Code
98 self.reason = _UNKNOWN # Reason-Phrase
Greg Stein5e0fa402000-06-26 08:28:01 +000099
Greg Steindd6eefb2000-07-18 09:09:48 +0000100 self.chunked = _UNKNOWN # is "chunked" being used?
101 self.chunk_left = _UNKNOWN # bytes left to read in current chunk
102 self.length = _UNKNOWN # number of bytes left in response
103 self.will_close = _UNKNOWN # conn will close at end of response
Greg Stein5e0fa402000-06-26 08:28:01 +0000104
Greg Steindd6eefb2000-07-18 09:09:48 +0000105 def begin(self):
106 if self.msg is not None:
107 # we've already started reading the response
108 return
Greg Stein5e0fa402000-06-26 08:28:01 +0000109
Greg Stein5e0fa402000-06-26 08:28:01 +0000110 line = self.fp.readline()
Greg Steindd6eefb2000-07-18 09:09:48 +0000111 try:
112 [version, status, reason] = string.split(line, None, 2)
113 except ValueError:
114 try:
115 [version, status] = string.split(line, None, 1)
116 reason = ""
117 except ValueError:
118 self.close()
119 raise BadStatusLine(line)
120 if version[:5] != 'HTTP/':
121 self.close()
122 raise BadStatusLine(line)
Greg Stein5e0fa402000-06-26 08:28:01 +0000123
Greg Steindd6eefb2000-07-18 09:09:48 +0000124 self.status = status = int(status)
125 self.reason = string.strip(reason)
Greg Stein5e0fa402000-06-26 08:28:01 +0000126
Greg Steindd6eefb2000-07-18 09:09:48 +0000127 if version == 'HTTP/1.0':
128 self.version = 10
129 elif version[:7] == 'HTTP/1.':
130 self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
131 else:
132 raise UnknownProtocol(version)
Greg Stein5e0fa402000-06-26 08:28:01 +0000133
Greg Steindd6eefb2000-07-18 09:09:48 +0000134 self.msg = mimetools.Message(self.fp, 0)
Greg Stein5e0fa402000-06-26 08:28:01 +0000135
Greg Steindd6eefb2000-07-18 09:09:48 +0000136 # don't let the msg keep an fp
137 self.msg.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000138
Greg Steindd6eefb2000-07-18 09:09:48 +0000139 # are we using the chunked-style of transfer encoding?
140 tr_enc = self.msg.getheader('transfer-encoding')
141 if tr_enc:
142 if string.lower(tr_enc) != 'chunked':
143 raise UnknownTransferEncoding()
144 self.chunked = 1
145 self.chunk_left = None
146 else:
147 self.chunked = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000148
Greg Steindd6eefb2000-07-18 09:09:48 +0000149 # will the connection close at the end of the response?
150 conn = self.msg.getheader('connection')
151 if conn:
152 conn = string.lower(conn)
153 # a "Connection: close" will always close the connection. if we
154 # don't see that and this is not HTTP/1.1, then the connection will
155 # close unless we see a Keep-Alive header.
156 self.will_close = string.find(conn, 'close') != -1 or \
157 ( self.version != 11 and \
158 not self.msg.getheader('keep-alive') )
159 else:
160 # for HTTP/1.1, the connection will always remain open
161 # otherwise, it will remain open IFF we see a Keep-Alive header
162 self.will_close = self.version != 11 and \
163 not self.msg.getheader('keep-alive')
Greg Stein5e0fa402000-06-26 08:28:01 +0000164
Greg Steindd6eefb2000-07-18 09:09:48 +0000165 # do we have a Content-Length?
166 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
167 length = self.msg.getheader('content-length')
168 if length and not self.chunked:
169 self.length = int(length)
170 else:
171 self.length = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000172
Greg Steindd6eefb2000-07-18 09:09:48 +0000173 # does the body have a fixed length? (of zero)
174 if (status == 204 or # No Content
175 status == 304 or # Not Modified
176 100 <= status < 200): # 1xx codes
177 self.length = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000178
Greg Steindd6eefb2000-07-18 09:09:48 +0000179 # if the connection remains open, and we aren't using chunked, and
180 # a content-length was not provided, then assume that the connection
181 # WILL close.
182 if not self.will_close and \
183 not self.chunked and \
184 self.length is None:
185 self.will_close = 1
Greg Stein5e0fa402000-06-26 08:28:01 +0000186
Greg Steindd6eefb2000-07-18 09:09:48 +0000187 # if there is no body, then close NOW. read() may never be called, thus
188 # we will never mark self as closed.
189 if self.length == 0:
190 self.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000191
Greg Steindd6eefb2000-07-18 09:09:48 +0000192 def close(self):
193 if self.fp:
194 self.fp.close()
195 self.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000196
Greg Steindd6eefb2000-07-18 09:09:48 +0000197 def isclosed(self):
198 # NOTE: it is possible that we will not ever call self.close(). This
199 # case occurs when will_close is TRUE, length is None, and we
200 # read up to the last byte, but NOT past it.
201 #
202 # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
203 # called, meaning self.isclosed() is meaningful.
204 return self.fp is None
205
206 def read(self, amt=None):
207 if self.fp is None:
208 return ''
209
210 if self.chunked:
211 chunk_left = self.chunk_left
212 value = ''
213 while 1:
214 if chunk_left is None:
215 line = self.fp.readline()
216 i = string.find(line, ';')
217 if i >= 0:
218 line = line[:i] # strip chunk-extensions
219 chunk_left = string.atoi(line, 16)
220 if chunk_left == 0:
221 break
222 if amt is None:
223 value = value + self._safe_read(chunk_left)
224 elif amt < chunk_left:
225 value = value + self._safe_read(amt)
226 self.chunk_left = chunk_left - amt
227 return value
228 elif amt == chunk_left:
229 value = value + self._safe_read(amt)
230 self._safe_read(2) # toss the CRLF at the end of the chunk
231 self.chunk_left = None
232 return value
233 else:
234 value = value + self._safe_read(chunk_left)
235 amt = amt - chunk_left
236
237 # we read the whole chunk, get another
238 self._safe_read(2) # toss the CRLF at the end of the chunk
239 chunk_left = None
240
241 # read and discard trailer up to the CRLF terminator
242 ### note: we shouldn't have any trailers!
243 while 1:
244 line = self.fp.readline()
245 if line == '\r\n':
246 break
247
248 # we read everything; close the "file"
249 self.close()
250
251 return value
252
253 elif amt is None:
254 # unbounded read
255 if self.will_close:
256 s = self.fp.read()
257 else:
258 s = self._safe_read(self.length)
259 self.close() # we read everything
260 return s
261
262 if self.length is not None:
263 if amt > self.length:
264 # clip the read to the "end of response"
265 amt = self.length
266 self.length = self.length - amt
267
268 # we do not use _safe_read() here because this may be a .will_close
269 # connection, and the user is reading more bytes than will be provided
270 # (for example, reading in 1k chunks)
271 s = self.fp.read(amt)
272
273 # close our "file" if we know we should
274 ### I'm not sure about the len(s) < amt part; we should be safe because
275 ### we shouldn't be using non-blocking sockets
276 if self.length == 0 or len(s) < amt:
277 self.close()
278
279 return s
280
281 def _safe_read(self, amt):
282 """Read the number of bytes requested, compensating for partial reads.
283
284 Normally, we have a blocking socket, but a read() can be interrupted
285 by a signal (resulting in a partial read).
286
287 Note that we cannot distinguish between EOF and an interrupt when zero
288 bytes have been read. IncompleteRead() will be raised in this
289 situation.
290
291 This function should be used when <amt> bytes "should" be present for
292 reading. If the bytes are truly not available (due to EOF), then the
293 IncompleteRead exception can be used to detect the problem.
294 """
295 s = ''
296 while amt > 0:
297 chunk = self.fp.read(amt)
298 if not chunk:
299 raise IncompleteRead(s)
300 s = s + chunk
301 amt = amt - len(chunk)
302 return s
303
304 def getheader(self, name, default=None):
305 if self.msg is None:
306 raise ResponseNotReady()
307 return self.msg.getheader(name, default)
Greg Stein5e0fa402000-06-26 08:28:01 +0000308
309
310class HTTPConnection:
311
Greg Steindd6eefb2000-07-18 09:09:48 +0000312 _http_vsn = 11
313 _http_vsn_str = 'HTTP/1.1'
Greg Stein5e0fa402000-06-26 08:28:01 +0000314
Greg Steindd6eefb2000-07-18 09:09:48 +0000315 response_class = HTTPResponse
316 default_port = HTTP_PORT
317 auto_open = 1
Greg Stein5e0fa402000-06-26 08:28:01 +0000318
Greg Steindd6eefb2000-07-18 09:09:48 +0000319 def __init__(self, host, port=None):
320 self.sock = None
321 self.__response = None
322 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000323
Greg Steindd6eefb2000-07-18 09:09:48 +0000324 self._set_hostport(host, port)
Greg Stein5e0fa402000-06-26 08:28:01 +0000325
Greg Steindd6eefb2000-07-18 09:09:48 +0000326 def _set_hostport(self, host, port):
327 if port is None:
328 i = string.find(host, ':')
329 if i >= 0:
330 port = int(host[i+1:])
331 host = host[:i]
332 else:
333 port = self.default_port
334 self.host = host
335 self.port = port
Greg Stein5e0fa402000-06-26 08:28:01 +0000336
Greg Steindd6eefb2000-07-18 09:09:48 +0000337 def connect(self):
338 """Connect to the host and port specified in __init__."""
339 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
340 self.sock.connect((self.host, self.port))
Greg Stein5e0fa402000-06-26 08:28:01 +0000341
Greg Steindd6eefb2000-07-18 09:09:48 +0000342 def close(self):
343 """Close the connection to the HTTP server."""
344 if self.sock:
345 self.sock.close() # close it manually... there may be other refs
346 self.sock = None
347 if self.__response:
348 self.__response.close()
349 self.__response = None
350 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000351
Greg Steindd6eefb2000-07-18 09:09:48 +0000352 def send(self, str):
353 """Send `str' to the server."""
354 if self.sock is None:
355 if self.auto_open:
356 self.connect()
357 else:
358 raise NotConnected()
Greg Stein5e0fa402000-06-26 08:28:01 +0000359
Greg Steindd6eefb2000-07-18 09:09:48 +0000360 # send the data to the server. if we get a broken pipe, then close
361 # the socket. we want to reconnect when somebody tries to send again.
362 #
363 # NOTE: we DO propagate the error, though, because we cannot simply
364 # ignore the error... the caller will know if they can retry.
365 try:
366 self.sock.send(str)
367 except socket.error, v:
368 if v[0] == 32: # Broken pipe
369 self.close()
370 raise
Greg Stein5e0fa402000-06-26 08:28:01 +0000371
Greg Steindd6eefb2000-07-18 09:09:48 +0000372 def putrequest(self, method, url):
373 """Send a request to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000374
Greg Steindd6eefb2000-07-18 09:09:48 +0000375 `method' specifies an HTTP request method, e.g. 'GET'.
376 `url' specifies the object being requested, e.g. '/index.html'.
377 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000378
Greg Steindd6eefb2000-07-18 09:09:48 +0000379 # check if a prior response has been completed
380 if self.__response and self.__response.isclosed():
381 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000382
Greg Steindd6eefb2000-07-18 09:09:48 +0000383 #
384 # in certain cases, we cannot issue another request on this connection.
385 # this occurs when:
386 # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
387 # 2) a response to a previous request has signalled that it is going
388 # to close the connection upon completion.
389 # 3) the headers for the previous response have not been read, thus
390 # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
391 #
392 # if there is no prior response, then we can request at will.
393 #
394 # if point (2) is true, then we will have passed the socket to the
395 # response (effectively meaning, "there is no prior response"), and
396 # will open a new one when a new request is made.
397 #
398 # Note: if a prior response exists, then we *can* start a new request.
399 # We are not allowed to begin fetching the response to this new
400 # request, however, until that prior response is complete.
401 #
402 if self.__state == _CS_IDLE:
403 self.__state = _CS_REQ_STARTED
404 else:
405 raise CannotSendRequest()
Greg Stein5e0fa402000-06-26 08:28:01 +0000406
Greg Steindd6eefb2000-07-18 09:09:48 +0000407 if not url:
408 url = '/'
409 str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000410
Greg Steindd6eefb2000-07-18 09:09:48 +0000411 try:
412 self.send(str)
413 except socket.error, v:
414 # trap 'Broken pipe' if we're allowed to automatically reconnect
415 if v[0] != 32 or not self.auto_open:
416 raise
417 # try one more time (the socket was closed; this will reopen)
418 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000419
Greg Steindd6eefb2000-07-18 09:09:48 +0000420 if self._http_vsn == 11:
421 # Issue some standard headers for better HTTP/1.1 compliance
Greg Stein5e0fa402000-06-26 08:28:01 +0000422
Greg Steindd6eefb2000-07-18 09:09:48 +0000423 # this header is issued *only* for HTTP/1.1 connections. more
424 # specifically, this means it is only issued when the client uses
425 # the new HTTPConnection() class. backwards-compat clients will
426 # be using HTTP/1.0 and those clients may be issuing this header
427 # themselves. we should NOT issue it twice; some web servers (such
428 # as Apache) barf when they see two Host: headers
429 self.putheader('Host', self.host)
Greg Stein5e0fa402000-06-26 08:28:01 +0000430
Greg Steindd6eefb2000-07-18 09:09:48 +0000431 # note: we are assuming that clients will not attempt to set these
432 # headers since *this* library must deal with the
433 # consequences. this also means that when the supporting
434 # libraries are updated to recognize other forms, then this
435 # code should be changed (removed or updated).
Greg Stein5e0fa402000-06-26 08:28:01 +0000436
Greg Steindd6eefb2000-07-18 09:09:48 +0000437 # we only want a Content-Encoding of "identity" since we don't
438 # support encodings such as x-gzip or x-deflate.
439 self.putheader('Accept-Encoding', 'identity')
Greg Stein5e0fa402000-06-26 08:28:01 +0000440
Greg Steindd6eefb2000-07-18 09:09:48 +0000441 # we can accept "chunked" Transfer-Encodings, but no others
442 # NOTE: no TE header implies *only* "chunked"
443 #self.putheader('TE', 'chunked')
Greg Stein5e0fa402000-06-26 08:28:01 +0000444
Greg Steindd6eefb2000-07-18 09:09:48 +0000445 # if TE is supplied in the header, then it must appear in a
446 # Connection header.
447 #self.putheader('Connection', 'TE')
Greg Stein5e0fa402000-06-26 08:28:01 +0000448
Greg Steindd6eefb2000-07-18 09:09:48 +0000449 else:
450 # For HTTP/1.0, the server will assume "not chunked"
451 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000452
Greg Steindd6eefb2000-07-18 09:09:48 +0000453 def putheader(self, header, value):
454 """Send a request header line to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000455
Greg Steindd6eefb2000-07-18 09:09:48 +0000456 For example: h.putheader('Accept', 'text/html')
457 """
458 if self.__state != _CS_REQ_STARTED:
459 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000460
Greg Steindd6eefb2000-07-18 09:09:48 +0000461 str = '%s: %s\r\n' % (header, value)
462 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000463
Greg Steindd6eefb2000-07-18 09:09:48 +0000464 def endheaders(self):
465 """Indicate that the last header line has been sent to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000466
Greg Steindd6eefb2000-07-18 09:09:48 +0000467 if self.__state == _CS_REQ_STARTED:
468 self.__state = _CS_REQ_SENT
469 else:
470 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000471
Greg Steindd6eefb2000-07-18 09:09:48 +0000472 self.send('\r\n')
Greg Stein5e0fa402000-06-26 08:28:01 +0000473
Greg Steindd6eefb2000-07-18 09:09:48 +0000474 def request(self, method, url, body=None, headers={}):
475 """Send a complete request to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000476
Greg Steindd6eefb2000-07-18 09:09:48 +0000477 try:
478 self._send_request(method, url, body, headers)
479 except socket.error, v:
480 # trap 'Broken pipe' if we're allowed to automatically reconnect
481 if v[0] != 32 or not self.auto_open:
482 raise
483 # try one more time
484 self._send_request(method, url, body, headers)
Greg Stein5e0fa402000-06-26 08:28:01 +0000485
Greg Steindd6eefb2000-07-18 09:09:48 +0000486 def _send_request(self, method, url, body, headers):
487 self.putrequest(method, url)
Greg Stein5e0fa402000-06-26 08:28:01 +0000488
Greg Steindd6eefb2000-07-18 09:09:48 +0000489 if body:
490 self.putheader('Content-Length', str(len(body)))
491 for hdr, value in headers.items():
492 self.putheader(hdr, value)
493 self.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000494
Greg Steindd6eefb2000-07-18 09:09:48 +0000495 if body:
496 self.send(body)
Greg Stein5e0fa402000-06-26 08:28:01 +0000497
Greg Steindd6eefb2000-07-18 09:09:48 +0000498 def getresponse(self):
499 "Get the response from the server."
Greg Stein5e0fa402000-06-26 08:28:01 +0000500
Greg Steindd6eefb2000-07-18 09:09:48 +0000501 # check if a prior response has been completed
502 if self.__response and self.__response.isclosed():
503 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000504
Greg Steindd6eefb2000-07-18 09:09:48 +0000505 #
506 # if a prior response exists, then it must be completed (otherwise, we
507 # cannot read this response's header to determine the connection-close
508 # behavior)
509 #
510 # note: if a prior response existed, but was connection-close, then the
511 # socket and response were made independent of this HTTPConnection
512 # object since a new request requires that we open a whole new
513 # connection
514 #
515 # this means the prior response had one of two states:
516 # 1) will_close: this connection was reset and the prior socket and
517 # response operate independently
518 # 2) persistent: the response was retained and we await its
519 # isclosed() status to become true.
520 #
521 if self.__state != _CS_REQ_SENT or self.__response:
522 raise ResponseNotReady()
Greg Stein5e0fa402000-06-26 08:28:01 +0000523
Greg Steindd6eefb2000-07-18 09:09:48 +0000524 response = self.response_class(self.sock)
Greg Stein5e0fa402000-06-26 08:28:01 +0000525
Greg Steindd6eefb2000-07-18 09:09:48 +0000526 response.begin()
527 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000528
Greg Steindd6eefb2000-07-18 09:09:48 +0000529 if response.will_close:
530 # this effectively passes the connection to the response
531 self.close()
532 else:
533 # remember this, so we can tell when it is complete
534 self.__response = response
Greg Stein5e0fa402000-06-26 08:28:01 +0000535
Greg Steindd6eefb2000-07-18 09:09:48 +0000536 return response
Greg Stein5e0fa402000-06-26 08:28:01 +0000537
538
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000539class FakeSocket:
Greg Steindd6eefb2000-07-18 09:09:48 +0000540 def __init__(self, sock, ssl):
541 self.__sock = sock
542 self.__ssl = ssl
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000543
Greg Steindd6eefb2000-07-18 09:09:48 +0000544 def makefile(self, mode): # hopefully, never have to write
545 if mode != 'r' and mode != 'rb':
546 raise UnimplementedFileMode()
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000547
Greg Steindd6eefb2000-07-18 09:09:48 +0000548 msgbuf = ""
549 while 1:
550 try:
551 msgbuf = msgbuf + self.__ssl.read()
552 except socket.sslerror, msg:
553 break
554 return StringIO(msgbuf)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000555
Greg Steindd6eefb2000-07-18 09:09:48 +0000556 def send(self, stuff, flags = 0):
557 return self.__ssl.write(stuff)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000558
Greg Steindd6eefb2000-07-18 09:09:48 +0000559 def recv(self, len = 1024, flags = 0):
560 return self.__ssl.read(len)
Guido van Rossum23acc951994-02-21 16:36:04 +0000561
Greg Steindd6eefb2000-07-18 09:09:48 +0000562 def __getattr__(self, attr):
563 return getattr(self.__sock, attr)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000564
Guido van Rossum23acc951994-02-21 16:36:04 +0000565
Greg Stein5e0fa402000-06-26 08:28:01 +0000566class HTTPSConnection(HTTPConnection):
Greg Steindd6eefb2000-07-18 09:09:48 +0000567 "This class allows communication via SSL."
Greg Stein5e0fa402000-06-26 08:28:01 +0000568
Greg Steindd6eefb2000-07-18 09:09:48 +0000569 default_port = HTTPS_PORT
Greg Stein5e0fa402000-06-26 08:28:01 +0000570
Greg Steindd6eefb2000-07-18 09:09:48 +0000571 def __init__(self, host, port=None, **x509):
572 keys = x509.keys()
573 try:
574 keys.remove('key_file')
575 except ValueError:
576 pass
577 try:
578 keys.remove('cert_file')
579 except ValueError:
580 pass
581 if keys:
582 raise IllegalKeywordArgument()
583 HTTPConnection.__init__(self, host, port)
584 self.key_file = x509.get('key_file')
585 self.cert_file = x509.get('cert_file')
Greg Stein5e0fa402000-06-26 08:28:01 +0000586
Greg Steindd6eefb2000-07-18 09:09:48 +0000587 def connect(self):
588 "Connect to a host on a given (SSL) port."
Greg Stein5e0fa402000-06-26 08:28:01 +0000589
Greg Steindd6eefb2000-07-18 09:09:48 +0000590 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
591 sock.connect((self.host, self.port))
592 ssl = socket.ssl(sock, self.key_file, self.cert_file)
593 self.sock = FakeSocket(sock, ssl)
Greg Stein5e0fa402000-06-26 08:28:01 +0000594
595
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000596class HTTP:
Greg Steindd6eefb2000-07-18 09:09:48 +0000597 "Compatibility class with httplib.py from 1.5."
Greg Stein5e0fa402000-06-26 08:28:01 +0000598
Greg Steindd6eefb2000-07-18 09:09:48 +0000599 _http_vsn = 10
600 _http_vsn_str = 'HTTP/1.0'
Greg Stein5e0fa402000-06-26 08:28:01 +0000601
Greg Steindd6eefb2000-07-18 09:09:48 +0000602 debuglevel = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000603
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000604 _connection_class = HTTPConnection
605
Greg Steindd6eefb2000-07-18 09:09:48 +0000606 def __init__(self, host='', port=None, **x509):
607 "Provide a default host, since the superclass requires one."
Greg Stein5e0fa402000-06-26 08:28:01 +0000608
Greg Steindd6eefb2000-07-18 09:09:48 +0000609 # some joker passed 0 explicitly, meaning default port
610 if port == 0:
611 port = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000612
Greg Steindd6eefb2000-07-18 09:09:48 +0000613 # Note that we may pass an empty string as the host; this will throw
614 # an error when we attempt to connect. Presumably, the client code
615 # will call connect before then, with a proper host.
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000616 self._conn = self._connection_class(host, port)
617 # set up delegation to flesh out interface
618 self.send = self._conn.send
619 self.putrequest = self._conn.putrequest
620 self.endheaders = self._conn.endheaders
Greg Stein5e0fa402000-06-26 08:28:01 +0000621
Greg Steindd6eefb2000-07-18 09:09:48 +0000622 # we never actually use these for anything, but we keep them here for
623 # compatibility with post-1.5.2 CVS.
624 self.key_file = x509.get('key_file')
625 self.cert_file = x509.get('cert_file')
Greg Stein5e0fa402000-06-26 08:28:01 +0000626
Greg Steindd6eefb2000-07-18 09:09:48 +0000627 self.file = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000628
Greg Steindd6eefb2000-07-18 09:09:48 +0000629 def connect(self, host=None, port=None):
630 "Accept arguments to set the host/port, since the superclass doesn't."
Greg Stein5e0fa402000-06-26 08:28:01 +0000631
Greg Steindd6eefb2000-07-18 09:09:48 +0000632 if host is not None:
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000633 self._conn._set_hostport(host, port)
634 self._conn.connect()
Greg Stein5e0fa402000-06-26 08:28:01 +0000635
Greg Steindd6eefb2000-07-18 09:09:48 +0000636 def set_debuglevel(self, debuglevel):
637 "The class no longer supports the debuglevel."
638 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000639
Greg Steindd6eefb2000-07-18 09:09:48 +0000640 def getfile(self):
641 "Provide a getfile, since the superclass' does not use this concept."
642 return self.file
Greg Stein5e0fa402000-06-26 08:28:01 +0000643
Greg Steindd6eefb2000-07-18 09:09:48 +0000644 def putheader(self, header, *values):
645 "The superclass allows only one value argument."
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000646 self._conn.putheader(header,
647 string.joinfields(values, '\r\n\t'))
Greg Stein5e0fa402000-06-26 08:28:01 +0000648
Greg Steindd6eefb2000-07-18 09:09:48 +0000649 def getreply(self):
650 """Compat definition since superclass does not define it.
Greg Stein5e0fa402000-06-26 08:28:01 +0000651
Greg Steindd6eefb2000-07-18 09:09:48 +0000652 Returns a tuple consisting of:
653 - server status code (e.g. '200' if all goes well)
654 - server "reason" corresponding to status code
655 - any RFC822 headers in the response from the server
656 """
657 try:
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000658 response = self._conn.getresponse()
Greg Steindd6eefb2000-07-18 09:09:48 +0000659 except BadStatusLine, e:
660 ### hmm. if getresponse() ever closes the socket on a bad request,
661 ### then we are going to have problems with self.sock
Greg Stein5e0fa402000-06-26 08:28:01 +0000662
Greg Steindd6eefb2000-07-18 09:09:48 +0000663 ### should we keep this behavior? do people use it?
664 # keep the socket open (as a file), and return it
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000665 self.file = self._conn.sock.makefile('rb', 0)
Greg Stein5e0fa402000-06-26 08:28:01 +0000666
Greg Steindd6eefb2000-07-18 09:09:48 +0000667 # close our socket -- we want to restart after any protocol error
668 self.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000669
Greg Steindd6eefb2000-07-18 09:09:48 +0000670 self.headers = None
671 return -1, e.line, None
Greg Stein5e0fa402000-06-26 08:28:01 +0000672
Greg Steindd6eefb2000-07-18 09:09:48 +0000673 self.headers = response.msg
674 self.file = response.fp
675 return response.status, response.reason, response.msg
Greg Stein5e0fa402000-06-26 08:28:01 +0000676
Greg Steindd6eefb2000-07-18 09:09:48 +0000677 def close(self):
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000678 self._conn.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000679
Greg Steindd6eefb2000-07-18 09:09:48 +0000680 # note that self.file == response.fp, which gets closed by the
681 # superclass. just clear the object ref here.
682 ### hmm. messy. if status==-1, then self.file is owned by us.
683 ### well... we aren't explicitly closing, but losing this ref will
684 ### do it
685 self.file = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000686
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000687if hasattr(socket, 'ssl'):
688 class HTTPS(HTTP):
689 """Compatibility with 1.5 httplib interface
690
691 Python 1.5.2 did not have an HTTPS class, but it defined an
692 interface for sending http requests that is also useful for
693 https.
694 """
695
696 _connection_class = HTTPSConnection
697
Greg Stein5e0fa402000-06-26 08:28:01 +0000698
699class HTTPException(Exception):
Greg Steindd6eefb2000-07-18 09:09:48 +0000700 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000701
702class NotConnected(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000703 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000704
705class UnknownProtocol(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000706 def __init__(self, version):
707 self.version = version
Greg Stein5e0fa402000-06-26 08:28:01 +0000708
709class UnknownTransferEncoding(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000710 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000711
712class IllegalKeywordArgument(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000713 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000714
715class UnimplementedFileMode(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000716 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000717
718class IncompleteRead(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000719 def __init__(self, partial):
720 self.partial = partial
Greg Stein5e0fa402000-06-26 08:28:01 +0000721
722class ImproperConnectionState(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000723 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000724
725class CannotSendRequest(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000726 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000727
728class CannotSendHeader(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000729 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000730
731class ResponseNotReady(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000732 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000733
734class BadStatusLine(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000735 def __init__(self, line):
736 self.line = line
Greg Stein5e0fa402000-06-26 08:28:01 +0000737
738# for backwards compatibility
739error = HTTPException
740
741
742#
743# snarfed from httplib.py for now...
744#
Guido van Rossum23acc951994-02-21 16:36:04 +0000745def test():
Guido van Rossum41999c11997-12-09 00:12:23 +0000746 """Test this module.
747
748 The test consists of retrieving and displaying the Python
749 home page, along with the error code and error string returned
750 by the www.python.org server.
Guido van Rossum41999c11997-12-09 00:12:23 +0000751 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000752
Guido van Rossum41999c11997-12-09 00:12:23 +0000753 import sys
754 import getopt
755 opts, args = getopt.getopt(sys.argv[1:], 'd')
756 dl = 0
757 for o, a in opts:
758 if o == '-d': dl = dl + 1
759 host = 'www.python.org'
760 selector = '/'
761 if args[0:]: host = args[0]
762 if args[1:]: selector = args[1]
763 h = HTTP()
764 h.set_debuglevel(dl)
765 h.connect(host)
766 h.putrequest('GET', selector)
767 h.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000768 status, reason, headers = h.getreply()
769 print 'status =', status
770 print 'reason =', reason
Guido van Rossum41999c11997-12-09 00:12:23 +0000771 print
772 if headers:
773 for header in headers.headers: print string.strip(header)
774 print
775 print h.getfile().read()
Greg Stein5e0fa402000-06-26 08:28:01 +0000776
777 if hasattr(socket, 'ssl'):
Jeremy Hylton29b8d5a2000-08-01 17:33:32 +0000778 host = 'sourceforge.net'
Greg Steindd6eefb2000-07-18 09:09:48 +0000779 hs = HTTPS()
780 hs.connect(host)
781 hs.putrequest('GET', selector)
782 hs.endheaders()
783 status, reason, headers = hs.getreply()
784 print 'status =', status
785 print 'reason =', reason
786 print
787 if headers:
788 for header in headers.headers: print string.strip(header)
789 print
790 print hs.getfile().read()
Guido van Rossum23acc951994-02-21 16:36:04 +0000791
Guido van Rossuma0dfc7a1995-09-07 19:28:19 +0000792
Guido van Rossum23acc951994-02-21 16:36:04 +0000793if __name__ == '__main__':
Guido van Rossum41999c11997-12-09 00:12:23 +0000794 test()