blob: 2a9546fbe857573bec8f72033b6ea1a493d71eae [file] [log] [blame]
Greg Stein5e0fa402000-06-26 08:28:01 +00001#
2# HTTP/1.1 client library
3#
Guido van Rossum23acc951994-02-21 16:36:04 +00004
Greg Stein5e0fa402000-06-26 08:28:01 +00005# ### this may as well go into a doc string...
6"""HTTP/1.1 client library
Guido van Rossum41999c11997-12-09 00:12:23 +00007
Greg Stein5e0fa402000-06-26 08:28:01 +00008<intro stuff goes here>
9<other stuff, too>
Guido van Rossum41999c11997-12-09 00:12:23 +000010
Greg Stein5e0fa402000-06-26 08:28:01 +000011HTTPConnection go through a number of "states", which defines when a client
12may legally make another request or fetch the response for a particular
13request. This diagram details these state transitions:
Guido van Rossum41999c11997-12-09 00:12:23 +000014
Greg Stein5e0fa402000-06-26 08:28:01 +000015 (null)
16 |
17 | HTTPConnection()
18 v
19 Idle
20 |
21 | putrequest()
22 v
23 Request-started
24 |
25 | ( putheader() )* endheaders()
26 v
27 Request-sent
28 |
29 | response = getresponse()
30 v
31 Unread-response [Response-headers-read]
32 |\____________________
33 | \
34 | response.read() | putrequest()
35 v v
36 Idle Req-started-unread-response
37 _______/|
38 / |
39 response.read() | | ( putheader() )* endheaders()
40 v v
41 Request-started Req-sent-unread-response
42 |
43 | response.read()
44 v
45 Request-sent
46
47This diagram presents the following rules:
48 -- a second request may not be started until {response-headers-read}
49 -- a response [object] cannot be retrieved until {request-sent}
50 -- there is no differentiation between an unread response body and a
51 partially read response body
52
53Note: this enforcement is applied by the HTTPConnection class. The
54 HTTPResponse class does not enforce this state machine, which
55 implies sophisticated clients may accelerate the request/response
56 pipeline. Caution should be taken, though: accelerating the states
57 beyond the above pattern may imply knowledge of the server's
58 connection-close behavior for certain requests. For example, it
59 is impossible to tell whether the server will close the connection
60 UNTIL the response headers have been read; this means that further
61 requests cannot be placed into the pipeline until it is known that
62 the server will NOT be closing the connection.
63
64Logical State __state __response
65------------- ------- ----------
66Idle _CS_IDLE None
67Request-started _CS_REQ_STARTED None
68Request-sent _CS_REQ_SENT None
69Unread-response _CS_IDLE <response_class>
70Req-started-unread-response _CS_REQ_STARTED <response_class>
71Req-sent-unread-response _CS_REQ_SENT <response_class>
Guido van Rossum41999c11997-12-09 00:12:23 +000072"""
Guido van Rossum23acc951994-02-21 16:36:04 +000073
Greg Stein5e0fa402000-06-26 08:28:01 +000074
Guido van Rossum23acc951994-02-21 16:36:04 +000075import socket
76import string
Guido van Rossum65ab98c1995-08-07 20:13:02 +000077import mimetools
Guido van Rossum23acc951994-02-21 16:36:04 +000078
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000079try:
Greg Steindd6eefb2000-07-18 09:09:48 +000080 from cStringIO import StringIO
Greg Stein5e0fa402000-06-26 08:28:01 +000081except ImportError:
Greg Steindd6eefb2000-07-18 09:09:48 +000082 from StringIO import StringIO
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000083
Guido van Rossum23acc951994-02-21 16:36:04 +000084HTTP_PORT = 80
Guido van Rossum09c8b6c1999-12-07 21:37:17 +000085HTTPS_PORT = 443
86
Greg Stein5e0fa402000-06-26 08:28:01 +000087_UNKNOWN = 'UNKNOWN'
88
89# connection states
90_CS_IDLE = 'Idle'
91_CS_REQ_STARTED = 'Request-started'
92_CS_REQ_SENT = 'Request-sent'
93
94
95class HTTPResponse:
Greg Steindd6eefb2000-07-18 09:09:48 +000096 def __init__(self, sock):
97 self.fp = sock.makefile('rb', 0)
Greg Stein5e0fa402000-06-26 08:28:01 +000098
Greg Steindd6eefb2000-07-18 09:09:48 +000099 self.msg = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000100
Greg Steindd6eefb2000-07-18 09:09:48 +0000101 # from the Status-Line of the response
102 self.version = _UNKNOWN # HTTP-Version
103 self.status = _UNKNOWN # Status-Code
104 self.reason = _UNKNOWN # Reason-Phrase
Greg Stein5e0fa402000-06-26 08:28:01 +0000105
Greg Steindd6eefb2000-07-18 09:09:48 +0000106 self.chunked = _UNKNOWN # is "chunked" being used?
107 self.chunk_left = _UNKNOWN # bytes left to read in current chunk
108 self.length = _UNKNOWN # number of bytes left in response
109 self.will_close = _UNKNOWN # conn will close at end of response
Greg Stein5e0fa402000-06-26 08:28:01 +0000110
Greg Steindd6eefb2000-07-18 09:09:48 +0000111 def begin(self):
112 if self.msg is not None:
113 # we've already started reading the response
114 return
Greg Stein5e0fa402000-06-26 08:28:01 +0000115
Greg Stein5e0fa402000-06-26 08:28:01 +0000116 line = self.fp.readline()
Greg Steindd6eefb2000-07-18 09:09:48 +0000117 try:
118 [version, status, reason] = string.split(line, None, 2)
119 except ValueError:
120 try:
121 [version, status] = string.split(line, None, 1)
122 reason = ""
123 except ValueError:
124 self.close()
125 raise BadStatusLine(line)
126 if version[:5] != 'HTTP/':
127 self.close()
128 raise BadStatusLine(line)
Greg Stein5e0fa402000-06-26 08:28:01 +0000129
Greg Steindd6eefb2000-07-18 09:09:48 +0000130 self.status = status = int(status)
131 self.reason = string.strip(reason)
Greg Stein5e0fa402000-06-26 08:28:01 +0000132
Greg Steindd6eefb2000-07-18 09:09:48 +0000133 if version == 'HTTP/1.0':
134 self.version = 10
135 elif version[:7] == 'HTTP/1.':
136 self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
137 else:
138 raise UnknownProtocol(version)
Greg Stein5e0fa402000-06-26 08:28:01 +0000139
Greg Steindd6eefb2000-07-18 09:09:48 +0000140 self.msg = mimetools.Message(self.fp, 0)
Greg Stein5e0fa402000-06-26 08:28:01 +0000141
Greg Steindd6eefb2000-07-18 09:09:48 +0000142 # don't let the msg keep an fp
143 self.msg.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000144
Greg Steindd6eefb2000-07-18 09:09:48 +0000145 # are we using the chunked-style of transfer encoding?
146 tr_enc = self.msg.getheader('transfer-encoding')
147 if tr_enc:
148 if string.lower(tr_enc) != 'chunked':
149 raise UnknownTransferEncoding()
150 self.chunked = 1
151 self.chunk_left = None
152 else:
153 self.chunked = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000154
Greg Steindd6eefb2000-07-18 09:09:48 +0000155 # will the connection close at the end of the response?
156 conn = self.msg.getheader('connection')
157 if conn:
158 conn = string.lower(conn)
159 # a "Connection: close" will always close the connection. if we
160 # don't see that and this is not HTTP/1.1, then the connection will
161 # close unless we see a Keep-Alive header.
162 self.will_close = string.find(conn, 'close') != -1 or \
163 ( self.version != 11 and \
164 not self.msg.getheader('keep-alive') )
165 else:
166 # for HTTP/1.1, the connection will always remain open
167 # otherwise, it will remain open IFF we see a Keep-Alive header
168 self.will_close = self.version != 11 and \
169 not self.msg.getheader('keep-alive')
Greg Stein5e0fa402000-06-26 08:28:01 +0000170
Greg Steindd6eefb2000-07-18 09:09:48 +0000171 # do we have a Content-Length?
172 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
173 length = self.msg.getheader('content-length')
174 if length and not self.chunked:
175 self.length = int(length)
176 else:
177 self.length = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000178
Greg Steindd6eefb2000-07-18 09:09:48 +0000179 # does the body have a fixed length? (of zero)
180 if (status == 204 or # No Content
181 status == 304 or # Not Modified
182 100 <= status < 200): # 1xx codes
183 self.length = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000184
Greg Steindd6eefb2000-07-18 09:09:48 +0000185 # if the connection remains open, and we aren't using chunked, and
186 # a content-length was not provided, then assume that the connection
187 # WILL close.
188 if not self.will_close and \
189 not self.chunked and \
190 self.length is None:
191 self.will_close = 1
Greg Stein5e0fa402000-06-26 08:28:01 +0000192
Greg Steindd6eefb2000-07-18 09:09:48 +0000193 # if there is no body, then close NOW. read() may never be called, thus
194 # we will never mark self as closed.
195 if self.length == 0:
196 self.close()
Greg Stein5e0fa402000-06-26 08:28:01 +0000197
Greg Steindd6eefb2000-07-18 09:09:48 +0000198 def close(self):
199 if self.fp:
200 self.fp.close()
201 self.fp = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000202
Greg Steindd6eefb2000-07-18 09:09:48 +0000203 def isclosed(self):
204 # NOTE: it is possible that we will not ever call self.close(). This
205 # case occurs when will_close is TRUE, length is None, and we
206 # read up to the last byte, but NOT past it.
207 #
208 # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
209 # called, meaning self.isclosed() is meaningful.
210 return self.fp is None
211
212 def read(self, amt=None):
213 if self.fp is None:
214 return ''
215
216 if self.chunked:
217 chunk_left = self.chunk_left
218 value = ''
219 while 1:
220 if chunk_left is None:
221 line = self.fp.readline()
222 i = string.find(line, ';')
223 if i >= 0:
224 line = line[:i] # strip chunk-extensions
225 chunk_left = string.atoi(line, 16)
226 if chunk_left == 0:
227 break
228 if amt is None:
229 value = value + self._safe_read(chunk_left)
230 elif amt < chunk_left:
231 value = value + self._safe_read(amt)
232 self.chunk_left = chunk_left - amt
233 return value
234 elif amt == chunk_left:
235 value = value + self._safe_read(amt)
236 self._safe_read(2) # toss the CRLF at the end of the chunk
237 self.chunk_left = None
238 return value
239 else:
240 value = value + self._safe_read(chunk_left)
241 amt = amt - chunk_left
242
243 # we read the whole chunk, get another
244 self._safe_read(2) # toss the CRLF at the end of the chunk
245 chunk_left = None
246
247 # read and discard trailer up to the CRLF terminator
248 ### note: we shouldn't have any trailers!
249 while 1:
250 line = self.fp.readline()
251 if line == '\r\n':
252 break
253
254 # we read everything; close the "file"
255 self.close()
256
257 return value
258
259 elif amt is None:
260 # unbounded read
261 if self.will_close:
262 s = self.fp.read()
263 else:
264 s = self._safe_read(self.length)
265 self.close() # we read everything
266 return s
267
268 if self.length is not None:
269 if amt > self.length:
270 # clip the read to the "end of response"
271 amt = self.length
272 self.length = self.length - amt
273
274 # we do not use _safe_read() here because this may be a .will_close
275 # connection, and the user is reading more bytes than will be provided
276 # (for example, reading in 1k chunks)
277 s = self.fp.read(amt)
278
279 # close our "file" if we know we should
280 ### I'm not sure about the len(s) < amt part; we should be safe because
281 ### we shouldn't be using non-blocking sockets
282 if self.length == 0 or len(s) < amt:
283 self.close()
284
285 return s
286
287 def _safe_read(self, amt):
288 """Read the number of bytes requested, compensating for partial reads.
289
290 Normally, we have a blocking socket, but a read() can be interrupted
291 by a signal (resulting in a partial read).
292
293 Note that we cannot distinguish between EOF and an interrupt when zero
294 bytes have been read. IncompleteRead() will be raised in this
295 situation.
296
297 This function should be used when <amt> bytes "should" be present for
298 reading. If the bytes are truly not available (due to EOF), then the
299 IncompleteRead exception can be used to detect the problem.
300 """
301 s = ''
302 while amt > 0:
303 chunk = self.fp.read(amt)
304 if not chunk:
305 raise IncompleteRead(s)
306 s = s + chunk
307 amt = amt - len(chunk)
308 return s
309
310 def getheader(self, name, default=None):
311 if self.msg is None:
312 raise ResponseNotReady()
313 return self.msg.getheader(name, default)
Greg Stein5e0fa402000-06-26 08:28:01 +0000314
315
316class HTTPConnection:
317
Greg Steindd6eefb2000-07-18 09:09:48 +0000318 _http_vsn = 11
319 _http_vsn_str = 'HTTP/1.1'
Greg Stein5e0fa402000-06-26 08:28:01 +0000320
Greg Steindd6eefb2000-07-18 09:09:48 +0000321 response_class = HTTPResponse
322 default_port = HTTP_PORT
323 auto_open = 1
Greg Stein5e0fa402000-06-26 08:28:01 +0000324
Greg Steindd6eefb2000-07-18 09:09:48 +0000325 def __init__(self, host, port=None):
326 self.sock = None
327 self.__response = None
328 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000329
Greg Steindd6eefb2000-07-18 09:09:48 +0000330 self._set_hostport(host, port)
Greg Stein5e0fa402000-06-26 08:28:01 +0000331
Greg Steindd6eefb2000-07-18 09:09:48 +0000332 def _set_hostport(self, host, port):
333 if port is None:
334 i = string.find(host, ':')
335 if i >= 0:
336 port = int(host[i+1:])
337 host = host[:i]
338 else:
339 port = self.default_port
340 self.host = host
341 self.port = port
Greg Stein5e0fa402000-06-26 08:28:01 +0000342
Greg Steindd6eefb2000-07-18 09:09:48 +0000343 def connect(self):
344 """Connect to the host and port specified in __init__."""
345 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
346 self.sock.connect((self.host, self.port))
Greg Stein5e0fa402000-06-26 08:28:01 +0000347
Greg Steindd6eefb2000-07-18 09:09:48 +0000348 def close(self):
349 """Close the connection to the HTTP server."""
350 if self.sock:
351 self.sock.close() # close it manually... there may be other refs
352 self.sock = None
353 if self.__response:
354 self.__response.close()
355 self.__response = None
356 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000357
Greg Steindd6eefb2000-07-18 09:09:48 +0000358 def send(self, str):
359 """Send `str' to the server."""
360 if self.sock is None:
361 if self.auto_open:
362 self.connect()
363 else:
364 raise NotConnected()
Greg Stein5e0fa402000-06-26 08:28:01 +0000365
Greg Steindd6eefb2000-07-18 09:09:48 +0000366 # send the data to the server. if we get a broken pipe, then close
367 # the socket. we want to reconnect when somebody tries to send again.
368 #
369 # NOTE: we DO propagate the error, though, because we cannot simply
370 # ignore the error... the caller will know if they can retry.
371 try:
372 self.sock.send(str)
373 except socket.error, v:
374 if v[0] == 32: # Broken pipe
375 self.close()
376 raise
Greg Stein5e0fa402000-06-26 08:28:01 +0000377
Greg Steindd6eefb2000-07-18 09:09:48 +0000378 def putrequest(self, method, url):
379 """Send a request to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000380
Greg Steindd6eefb2000-07-18 09:09:48 +0000381 `method' specifies an HTTP request method, e.g. 'GET'.
382 `url' specifies the object being requested, e.g. '/index.html'.
383 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000384
Greg Steindd6eefb2000-07-18 09:09:48 +0000385 # check if a prior response has been completed
386 if self.__response and self.__response.isclosed():
387 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000388
Greg Steindd6eefb2000-07-18 09:09:48 +0000389 #
390 # in certain cases, we cannot issue another request on this connection.
391 # this occurs when:
392 # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
393 # 2) a response to a previous request has signalled that it is going
394 # to close the connection upon completion.
395 # 3) the headers for the previous response have not been read, thus
396 # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
397 #
398 # if there is no prior response, then we can request at will.
399 #
400 # if point (2) is true, then we will have passed the socket to the
401 # response (effectively meaning, "there is no prior response"), and
402 # will open a new one when a new request is made.
403 #
404 # Note: if a prior response exists, then we *can* start a new request.
405 # We are not allowed to begin fetching the response to this new
406 # request, however, until that prior response is complete.
407 #
408 if self.__state == _CS_IDLE:
409 self.__state = _CS_REQ_STARTED
410 else:
411 raise CannotSendRequest()
Greg Stein5e0fa402000-06-26 08:28:01 +0000412
Greg Steindd6eefb2000-07-18 09:09:48 +0000413 if not url:
414 url = '/'
415 str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000416
Greg Steindd6eefb2000-07-18 09:09:48 +0000417 try:
418 self.send(str)
419 except socket.error, v:
420 # trap 'Broken pipe' if we're allowed to automatically reconnect
421 if v[0] != 32 or not self.auto_open:
422 raise
423 # try one more time (the socket was closed; this will reopen)
424 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000425
Greg Steindd6eefb2000-07-18 09:09:48 +0000426 if self._http_vsn == 11:
427 # Issue some standard headers for better HTTP/1.1 compliance
Greg Stein5e0fa402000-06-26 08:28:01 +0000428
Greg Steindd6eefb2000-07-18 09:09:48 +0000429 # this header is issued *only* for HTTP/1.1 connections. more
430 # specifically, this means it is only issued when the client uses
431 # the new HTTPConnection() class. backwards-compat clients will
432 # be using HTTP/1.0 and those clients may be issuing this header
433 # themselves. we should NOT issue it twice; some web servers (such
434 # as Apache) barf when they see two Host: headers
435 self.putheader('Host', self.host)
Greg Stein5e0fa402000-06-26 08:28:01 +0000436
Greg Steindd6eefb2000-07-18 09:09:48 +0000437 # note: we are assuming that clients will not attempt to set these
438 # headers since *this* library must deal with the
439 # consequences. this also means that when the supporting
440 # libraries are updated to recognize other forms, then this
441 # code should be changed (removed or updated).
Greg Stein5e0fa402000-06-26 08:28:01 +0000442
Greg Steindd6eefb2000-07-18 09:09:48 +0000443 # we only want a Content-Encoding of "identity" since we don't
444 # support encodings such as x-gzip or x-deflate.
445 self.putheader('Accept-Encoding', 'identity')
Greg Stein5e0fa402000-06-26 08:28:01 +0000446
Greg Steindd6eefb2000-07-18 09:09:48 +0000447 # we can accept "chunked" Transfer-Encodings, but no others
448 # NOTE: no TE header implies *only* "chunked"
449 #self.putheader('TE', 'chunked')
Greg Stein5e0fa402000-06-26 08:28:01 +0000450
Greg Steindd6eefb2000-07-18 09:09:48 +0000451 # if TE is supplied in the header, then it must appear in a
452 # Connection header.
453 #self.putheader('Connection', 'TE')
Greg Stein5e0fa402000-06-26 08:28:01 +0000454
Greg Steindd6eefb2000-07-18 09:09:48 +0000455 else:
456 # For HTTP/1.0, the server will assume "not chunked"
457 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000458
Greg Steindd6eefb2000-07-18 09:09:48 +0000459 def putheader(self, header, value):
460 """Send a request header line to the server.
Greg Stein5e0fa402000-06-26 08:28:01 +0000461
Greg Steindd6eefb2000-07-18 09:09:48 +0000462 For example: h.putheader('Accept', 'text/html')
463 """
464 if self.__state != _CS_REQ_STARTED:
465 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000466
Greg Steindd6eefb2000-07-18 09:09:48 +0000467 str = '%s: %s\r\n' % (header, value)
468 self.send(str)
Greg Stein5e0fa402000-06-26 08:28:01 +0000469
Greg Steindd6eefb2000-07-18 09:09:48 +0000470 def endheaders(self):
471 """Indicate that the last header line has been sent to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000472
Greg Steindd6eefb2000-07-18 09:09:48 +0000473 if self.__state == _CS_REQ_STARTED:
474 self.__state = _CS_REQ_SENT
475 else:
476 raise CannotSendHeader()
Greg Stein5e0fa402000-06-26 08:28:01 +0000477
Greg Steindd6eefb2000-07-18 09:09:48 +0000478 self.send('\r\n')
Greg Stein5e0fa402000-06-26 08:28:01 +0000479
Greg Steindd6eefb2000-07-18 09:09:48 +0000480 def request(self, method, url, body=None, headers={}):
481 """Send a complete request to the server."""
Greg Stein5e0fa402000-06-26 08:28:01 +0000482
Greg Steindd6eefb2000-07-18 09:09:48 +0000483 try:
484 self._send_request(method, url, body, headers)
485 except socket.error, v:
486 # trap 'Broken pipe' if we're allowed to automatically reconnect
487 if v[0] != 32 or not self.auto_open:
488 raise
489 # try one more time
490 self._send_request(method, url, body, headers)
Greg Stein5e0fa402000-06-26 08:28:01 +0000491
Greg Steindd6eefb2000-07-18 09:09:48 +0000492 def _send_request(self, method, url, body, headers):
493 self.putrequest(method, url)
Greg Stein5e0fa402000-06-26 08:28:01 +0000494
Greg Steindd6eefb2000-07-18 09:09:48 +0000495 if body:
496 self.putheader('Content-Length', str(len(body)))
497 for hdr, value in headers.items():
498 self.putheader(hdr, value)
499 self.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000500
Greg Steindd6eefb2000-07-18 09:09:48 +0000501 if body:
502 self.send(body)
Greg Stein5e0fa402000-06-26 08:28:01 +0000503
Greg Steindd6eefb2000-07-18 09:09:48 +0000504 def getresponse(self):
505 "Get the response from the server."
Greg Stein5e0fa402000-06-26 08:28:01 +0000506
Greg Steindd6eefb2000-07-18 09:09:48 +0000507 # check if a prior response has been completed
508 if self.__response and self.__response.isclosed():
509 self.__response = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000510
Greg Steindd6eefb2000-07-18 09:09:48 +0000511 #
512 # if a prior response exists, then it must be completed (otherwise, we
513 # cannot read this response's header to determine the connection-close
514 # behavior)
515 #
516 # note: if a prior response existed, but was connection-close, then the
517 # socket and response were made independent of this HTTPConnection
518 # object since a new request requires that we open a whole new
519 # connection
520 #
521 # this means the prior response had one of two states:
522 # 1) will_close: this connection was reset and the prior socket and
523 # response operate independently
524 # 2) persistent: the response was retained and we await its
525 # isclosed() status to become true.
526 #
527 if self.__state != _CS_REQ_SENT or self.__response:
528 raise ResponseNotReady()
Greg Stein5e0fa402000-06-26 08:28:01 +0000529
Greg Steindd6eefb2000-07-18 09:09:48 +0000530 response = self.response_class(self.sock)
Greg Stein5e0fa402000-06-26 08:28:01 +0000531
Greg Steindd6eefb2000-07-18 09:09:48 +0000532 response.begin()
533 self.__state = _CS_IDLE
Greg Stein5e0fa402000-06-26 08:28:01 +0000534
Greg Steindd6eefb2000-07-18 09:09:48 +0000535 if response.will_close:
536 # this effectively passes the connection to the response
537 self.close()
538 else:
539 # remember this, so we can tell when it is complete
540 self.__response = response
Greg Stein5e0fa402000-06-26 08:28:01 +0000541
Greg Steindd6eefb2000-07-18 09:09:48 +0000542 return response
Greg Stein5e0fa402000-06-26 08:28:01 +0000543
544
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000545class FakeSocket:
Greg Steindd6eefb2000-07-18 09:09:48 +0000546 def __init__(self, sock, ssl):
547 self.__sock = sock
548 self.__ssl = ssl
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000549
Greg Steindd6eefb2000-07-18 09:09:48 +0000550 def makefile(self, mode): # hopefully, never have to write
551 if mode != 'r' and mode != 'rb':
552 raise UnimplementedFileMode()
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000553
Greg Steindd6eefb2000-07-18 09:09:48 +0000554 msgbuf = ""
555 while 1:
556 try:
557 msgbuf = msgbuf + self.__ssl.read()
558 except socket.sslerror, msg:
559 break
560 return StringIO(msgbuf)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000561
Greg Steindd6eefb2000-07-18 09:09:48 +0000562 def send(self, stuff, flags = 0):
563 return self.__ssl.write(stuff)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000564
Greg Steindd6eefb2000-07-18 09:09:48 +0000565 def recv(self, len = 1024, flags = 0):
566 return self.__ssl.read(len)
Guido van Rossum23acc951994-02-21 16:36:04 +0000567
Greg Steindd6eefb2000-07-18 09:09:48 +0000568 def __getattr__(self, attr):
569 return getattr(self.__sock, attr)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000570
Guido van Rossum23acc951994-02-21 16:36:04 +0000571
Greg Stein5e0fa402000-06-26 08:28:01 +0000572class HTTPSConnection(HTTPConnection):
Greg Steindd6eefb2000-07-18 09:09:48 +0000573 "This class allows communication via SSL."
Greg Stein5e0fa402000-06-26 08:28:01 +0000574
Greg Steindd6eefb2000-07-18 09:09:48 +0000575 default_port = HTTPS_PORT
Greg Stein5e0fa402000-06-26 08:28:01 +0000576
Greg Steindd6eefb2000-07-18 09:09:48 +0000577 def __init__(self, host, port=None, **x509):
578 keys = x509.keys()
579 try:
580 keys.remove('key_file')
581 except ValueError:
582 pass
583 try:
584 keys.remove('cert_file')
585 except ValueError:
586 pass
587 if keys:
588 raise IllegalKeywordArgument()
589 HTTPConnection.__init__(self, host, port)
590 self.key_file = x509.get('key_file')
591 self.cert_file = x509.get('cert_file')
Greg Stein5e0fa402000-06-26 08:28:01 +0000592
Greg Steindd6eefb2000-07-18 09:09:48 +0000593 def connect(self):
594 "Connect to a host on a given (SSL) port."
Greg Stein5e0fa402000-06-26 08:28:01 +0000595
Greg Steindd6eefb2000-07-18 09:09:48 +0000596 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
597 sock.connect((self.host, self.port))
598 ssl = socket.ssl(sock, self.key_file, self.cert_file)
599 self.sock = FakeSocket(sock, ssl)
Greg Stein5e0fa402000-06-26 08:28:01 +0000600
601
602class HTTP(HTTPConnection):
Greg Steindd6eefb2000-07-18 09:09:48 +0000603 "Compatibility class with httplib.py from 1.5."
Greg Stein5e0fa402000-06-26 08:28:01 +0000604
Greg Steindd6eefb2000-07-18 09:09:48 +0000605 _http_vsn = 10
606 _http_vsn_str = 'HTTP/1.0'
Greg Stein5e0fa402000-06-26 08:28:01 +0000607
Greg Steindd6eefb2000-07-18 09:09:48 +0000608 debuglevel = 0
Greg Stein5e0fa402000-06-26 08:28:01 +0000609
Greg Steindd6eefb2000-07-18 09:09:48 +0000610 def __init__(self, host='', port=None, **x509):
611 "Provide a default host, since the superclass requires one."
Greg Stein5e0fa402000-06-26 08:28:01 +0000612
Greg Steindd6eefb2000-07-18 09:09:48 +0000613 # some joker passed 0 explicitly, meaning default port
614 if port == 0:
615 port = None
Greg Stein5e0fa402000-06-26 08:28:01 +0000616
Greg Steindd6eefb2000-07-18 09:09:48 +0000617 # Note that we may pass an empty string as the host; this will throw
618 # an error when we attempt to connect. Presumably, the client code
619 # will call connect before then, with a proper host.
620 HTTPConnection.__init__(self, host, port)
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:
633 self._set_hostport(host, port)
634 HTTPConnection.connect(self)
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."
646 HTTPConnection.putheader(self, 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:
658 response = self.getresponse()
659 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
665 self.file = self.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):
678 HTTPConnection.close(self)
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
687
688class HTTPException(Exception):
Greg Steindd6eefb2000-07-18 09:09:48 +0000689 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000690
691class NotConnected(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000692 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000693
694class UnknownProtocol(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000695 def __init__(self, version):
696 self.version = version
Greg Stein5e0fa402000-06-26 08:28:01 +0000697
698class UnknownTransferEncoding(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000699 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000700
701class IllegalKeywordArgument(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000702 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000703
704class UnimplementedFileMode(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000705 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000706
707class IncompleteRead(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000708 def __init__(self, partial):
709 self.partial = partial
Greg Stein5e0fa402000-06-26 08:28:01 +0000710
711class ImproperConnectionState(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000712 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000713
714class CannotSendRequest(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000715 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000716
717class CannotSendHeader(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000718 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000719
720class ResponseNotReady(ImproperConnectionState):
Greg Steindd6eefb2000-07-18 09:09:48 +0000721 pass
Greg Stein5e0fa402000-06-26 08:28:01 +0000722
723class BadStatusLine(HTTPException):
Greg Steindd6eefb2000-07-18 09:09:48 +0000724 def __init__(self, line):
725 self.line = line
Greg Stein5e0fa402000-06-26 08:28:01 +0000726
727# for backwards compatibility
728error = HTTPException
729
730
731#
732# snarfed from httplib.py for now...
733#
Guido van Rossum23acc951994-02-21 16:36:04 +0000734def test():
Guido van Rossum41999c11997-12-09 00:12:23 +0000735 """Test this module.
736
737 The test consists of retrieving and displaying the Python
738 home page, along with the error code and error string returned
739 by the www.python.org server.
Guido van Rossum41999c11997-12-09 00:12:23 +0000740 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000741
Guido van Rossum41999c11997-12-09 00:12:23 +0000742 import sys
743 import getopt
744 opts, args = getopt.getopt(sys.argv[1:], 'd')
745 dl = 0
746 for o, a in opts:
747 if o == '-d': dl = dl + 1
748 host = 'www.python.org'
749 selector = '/'
750 if args[0:]: host = args[0]
751 if args[1:]: selector = args[1]
752 h = HTTP()
753 h.set_debuglevel(dl)
754 h.connect(host)
755 h.putrequest('GET', selector)
756 h.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000757 status, reason, headers = h.getreply()
758 print 'status =', status
759 print 'reason =', reason
Guido van Rossum41999c11997-12-09 00:12:23 +0000760 print
761 if headers:
762 for header in headers.headers: print string.strip(header)
763 print
764 print h.getfile().read()
Greg Stein5e0fa402000-06-26 08:28:01 +0000765
766 if hasattr(socket, 'ssl'):
Greg Steindd6eefb2000-07-18 09:09:48 +0000767 host = 'www.c2.net'
768 hs = HTTPS()
769 hs.connect(host)
770 hs.putrequest('GET', selector)
771 hs.endheaders()
772 status, reason, headers = hs.getreply()
773 print 'status =', status
774 print 'reason =', reason
775 print
776 if headers:
777 for header in headers.headers: print string.strip(header)
778 print
779 print hs.getfile().read()
Guido van Rossum23acc951994-02-21 16:36:04 +0000780
Guido van Rossuma0dfc7a1995-09-07 19:28:19 +0000781
Guido van Rossum23acc951994-02-21 16:36:04 +0000782if __name__ == '__main__':
Guido van Rossum41999c11997-12-09 00:12:23 +0000783 test()