blob: 5c0dacd0d39892a446f345e13695d2bfc7451b5e [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 Stein5e0fa402000-06-26 08:28:01 +000080 from cStringIO import StringIO
81except ImportError:
82 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:
96 def __init__(self, sock):
97 self.fp = sock.makefile('rb', 0)
98
99 self.msg = None
100
101 # 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
105
106 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 # connection will close at end of response
110
111 def begin(self):
112 if self.msg is not None:
113 # we've already started reading the response
114 return
115
116 line = self.fp.readline()
117 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)
129
130 self.status = status = int(status)
131 self.reason = string.strip(reason)
132
133 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)
139
140 self.msg = mimetools.Message(self.fp, 0)
141
142 # don't let the msg keep an fp
143 self.msg.fp = None
144
145 # 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
154
155 # 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')
170
171 # 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
178
179 # 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
184
185 # 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
192
193 # 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()
197
198 def close(self):
199 if self.fp:
200 self.fp.close()
201 self.fp = None
202
203 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 situation.
295
296 This function should be used when <amt> bytes "should" be present for
297 reading. If the bytes are truly not available (due to EOF), then the
298 IncompleteRead exception can be used to detect the problem.
299 """
300 s = ''
301 while amt > 0:
302 chunk = self.fp.read(amt)
303 if not chunk:
304 raise IncompleteRead(s)
305 s = s + chunk
306 amt = amt - len(chunk)
307 return s
308
309 def getheader(self, name, default=None):
310 if self.msg is None:
311 raise ResponseNotReady()
312 return self.msg.getheader(name, default)
313
314
315class HTTPConnection:
316
317 _http_vsn = 11
318 _http_vsn_str = 'HTTP/1.1'
319
320 response_class = HTTPResponse
321 default_port = HTTP_PORT
322 auto_open = 1
323
324 def __init__(self, host, port=None):
325 self.sock = None
326 self.__response = None
327 self.__state = _CS_IDLE
328
329 self._set_hostport(host, port)
330
331 def _set_hostport(self, host, port):
332 if port is None:
333 i = string.find(host, ':')
334 if i >= 0:
335 port = int(host[i+1:])
336 host = host[:i]
337 else:
338 port = self.default_port
339 self.host = host
340 self.port = port
341
342 def connect(self):
343 """Connect to the host and port specified in __init__."""
344 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
345 self.sock.connect((self.host, self.port))
346
347 def close(self):
348 """Close the connection to the HTTP server."""
349 if self.sock:
350 self.sock.close() # close it manually... there may be other refs
351 self.sock = None
352 if self.__response:
353 self.__response.close()
354 self.__response = None
355 self.__state = _CS_IDLE
356
357 def send(self, str):
358 """Send `str' to the server."""
359 if self.sock is None:
360 if self.auto_open:
361 self.connect()
362 else:
363 raise NotConnected()
364
365 # send the data to the server. if we get a broken pipe, then close
366 # the socket. we want to reconnect when somebody tries to send again.
367 #
368 # NOTE: we DO propagate the error, though, because we cannot simply
369 # ignore the error... the caller will know if they can retry.
370 try:
371 self.sock.send(str)
372 except socket.error, v:
373 if v[0] == 32: # Broken pipe
374 self.close()
375 raise
376
377 def putrequest(self, method, url):
378 """Send a request to the server.
379
380 `method' specifies an HTTP request method, e.g. 'GET'.
381 `url' specifies the object being requested, e.g. '/index.html'.
382 """
383
384 # check if a prior response has been completed
385 if self.__response and self.__response.isclosed():
386 self.__response = None
387
388 #
389 # in certain cases, we cannot issue another request on this connection.
390 # this occurs when:
391 # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
392 # 2) a response to a previous request has signalled that it is going
393 # to close the connection upon completion.
394 # 3) the headers for the previous response have not been read, thus
395 # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
396 #
397 # if there is no prior response, then we can request at will.
398 #
399 # if point (2) is true, then we will have passed the socket to the
400 # response (effectively meaning, "there is no prior response"), and will
401 # open a new one when a new request is made.
402 #
403 # Note: if a prior response exists, then we *can* start a new request.
404 # We are not allowed to begin fetching the response to this new
405 # request, however, until that prior response is complete.
406 #
407 if self.__state == _CS_IDLE:
408 self.__state = _CS_REQ_STARTED
409 else:
410 raise CannotSendRequest()
411
412 if not url:
413 url = '/'
414 str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
415
416 try:
417 self.send(str)
418 except socket.error, v:
419 # trap 'Broken pipe' if we're allowed to automatically reconnect
420 if v[0] != 32 or not self.auto_open:
421 raise
422 # try one more time (the socket was closed; this will reopen)
423 self.send(str)
424
425 if self._http_vsn == 11:
426 # Issue some standard headers for better HTTP/1.1 compliance
427
428 # this header is issued *only* for HTTP/1.1 connections. more
429 # specifically, this means it is only issued when the client uses
430 # the new HTTPConnection() class. backwards-compat clients will
431 # be using HTTP/1.0 and those clients may be issuing this header
432 # themselves. we should NOT issue it twice; some web servers (such
433 # as Apache) barf when they see two Host: headers
434 self.putheader('Host', self.host)
435
436 # note: we are assuming that clients will not attempt to set these
437 # headers since *this* library must deal with the consequences.
438 # this also means that when the supporting libraries are
439 # updated to recognize other forms, then this code should be
440 # changed (removed or updated).
441
442 # we only want a Content-Encoding of "identity" since we don't
443 # support encodings such as x-gzip or x-deflate.
444 self.putheader('Accept-Encoding', 'identity')
445
446 # we can accept "chunked" Transfer-Encodings, but no others
447 # NOTE: no TE header implies *only* "chunked"
448 #self.putheader('TE', 'chunked')
449
450 # if TE is supplied in the header, then it must appear in a
451 # Connection header.
452 #self.putheader('Connection', 'TE')
453
454 else:
455 # For HTTP/1.0, the server will assume "not chunked"
456 pass
457
458 def putheader(self, header, value):
459 """Send a request header line to the server.
460
461 For example: h.putheader('Accept', 'text/html')
462 """
463 if self.__state != _CS_REQ_STARTED:
464 raise CannotSendHeader()
465
466 str = '%s: %s\r\n' % (header, value)
467 self.send(str)
468
469 def endheaders(self):
470 """Indicate that the last header line has been sent to the server."""
471
472 if self.__state == _CS_REQ_STARTED:
473 self.__state = _CS_REQ_SENT
474 else:
475 raise CannotSendHeader()
476
477 self.send('\r\n')
478
479 def request(self, method, url, body=None, headers={}):
480 """Send a complete request to the server."""
481
482 try:
483 self._send_request(method, url, body, headers)
484 except socket.error, v:
485 # trap 'Broken pipe' if we're allowed to automatically reconnect
486 if v[0] != 32 or not self.auto_open:
487 raise
488 # try one more time
489 self._send_request(method, url, body, headers)
490
491 def _send_request(self, method, url, body, headers):
492 self.putrequest(method, url)
493
494 if body:
495 self.putheader('Content-Length', str(len(body)))
496 for hdr, value in headers.items():
497 self.putheader(hdr, value)
498 self.endheaders()
499
500 if body:
501 self.send(body)
502
503 def getresponse(self):
504 "Get the response from the server."
505
506 # check if a prior response has been completed
507 if self.__response and self.__response.isclosed():
508 self.__response = None
509
510 #
511 # if a prior response exists, then it must be completed (otherwise, we
512 # cannot read this response's header to determine the connection-close
513 # behavior)
514 #
515 # note: if a prior response existed, but was connection-close, then the
516 # socket and response were made independent of this HTTPConnection object
517 # since a new request requires that we open a whole new connection
518 #
519 # this means the prior response had one of two states:
520 # 1) will_close: this connection was reset and the prior socket and
521 # response operate independently
522 # 2) persistent: the response was retained and we await its isclosed()
523 # status to become true.
524 #
525 if self.__state != _CS_REQ_SENT or self.__response:
526 raise ResponseNotReady()
527
528 response = self.response_class(self.sock)
529
530 response.begin()
531 self.__state = _CS_IDLE
532
533 if response.will_close:
534 # this effectively passes the connection to the response
535 self.close()
536 else:
537 # remember this, so we can tell when it is complete
538 self.__response = response
539
540 return response
541
542
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000543class FakeSocket:
Greg Stein5e0fa402000-06-26 08:28:01 +0000544 def __init__(self, sock, ssl):
545 self.__sock = sock
546 self.__ssl = ssl
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000547
Greg Stein5e0fa402000-06-26 08:28:01 +0000548 def makefile(self, mode): # hopefully, never have to write
549 if mode != 'r' and mode != 'rb':
550 raise UnimplementedFileMode()
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000551
Greg Stein5e0fa402000-06-26 08:28:01 +0000552 msgbuf = ""
553 while 1:
554 try:
555 msgbuf = msgbuf + self.__ssl.read()
556 except socket.sslerror, msg:
557 break
558 return StringIO(msgbuf)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000559
Greg Stein5e0fa402000-06-26 08:28:01 +0000560 def send(self, stuff, flags = 0):
561 return self.__ssl.write(stuff)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000562
Greg Stein5e0fa402000-06-26 08:28:01 +0000563 def recv(self, len = 1024, flags = 0):
564 return self.__ssl.read(len)
Guido van Rossum23acc951994-02-21 16:36:04 +0000565
Greg Stein5e0fa402000-06-26 08:28:01 +0000566 def __getattr__(self, attr):
567 return getattr(self.__sock, attr)
Guido van Rossum09c8b6c1999-12-07 21:37:17 +0000568
Guido van Rossum23acc951994-02-21 16:36:04 +0000569
Greg Stein5e0fa402000-06-26 08:28:01 +0000570class HTTPSConnection(HTTPConnection):
571 "This class allows communication via SSL."
572
573 default_port = HTTPS_PORT
574
575 def __init__(self, host, port=None, **x509):
576 keys = x509.keys()
577 try:
578 keys.remove('key_file')
579 except ValueError:
580 pass
581 try:
582 keys.remove('cert_file')
583 except ValueError:
584 pass
585 if keys:
586 raise IllegalKeywordArgument()
587 HTTPConnection.__init__(self, host, port)
588 self.key_file = x509.get('key_file')
589 self.cert_file = x509.get('cert_file')
590
591 def connect(self):
592 "Connect to a host on a given (SSL) port."
593
594 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
595 sock.connect((self.host, self.port))
596 ssl = socket.ssl(sock, self.key_file, self.cert_file)
597 self.sock = FakeSocket(sock, ssl)
598
599
600class HTTP(HTTPConnection):
601 "Compatibility class with httplib.py from 1.5."
602
603 _http_vsn = 10
604 _http_vsn_str = 'HTTP/1.0'
605
606 debuglevel = 0
607
608 def __init__(self, host='', port=None, **x509):
609 "Provide a default host, since the superclass requires one."
610
611 # some joker passed 0 explicitly, meaning default port
612 if port == 0:
613 port = None
614
615 # Note that we may pass an empty string as the host; this will throw
616 # an error when we attempt to connect. Presumably, the client code
617 # will call connect before then, with a proper host.
618 HTTPConnection.__init__(self, host, port)
619
620 # we never actually use these for anything, but we keep them here for
621 # compatibility with post-1.5.2 CVS.
622 self.key_file = x509.get('key_file')
623 self.cert_file = x509.get('cert_file')
624
625 self.file = None
626
627 def connect(self, host=None, port=None):
628 "Accept arguments to set the host/port, since the superclass doesn't."
629
630 if host is not None:
631 self._set_hostport(host, port)
632 HTTPConnection.connect(self)
633
634 def set_debuglevel(self, debuglevel):
635 "The class no longer supports the debuglevel."
636 pass
637
638 def getfile(self):
639 "Provide a getfile, since the superclass' does not use this concept."
640 return self.file
641
642 def putheader(self, header, *values):
643 "The superclass allows only one value argument."
644 HTTPConnection.putheader(self, header, string.joinfields(values, '\r\n\t'))
645
646 def getreply(self):
647 """Compat definition since superclass does not define it.
648
649 Returns a tuple consisting of:
650 - server status code (e.g. '200' if all goes well)
651 - server "reason" corresponding to status code
652 - any RFC822 headers in the response from the server
653 """
654 try:
655 response = self.getresponse()
656 except BadStatusLine, e:
657 ### hmm. if getresponse() ever closes the socket on a bad request,
658 ### then we are going to have problems with self.sock
659
660 ### should we keep this behavior? do people use it?
661 # keep the socket open (as a file), and return it
662 self.file = self.sock.makefile('rb', 0)
663
664 # close our socket -- we want to restart after any protocol error
665 self.close()
666
667 self.headers = None
668 return -1, e.line, None
669
670 self.headers = response.msg
671 self.file = response.fp
672 return response.status, response.reason, response.msg
673
674 def close(self):
675 HTTPConnection.close(self)
676
677 # note that self.file == response.fp, which gets closed by the
678 # superclass. just clear the object ref here.
679 ### hmm. messy. if status==-1, then self.file is owned by us.
680 ### well... we aren't explicitly closing, but losing this ref will do it
681 self.file = None
682
683
684class HTTPException(Exception):
685 pass
686
687class NotConnected(HTTPException):
688 pass
689
690class UnknownProtocol(HTTPException):
691 def __init__(self, version):
692 self.version = version
693
694class UnknownTransferEncoding(HTTPException):
695 pass
696
697class IllegalKeywordArgument(HTTPException):
698 pass
699
700class UnimplementedFileMode(HTTPException):
701 pass
702
703class IncompleteRead(HTTPException):
704 def __init__(self, partial):
705 self.partial = partial
706
707class ImproperConnectionState(HTTPException):
708 pass
709
710class CannotSendRequest(ImproperConnectionState):
711 pass
712
713class CannotSendHeader(ImproperConnectionState):
714 pass
715
716class ResponseNotReady(ImproperConnectionState):
717 pass
718
719class BadStatusLine(HTTPException):
720 def __init__(self, line):
721 self.line = line
722
723# for backwards compatibility
724error = HTTPException
725
726
727#
728# snarfed from httplib.py for now...
729#
Guido van Rossum23acc951994-02-21 16:36:04 +0000730def test():
Guido van Rossum41999c11997-12-09 00:12:23 +0000731 """Test this module.
732
733 The test consists of retrieving and displaying the Python
734 home page, along with the error code and error string returned
735 by the www.python.org server.
Guido van Rossum41999c11997-12-09 00:12:23 +0000736 """
Greg Stein5e0fa402000-06-26 08:28:01 +0000737
Guido van Rossum41999c11997-12-09 00:12:23 +0000738 import sys
739 import getopt
740 opts, args = getopt.getopt(sys.argv[1:], 'd')
741 dl = 0
742 for o, a in opts:
743 if o == '-d': dl = dl + 1
744 host = 'www.python.org'
745 selector = '/'
746 if args[0:]: host = args[0]
747 if args[1:]: selector = args[1]
748 h = HTTP()
749 h.set_debuglevel(dl)
750 h.connect(host)
751 h.putrequest('GET', selector)
752 h.endheaders()
Greg Stein5e0fa402000-06-26 08:28:01 +0000753 status, reason, headers = h.getreply()
754 print 'status =', status
755 print 'reason =', reason
Guido van Rossum41999c11997-12-09 00:12:23 +0000756 print
757 if headers:
758 for header in headers.headers: print string.strip(header)
759 print
760 print h.getfile().read()
Greg Stein5e0fa402000-06-26 08:28:01 +0000761
762 if hasattr(socket, 'ssl'):
763 host = 'www.c2.net'
764 hs = HTTPS()
765 hs.connect(host)
766 hs.putrequest('GET', selector)
767 hs.endheaders()
768 status, reason, headers = hs.getreply()
769 print 'status =', status
770 print 'reason =', reason
771 print
772 if headers:
773 for header in headers.headers: print string.strip(header)
774 print
775 print hs.getfile().read()
Guido van Rossum23acc951994-02-21 16:36:04 +0000776
Guido van Rossuma0dfc7a1995-09-07 19:28:19 +0000777
Guido van Rossum23acc951994-02-21 16:36:04 +0000778if __name__ == '__main__':
Guido van Rossum41999c11997-12-09 00:12:23 +0000779 test()