Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(75898)

Delta Between Two Patch Sets: Lib/httplib.py

Issue 16037: httplib: header parsing is not delimited
Left Patch Set: Created 5 years, 9 months ago
Right Patch Set: Created 4 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Lib/test/test_httplib.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 """HTTP/1.1 client library 1 r"""HTTP/1.1 client library
2 2
3 <intro stuff goes here> 3 <intro stuff goes here>
4 <other stuff, too> 4 <other stuff, too>
5 5
6 HTTPConnection goes through a number of "states", which define when a client 6 HTTPConnection goes through a number of "states", which define when a client
7 may legally make another request or fetch the response for a particular 7 may legally make another request or fetch the response for a particular
8 request. This diagram details these state transitions: 8 request. This diagram details these state transitions:
9 9
10 (null) 10 (null)
11 | 11 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 ------------- ------- ---------- 60 ------------- ------- ----------
61 Idle _CS_IDLE None 61 Idle _CS_IDLE None
62 Request-started _CS_REQ_STARTED None 62 Request-started _CS_REQ_STARTED None
63 Request-sent _CS_REQ_SENT None 63 Request-sent _CS_REQ_SENT None
64 Unread-response _CS_IDLE <response_class> 64 Unread-response _CS_IDLE <response_class>
65 Req-started-unread-response _CS_REQ_STARTED <response_class> 65 Req-started-unread-response _CS_REQ_STARTED <response_class>
66 Req-sent-unread-response _CS_REQ_SENT <response_class> 66 Req-sent-unread-response _CS_REQ_SENT <response_class>
67 """ 67 """
68 68
69 from array import array 69 from array import array
70 import os
70 import socket 71 import socket
71 from sys import py3kwarning 72 from sys import py3kwarning
72 from urlparse import urlsplit 73 from urlparse import urlsplit
73 import warnings 74 import warnings
74 with warnings.catch_warnings(): 75 with warnings.catch_warnings():
75 if py3kwarning: 76 if py3kwarning:
76 warnings.filterwarnings("ignore", ".*mimetools has been removed", 77 warnings.filterwarnings("ignore", ".*mimetools has been removed",
77 DeprecationWarning) 78 DeprecationWarning)
78 import mimetools 79 import mimetools
79 80
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 501: 'Not Implemented', 205 501: 'Not Implemented',
205 502: 'Bad Gateway', 206 502: 'Bad Gateway',
206 503: 'Service Unavailable', 207 503: 'Service Unavailable',
207 504: 'Gateway Timeout', 208 504: 'Gateway Timeout',
208 505: 'HTTP Version Not Supported', 209 505: 'HTTP Version Not Supported',
209 } 210 }
210 211
211 # maximal amount of data to read at one time in _safe_read 212 # maximal amount of data to read at one time in _safe_read
212 MAXAMOUNT = 1048576 213 MAXAMOUNT = 1048576
213 214
214 # maximum amount of headers accepted 215 # maximal line length when calling readline().
216 _MAXLINE = 65536
215 _MAXHEADERS = 100 217 _MAXHEADERS = 100
216
217 218
218 class HTTPMessage(mimetools.Message): 219 class HTTPMessage(mimetools.Message):
219 220
220 def addheader(self, key, value): 221 def addheader(self, key, value):
221 """Add header for field key handling repeats.""" 222 """Add header for field key handling repeats."""
222 prev = self.dict.get(key) 223 prev = self.dict.get(key)
223 if prev is None: 224 if prev is None:
224 self.dict[key] = value 225 self.dict[key] = value
225 else: 226 else:
226 combined = ", ".join((prev, value)) 227 combined = ", ".join((prev, value))
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 self.status = '' 266 self.status = ''
266 headerseen = "" 267 headerseen = ""
267 firstline = 1 268 firstline = 1
268 startofline = unread = tell = None 269 startofline = unread = tell = None
269 if hasattr(self.fp, 'unread'): 270 if hasattr(self.fp, 'unread'):
270 unread = self.fp.unread 271 unread = self.fp.unread
271 elif self.seekable: 272 elif self.seekable:
272 tell = self.fp.tell 273 tell = self.fp.tell
273 while True: 274 while True:
274 if len(hlist) > _MAXHEADERS: 275 if len(hlist) > _MAXHEADERS:
275 raise TooManyHeaders() 276 raise HTTPException("got more than %d headers" % _MAXHEADERS)
276 if tell: 277 if tell:
277 try: 278 try:
278 startofline = tell() 279 startofline = tell()
279 except IOError: 280 except IOError:
280 startofline = tell = None 281 startofline = tell = None
281 self.seekable = 0 282 self.seekable = 0
282 line = self.fp.readline() 283 line = self.fp.readline(_MAXLINE + 1)
284 if len(line) > _MAXLINE:
285 raise LineTooLong("header line")
283 if not line: 286 if not line:
284 self.status = 'EOF in headers' 287 self.status = 'EOF in headers'
285 break 288 break
286 # Skip unix From name time lines 289 # Skip unix From name time lines
287 if firstline and line.startswith('From '): 290 if firstline and line.startswith('From '):
288 self.unixfrom = self.unixfrom + line 291 self.unixfrom = self.unixfrom + line
289 continue 292 continue
290 firstline = 0 293 firstline = 0
291 if headerseen and line[0] in ' \t': 294 if headerseen and line[0] in ' \t':
292 # XXX Not sure if continuation lines are handled properly 295 # XXX Not sure if continuation lines are handled properly
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 class HTTPResponse: 328 class HTTPResponse:
326 329
327 # strict: If true, raise BadStatusLine if the status line can't be 330 # strict: If true, raise BadStatusLine if the status line can't be
328 # parsed as a valid HTTP/1.0 or 1.1 status line. By default it is 331 # parsed as a valid HTTP/1.0 or 1.1 status line. By default it is
329 # false because it prevents clients from talking to HTTP/0.9 332 # false because it prevents clients from talking to HTTP/0.9
330 # servers. Note that a response with a sufficiently corrupted 333 # servers. Note that a response with a sufficiently corrupted
331 # status line will look like an HTTP/0.9 response. 334 # status line will look like an HTTP/0.9 response.
332 335
333 # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details. 336 # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details.
334 337
335 def __init__(self, sock, debuglevel=0, strict=0, method=None): 338 def __init__(self, sock, debuglevel=0, strict=0, method=None, buffering=Fals e):
336 self.fp = sock.makefile('rb', 0) 339 if buffering:
340 # The caller won't be using any sock.recv() calls, so buffering
341 # is fine and recommended for performance.
342 self.fp = sock.makefile('rb')
343 else:
344 # The buffer size is specified as zero, because the headers of
345 # the response are read with readline(). If the reads were
346 # buffered the readline() calls could consume some of the
347 # response, which make be read via a recv() on the underlying
348 # socket.
349 self.fp = sock.makefile('rb', 0)
337 self.debuglevel = debuglevel 350 self.debuglevel = debuglevel
338 self.strict = strict 351 self.strict = strict
339 self._method = method 352 self._method = method
340 353
341 self.msg = None 354 self.msg = None
342 355
343 # from the Status-Line of the response 356 # from the Status-Line of the response
344 self.version = _UNKNOWN # HTTP-Version 357 self.version = _UNKNOWN # HTTP-Version
345 self.status = _UNKNOWN # Status-Code 358 self.status = _UNKNOWN # Status-Code
346 self.reason = _UNKNOWN # Reason-Phrase 359 self.reason = _UNKNOWN # Reason-Phrase
347 360
348 self.chunked = _UNKNOWN # is "chunked" being used? 361 self.chunked = _UNKNOWN # is "chunked" being used?
349 self.chunk_left = _UNKNOWN # bytes left to read in current chunk 362 self.chunk_left = _UNKNOWN # bytes left to read in current chunk
350 self.length = _UNKNOWN # number of bytes left in response 363 self.length = _UNKNOWN # number of bytes left in response
351 self.will_close = _UNKNOWN # conn will close at end of response 364 self.will_close = _UNKNOWN # conn will close at end of response
352 365
353 def _read_status(self): 366 def _read_status(self):
354 # Initialize with Simple-Response defaults 367 # Initialize with Simple-Response defaults
355 line = self.fp.readline() 368 line = self.fp.readline(_MAXLINE + 1)
369 if len(line) > _MAXLINE:
370 raise LineTooLong("header line")
356 if self.debuglevel > 0: 371 if self.debuglevel > 0:
357 print "reply:", repr(line) 372 print "reply:", repr(line)
358 if not line: 373 if not line:
359 # Presumably, the server closed the connection before 374 # Presumably, the server closed the connection before
360 # sending a valid response. 375 # sending a valid response.
361 raise BadStatusLine(line) 376 raise BadStatusLine(line)
362 try: 377 try:
363 [version, status, reason] = line.split(None, 2) 378 [version, status, reason] = line.split(None, 2)
364 except ValueError: 379 except ValueError:
365 try: 380 try:
(...skipping 26 matching lines...) Expand all
392 # we've already started reading the response 407 # we've already started reading the response
393 return 408 return
394 409
395 # read until we get a non-100 response 410 # read until we get a non-100 response
396 while True: 411 while True:
397 version, status, reason = self._read_status() 412 version, status, reason = self._read_status()
398 if status != CONTINUE: 413 if status != CONTINUE:
399 break 414 break
400 # skip the header from the 100 response 415 # skip the header from the 100 response
401 while True: 416 while True:
402 skip = self.fp.readline().strip() 417 skip = self.fp.readline(_MAXLINE + 1)
418 if len(skip) > _MAXLINE:
419 raise LineTooLong("header line")
420 skip = skip.strip()
403 if not skip: 421 if not skip:
404 break 422 break
405 if self.debuglevel > 0: 423 if self.debuglevel > 0:
406 print "header:", skip 424 print "header:", skip
407 425
408 self.status = status 426 self.status = status
409 self.reason = reason.strip() 427 self.reason = reason.strip()
410 if version == 'HTTP/1.0': 428 if version == 'HTTP/1.0':
411 self.version = 10 429 self.version = 10
412 elif version.startswith('HTTP/1.'): 430 elif version.startswith('HTTP/1.'):
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 return '' 543 return ''
526 544
527 if self.chunked: 545 if self.chunked:
528 return self._read_chunked(amt) 546 return self._read_chunked(amt)
529 547
530 if amt is None: 548 if amt is None:
531 # unbounded read 549 # unbounded read
532 if self.length is None: 550 if self.length is None:
533 s = self.fp.read() 551 s = self.fp.read()
534 else: 552 else:
535 s = self._safe_read(self.length) 553 try:
554 s = self._safe_read(self.length)
555 except IncompleteRead:
556 self.close()
557 raise
536 self.length = 0 558 self.length = 0
537 self.close() # we read everything 559 self.close() # we read everything
538 return s 560 return s
539 561
540 if self.length is not None: 562 if self.length is not None:
541 if amt > self.length: 563 if amt > self.length:
542 # clip the read to the "end of response" 564 # clip the read to the "end of response"
543 amt = self.length 565 amt = self.length
544 566
545 # we do not use _safe_read() here because this may be a .will_close 567 # we do not use _safe_read() here because this may be a .will_close
546 # connection, and the user is reading more bytes than will be provided 568 # connection, and the user is reading more bytes than will be provided
547 # (for example, reading in 1k chunks) 569 # (for example, reading in 1k chunks)
548 s = self.fp.read(amt) 570 s = self.fp.read(amt)
571 if not s and amt:
572 # Ideally, we would raise IncompleteRead if the content-length
573 # wasn't satisfied, but it might break compatibility.
574 self.close()
549 if self.length is not None: 575 if self.length is not None:
550 self.length -= len(s) 576 self.length -= len(s)
551 if not self.length: 577 if not self.length:
552 self.close() 578 self.close()
579
553 return s 580 return s
554 581
555 def _read_chunked(self, amt): 582 def _read_chunked(self, amt):
556 assert self.chunked != _UNKNOWN 583 assert self.chunked != _UNKNOWN
557 chunk_left = self.chunk_left 584 chunk_left = self.chunk_left
558 value = [] 585 value = []
559 while True: 586 while True:
560 if chunk_left is None: 587 if chunk_left is None:
561 line = self.fp.readline() 588 line = self.fp.readline(_MAXLINE + 1)
589 if len(line) > _MAXLINE:
590 raise LineTooLong("chunk size")
562 i = line.find(';') 591 i = line.find(';')
563 if i >= 0: 592 if i >= 0:
564 line = line[:i] # strip chunk-extensions 593 line = line[:i] # strip chunk-extensions
565 try: 594 try:
566 chunk_left = int(line, 16) 595 chunk_left = int(line, 16)
567 except ValueError: 596 except ValueError:
568 # close the connection as protocol synchronisation is 597 # close the connection as protocol synchronisation is
569 # probably lost 598 # probably lost
570 self.close() 599 self.close()
571 raise IncompleteRead(''.join(value)) 600 raise IncompleteRead(''.join(value))
(...skipping 14 matching lines...) Expand all
586 value.append(self._safe_read(chunk_left)) 615 value.append(self._safe_read(chunk_left))
587 amt -= chunk_left 616 amt -= chunk_left
588 617
589 # we read the whole chunk, get another 618 # we read the whole chunk, get another
590 self._safe_read(2) # toss the CRLF at the end of the chunk 619 self._safe_read(2) # toss the CRLF at the end of the chunk
591 chunk_left = None 620 chunk_left = None
592 621
593 # read and discard trailer up to the CRLF terminator 622 # read and discard trailer up to the CRLF terminator
594 ### note: we shouldn't have any trailers! 623 ### note: we shouldn't have any trailers!
595 while True: 624 while True:
596 line = self.fp.readline() 625 line = self.fp.readline(_MAXLINE + 1)
626 if len(line) > _MAXLINE:
627 raise LineTooLong("trailer line")
597 if not line: 628 if not line:
598 # a vanishingly small number of sites EOF without 629 # a vanishingly small number of sites EOF without
599 # sending the trailer 630 # sending the trailer
600 break 631 break
601 if line == '\r\n': 632 if line == '\r\n':
602 break 633 break
603 634
604 # we read everything; close the "file" 635 # we read everything; close the "file"
605 self.close() 636 self.close()
606 637
607 return ''.join(value) 638 return ''.join(value)
608 639
609 def _safe_read(self, amt): 640 def _safe_read(self, amt):
610 """Read the number of bytes requested, compensating for partial reads. 641 """Read the number of bytes requested, compensating for partial reads.
611 642
612 Normally, we have a blocking socket, but a read() can be interrupted 643 Normally, we have a blocking socket, but a read() can be interrupted
613 by a signal (resulting in a partial read). 644 by a signal (resulting in a partial read).
614 645
615 Note that we cannot distinguish between EOF and an interrupt when zero 646 Note that we cannot distinguish between EOF and an interrupt when zero
616 bytes have been read. IncompleteRead() will be raised in this 647 bytes have been read. IncompleteRead() will be raised in this
617 situation. 648 situation.
618 649
619 This function should be used when <amt> bytes "should" be present for 650 This function should be used when <amt> bytes "should" be present for
620 reading. If the bytes are truly not available (due to EOF), then the 651 reading. If the bytes are truly not available (due to EOF), then the
621 IncompleteRead exception can be used to detect the problem. 652 IncompleteRead exception can be used to detect the problem.
622 """ 653 """
654 # NOTE(gps): As of svn r74426 socket._fileobject.read(x) will never
655 # return less than x bytes unless EOF is encountered. It now handles
656 # signal interruptions (socket.error EINTR) internally. This code
657 # never caught that exception anyways. It seems largely pointless.
658 # self.fp.read(amt) will work fine.
623 s = [] 659 s = []
624 while amt > 0: 660 while amt > 0:
625 chunk = self.fp.read(min(amt, MAXAMOUNT)) 661 chunk = self.fp.read(min(amt, MAXAMOUNT))
626 if not chunk: 662 if not chunk:
627 raise IncompleteRead(''.join(s), amt) 663 raise IncompleteRead(''.join(s), amt)
628 s.append(chunk) 664 s.append(chunk)
629 amt -= len(chunk) 665 amt -= len(chunk)
630 return ''.join(s) 666 return ''.join(s)
631 667
668 def fileno(self):
669 return self.fp.fileno()
670
632 def getheader(self, name, default=None): 671 def getheader(self, name, default=None):
633 if self.msg is None: 672 if self.msg is None:
634 raise ResponseNotReady() 673 raise ResponseNotReady()
635 return self.msg.getheader(name, default) 674 return self.msg.getheader(name, default)
636 675
637 def getheaders(self): 676 def getheaders(self):
638 """Return list of (header, value) tuples.""" 677 """Return list of (header, value) tuples."""
639 if self.msg is None: 678 if self.msg is None:
640 raise ResponseNotReady() 679 raise ResponseNotReady()
641 return self.msg.items() 680 return self.msg.items()
642 681
643 682
644 class HTTPConnection: 683 class HTTPConnection:
645 684
646 _http_vsn = 11 685 _http_vsn = 11
647 _http_vsn_str = 'HTTP/1.1' 686 _http_vsn_str = 'HTTP/1.1'
648 687
649 response_class = HTTPResponse 688 response_class = HTTPResponse
650 default_port = HTTP_PORT 689 default_port = HTTP_PORT
651 auto_open = 1 690 auto_open = 1
652 debuglevel = 0 691 debuglevel = 0
653 strict = 0 692 strict = 0
654 693
655 def __init__(self, host, port=None, strict=None, 694 def __init__(self, host, port=None, strict=None,
656 timeout=socket._GLOBAL_DEFAULT_TIMEOUT): 695 timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
657 self.timeout = timeout 696 self.timeout = timeout
697 self.source_address = source_address
658 self.sock = None 698 self.sock = None
659 self._buffer = [] 699 self._buffer = []
660 self.__response = None 700 self.__response = None
661 self.__state = _CS_IDLE 701 self.__state = _CS_IDLE
662 self._method = None 702 self._method = None
663 self._tunnel_host = None 703 self._tunnel_host = None
664 self._tunnel_port = None 704 self._tunnel_port = None
665 self._tunnel_headers = {} 705 self._tunnel_headers = {}
666
667 self._set_hostport(host, port)
668 if strict is not None: 706 if strict is not None:
669 self.strict = strict 707 self.strict = strict
670 708
671 def _set_tunnel(self, host, port=None, headers=None): 709 (self.host, self.port) = self._get_hostport(host, port)
672 """ Sets up the host and the port for the HTTP CONNECT Tunnelling. 710
711 # This is stored as an instance variable to allow unittests
712 # to replace with a suitable mock
713 self._create_connection = socket.create_connection
714
715 def set_tunnel(self, host, port=None, headers=None):
716 """ Set up host and port for HTTP CONNECT tunnelling.
717
718 In a connection that uses HTTP Connect tunneling, the host passed to the
719 constructor is used as proxy server that relays all communication to the
720 endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT
721 request to the proxy server when the connection is established.
722
723 This method must be called before the HTML connection has been
724 established.
673 725
674 The headers argument should be a mapping of extra HTTP headers 726 The headers argument should be a mapping of extra HTTP headers
675 to send with the CONNECT request. 727 to send with the CONNECT request.
676 """ 728 """
729 # Verify if this is required.
730 if self.sock:
731 raise RuntimeError("Can't setup tunnel for established connection.")
732
677 self._tunnel_host = host 733 self._tunnel_host = host
678 self._tunnel_port = port 734 self._tunnel_port = port
679 if headers: 735 if headers:
680 self._tunnel_headers = headers 736 self._tunnel_headers = headers
681 else: 737 else:
682 self._tunnel_headers.clear() 738 self._tunnel_headers.clear()
683 739
684 def _set_hostport(self, host, port): 740 def _get_hostport(self, host, port):
685 if port is None: 741 if port is None:
686 i = host.rfind(':') 742 i = host.rfind(':')
687 j = host.rfind(']') # ipv6 addresses have [...] 743 j = host.rfind(']') # ipv6 addresses have [...]
688 if i > j: 744 if i > j:
689 try: 745 try:
690 port = int(host[i+1:]) 746 port = int(host[i+1:])
691 except ValueError: 747 except ValueError:
692 raise InvalidURL("nonnumeric port: '%s'" % host[i+1:]) 748 if host[i+1:] == "": # http://foo.com:/ == http://foo.com/
749 port = self.default_port
750 else:
751 raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
693 host = host[:i] 752 host = host[:i]
694 else: 753 else:
695 port = self.default_port 754 port = self.default_port
696 if host and host[0] == '[' and host[-1] == ']': 755 if host and host[0] == '[' and host[-1] == ']':
697 host = host[1:-1] 756 host = host[1:-1]
698 self.host = host 757 return (host, port)
699 self.port = port
700 758
701 def set_debuglevel(self, level): 759 def set_debuglevel(self, level):
702 self.debuglevel = level 760 self.debuglevel = level
703 761
704 def _tunnel(self): 762 def _tunnel(self):
705 self._set_hostport(self._tunnel_host, self._tunnel_port) 763 (host, port) = self._get_hostport(self._tunnel_host, self._tunnel_port)
706 self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port)) 764 self.send("CONNECT %s:%d HTTP/1.0\r\n" % (host, port))
707 for header, value in self._tunnel_headers.iteritems(): 765 for header, value in self._tunnel_headers.iteritems():
708 self.send("%s: %s\r\n" % (header, value)) 766 self.send("%s: %s\r\n" % (header, value))
709 self.send("\r\n") 767 self.send("\r\n")
710 response = self.response_class(self.sock, strict = self.strict, 768 response = self.response_class(self.sock, strict = self.strict,
711 method = self._method) 769 method = self._method)
712 (version, code, message) = response._read_status() 770 (version, code, message) = response._read_status()
713 771
714 if code != 200: 772 if code != 200:
715 self.close() 773 self.close()
716 raise socket.error("Tunnel connection failed: %d %s" % (code, 774 raise socket.error("Tunnel connection failed: %d %s" % (code,
717 message.stri p())) 775 message.stri p()))
718 while True: 776 while True:
719 line = response.fp.readline() 777 line = response.fp.readline(_MAXLINE + 1)
720 if line == '\r\n': break 778 if len(line) > _MAXLINE:
779 raise LineTooLong("header line")
780 if not line:
781 # for sites which EOF without sending trailer
782 break
783 if line == '\r\n':
784 break
721 785
722 786
723 def connect(self): 787 def connect(self):
724 """Connect to the host and port specified in __init__.""" 788 """Connect to the host and port specified in __init__."""
725 self.sock = socket.create_connection((self.host,self.port), 789 self.sock = self._create_connection((self.host,self.port),
726 self.timeout) 790 self.timeout, self.source_address)
727 791
728 if self._tunnel_host: 792 if self._tunnel_host:
729 self._tunnel() 793 self._tunnel()
730 794
731 def close(self): 795 def close(self):
732 """Close the connection to the HTTP server.""" 796 """Close the connection to the HTTP server."""
733 if self.sock: 797 if self.sock:
734 self.sock.close() # close it manually... there may be other refs 798 self.sock.close() # close it manually... there may be other refs
735 self.sock = None 799 self.sock = None
736 if self.__response: 800 if self.__response:
737 self.__response.close() 801 self.__response.close()
738 self.__response = None 802 self.__response = None
739 self.__state = _CS_IDLE 803 self.__state = _CS_IDLE
740 804
741 def send(self, str): 805 def send(self, data):
742 """Send `str' to the server.""" 806 """Send `data' to the server."""
743 if self.sock is None: 807 if self.sock is None:
744 if self.auto_open: 808 if self.auto_open:
745 self.connect() 809 self.connect()
746 else: 810 else:
747 raise NotConnected() 811 raise NotConnected()
748 812
749 # send the data to the server. if we get a broken pipe, then close
750 # the socket. we want to reconnect when somebody tries to send again.
751 #
752 # NOTE: we DO propagate the error, though, because we cannot simply
753 # ignore the error... the caller will know if they can retry.
754 if self.debuglevel > 0: 813 if self.debuglevel > 0:
755 print "send:", repr(str) 814 print "send:", repr(data)
756 try: 815 blocksize = 8192
757 blocksize=8192 816 if hasattr(data,'read') and not isinstance(data, array):
758 if hasattr(str,'read') and not isinstance(str, array): 817 if self.debuglevel > 0: print "sendIng a read()able"
759 if self.debuglevel > 0: print "sendIng a read()able" 818 datablock = data.read(blocksize)
760 data=str.read(blocksize) 819 while datablock:
761 while data: 820 self.sock.sendall(datablock)
762 self.sock.sendall(data) 821 datablock = data.read(blocksize)
763 data=str.read(blocksize) 822 else:
764 else: 823 self.sock.sendall(data)
765 self.sock.sendall(str)
766 except socket.error, v:
767 if v.args[0] == 32: # Broken pipe
768 self.close()
769 raise
770 824
771 def _output(self, s): 825 def _output(self, s):
772 """Add a line of output to the current request buffer. 826 """Add a line of output to the current request buffer.
773 827
774 Assumes that the line does *not* end with \\r\\n. 828 Assumes that the line does *not* end with \\r\\n.
775 """ 829 """
776 self._buffer.append(s) 830 self._buffer.append(s)
777 831
778 def _send_output(self): 832 def _send_output(self, message_body=None):
779 """Send the currently buffered request and clear the buffer. 833 """Send the currently buffered request and clear the buffer.
780 834
781 Appends an extra \\r\\n to the buffer. 835 Appends an extra \\r\\n to the buffer.
836 A message_body may be specified, to be appended to the request.
782 """ 837 """
783 self._buffer.extend(("", "")) 838 self._buffer.extend(("", ""))
784 msg = "\r\n".join(self._buffer) 839 msg = "\r\n".join(self._buffer)
785 del self._buffer[:] 840 del self._buffer[:]
841 # If msg and message_body are sent in a single send() call,
842 # it will avoid performance problems caused by the interaction
843 # between delayed ack and the Nagle algorithm.
844 if isinstance(message_body, str):
845 msg += message_body
846 message_body = None
786 self.send(msg) 847 self.send(msg)
848 if message_body is not None:
849 #message_body was not a string (i.e. it is a file) and
850 #we must run the risk of Nagle
851 self.send(message_body)
787 852
788 def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): 853 def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
789 """Send a request to the server. 854 """Send a request to the server.
790 855
791 `method' specifies an HTTP request method, e.g. 'GET'. 856 `method' specifies an HTTP request method, e.g. 'GET'.
792 `url' specifies the object being requested, e.g. '/index.html'. 857 `url' specifies the object being requested, e.g. '/index.html'.
793 `skip_host' if True does not add automatically a 'Host:' header 858 `skip_host' if True does not add automatically a 'Host:' header
794 `skip_accept_encoding' if True does not add automatically an 859 `skip_accept_encoding' if True does not add automatically an
795 'Accept-Encoding:' header 860 'Accept-Encoding:' header
796 """ 861 """
(...skipping 23 matching lines...) Expand all
820 # 885 #
821 if self.__state == _CS_IDLE: 886 if self.__state == _CS_IDLE:
822 self.__state = _CS_REQ_STARTED 887 self.__state = _CS_REQ_STARTED
823 else: 888 else:
824 raise CannotSendRequest() 889 raise CannotSendRequest()
825 890
826 # Save the method we use, we need it later in the response phase 891 # Save the method we use, we need it later in the response phase
827 self._method = method 892 self._method = method
828 if not url: 893 if not url:
829 url = '/' 894 url = '/'
830 str = '%s %s %s' % (method, url, self._http_vsn_str) 895 hdr = '%s %s %s' % (method, url, self._http_vsn_str)
831 896
832 self._output(str) 897 self._output(hdr)
833 898
834 if self._http_vsn == 11: 899 if self._http_vsn == 11:
835 # Issue some standard headers for better HTTP/1.1 compliance 900 # Issue some standard headers for better HTTP/1.1 compliance
836 901
837 if not skip_host: 902 if not skip_host:
838 # this header is issued *only* for HTTP/1.1 903 # this header is issued *only* for HTTP/1.1
839 # connections. more specifically, this means it is 904 # connections. more specifically, this means it is
840 # only issued when the client uses the new 905 # only issued when the client uses the new
841 # HTTPConnection() class. backwards-compat clients 906 # HTTPConnection() class. backwards-compat clients
842 # will be using HTTP/1.0 and those clients may be 907 # will be using HTTP/1.0 and those clients may be
(...skipping 10 matching lines...) Expand all
853 if url.startswith('http'): 918 if url.startswith('http'):
854 nil, netloc, nil, nil, nil = urlsplit(url) 919 nil, netloc, nil, nil, nil = urlsplit(url)
855 920
856 if netloc: 921 if netloc:
857 try: 922 try:
858 netloc_enc = netloc.encode("ascii") 923 netloc_enc = netloc.encode("ascii")
859 except UnicodeEncodeError: 924 except UnicodeEncodeError:
860 netloc_enc = netloc.encode("idna") 925 netloc_enc = netloc.encode("idna")
861 self.putheader('Host', netloc_enc) 926 self.putheader('Host', netloc_enc)
862 else: 927 else:
928 if self._tunnel_host:
929 host = self._tunnel_host
930 port = self._tunnel_port
931 else:
932 host = self.host
933 port = self.port
934
863 try: 935 try:
864 host_enc = self.host.encode("ascii") 936 host_enc = host.encode("ascii")
865 except UnicodeEncodeError: 937 except UnicodeEncodeError:
866 host_enc = self.host.encode("idna") 938 host_enc = host.encode("idna")
867 if self.port == self.default_port: 939 # Wrap the IPv6 Host Header with [] (RFC 2732)
940 if host_enc.find(':') >= 0:
941 host_enc = "[" + host_enc + "]"
942 if port == self.default_port:
868 self.putheader('Host', host_enc) 943 self.putheader('Host', host_enc)
869 else: 944 else:
870 self.putheader('Host', "%s:%s" % (host_enc, self.port)) 945 self.putheader('Host', "%s:%s" % (host_enc, port))
871 946
872 # note: we are assuming that clients will not attempt to set these 947 # note: we are assuming that clients will not attempt to set these
873 # headers since *this* library must deal with the 948 # headers since *this* library must deal with the
874 # consequences. this also means that when the supporting 949 # consequences. this also means that when the supporting
875 # libraries are updated to recognize other forms, then this 950 # libraries are updated to recognize other forms, then this
876 # code should be changed (removed or updated). 951 # code should be changed (removed or updated).
877 952
878 # we only want a Content-Encoding of "identity" since we don't 953 # we only want a Content-Encoding of "identity" since we don't
879 # support encodings such as x-gzip or x-deflate. 954 # support encodings such as x-gzip or x-deflate.
880 if not skip_accept_encoding: 955 if not skip_accept_encoding:
881 self.putheader('Accept-Encoding', 'identity') 956 self.putheader('Accept-Encoding', 'identity')
882 957
883 # we can accept "chunked" Transfer-Encodings, but no others 958 # we can accept "chunked" Transfer-Encodings, but no others
884 # NOTE: no TE header implies *only* "chunked" 959 # NOTE: no TE header implies *only* "chunked"
885 #self.putheader('TE', 'chunked') 960 #self.putheader('TE', 'chunked')
886 961
887 # if TE is supplied in the header, then it must appear in a 962 # if TE is supplied in the header, then it must appear in a
888 # Connection header. 963 # Connection header.
889 #self.putheader('Connection', 'TE') 964 #self.putheader('Connection', 'TE')
890 965
891 else: 966 else:
892 # For HTTP/1.0, the server will assume "not chunked" 967 # For HTTP/1.0, the server will assume "not chunked"
893 pass 968 pass
894 969
895 def putheader(self, header, value): 970 def putheader(self, header, *values):
896 """Send a request header line to the server. 971 """Send a request header line to the server.
897 972
898 For example: h.putheader('Accept', 'text/html') 973 For example: h.putheader('Accept', 'text/html')
899 """ 974 """
900 if self.__state != _CS_REQ_STARTED: 975 if self.__state != _CS_REQ_STARTED:
901 raise CannotSendHeader() 976 raise CannotSendHeader()
902 977
903 str = '%s: %s' % (header, value) 978 hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values]))
904 self._output(str) 979 self._output(hdr)
905 980
906 def endheaders(self): 981 def endheaders(self, message_body=None):
907 """Indicate that the last header line has been sent to the server.""" 982 """Indicate that the last header line has been sent to the server.
908 983
984 This method sends the request to the server. The optional
985 message_body argument can be used to pass a message body
986 associated with the request. The message body will be sent in
987 the same packet as the message headers if it is string, otherwise it is
988 sent as a separate packet.
989 """
909 if self.__state == _CS_REQ_STARTED: 990 if self.__state == _CS_REQ_STARTED:
910 self.__state = _CS_REQ_SENT 991 self.__state = _CS_REQ_SENT
911 else: 992 else:
912 raise CannotSendHeader() 993 raise CannotSendHeader()
913 994 self._send_output(message_body)
914 self._send_output()
915 995
916 def request(self, method, url, body=None, headers={}): 996 def request(self, method, url, body=None, headers={}):
917 """Send a complete request to the server.""" 997 """Send a complete request to the server."""
918 998 self._send_request(method, url, body, headers)
999
1000 def _set_content_length(self, body):
1001 # Set the content-length based on the body.
1002 thelen = None
919 try: 1003 try:
920 self._send_request(method, url, body, headers) 1004 thelen = str(len(body))
921 except socket.error, v: 1005 except TypeError, te:
922 # trap 'Broken pipe' if we're allowed to automatically reconnect 1006 # If this is a file-like object, try to
923 if v.args[0] != 32 or not self.auto_open: 1007 # fstat its file descriptor
924 raise 1008 try:
925 # try one more time 1009 thelen = str(os.fstat(body.fileno()).st_size)
926 self._send_request(method, url, body, headers) 1010 except (AttributeError, OSError):
1011 # Don't send a length if this failed
1012 if self.debuglevel > 0: print "Cannot stat!!"
1013
1014 if thelen is not None:
1015 self.putheader('Content-Length', thelen)
927 1016
928 def _send_request(self, method, url, body, headers): 1017 def _send_request(self, method, url, body, headers):
929 # honour explicitly requested Host: and Accept-Encoding headers 1018 # Honor explicitly requested Host: and Accept-Encoding: headers.
930 header_names = dict.fromkeys([k.lower() for k in headers]) 1019 header_names = dict.fromkeys([k.lower() for k in headers])
931 skips = {} 1020 skips = {}
932 if 'host' in header_names: 1021 if 'host' in header_names:
933 skips['skip_host'] = 1 1022 skips['skip_host'] = 1
934 if 'accept-encoding' in header_names: 1023 if 'accept-encoding' in header_names:
935 skips['skip_accept_encoding'] = 1 1024 skips['skip_accept_encoding'] = 1
936 1025
937 self.putrequest(method, url, **skips) 1026 self.putrequest(method, url, **skips)
938 1027
939 if body and ('content-length' not in header_names): 1028 if body is not None and 'content-length' not in header_names:
940 thelen=None 1029 self._set_content_length(body)
941 try:
942 thelen=str(len(body))
943 except TypeError, te:
944 # If this is a file-like object, try to
945 # fstat its file descriptor
946 import os
947 try:
948 thelen = str(os.fstat(body.fileno()).st_size)
949 except (AttributeError, OSError):
950 # Don't send a length if this failed
951 if self.debuglevel > 0: print "Cannot stat!!"
952
953 if thelen is not None:
954 self.putheader('Content-Length',thelen)
955 for hdr, value in headers.iteritems(): 1030 for hdr, value in headers.iteritems():
956 self.putheader(hdr, value) 1031 self.putheader(hdr, value)
957 self.endheaders() 1032 self.endheaders(body)
958 1033
959 if body: 1034 def getresponse(self, buffering=False):
960 self.send(body)
961
962 def getresponse(self):
963 "Get the response from the server." 1035 "Get the response from the server."
964 1036
965 # if a prior response has been completed, then forget about it. 1037 # if a prior response has been completed, then forget about it.
966 if self.__response and self.__response.isclosed(): 1038 if self.__response and self.__response.isclosed():
967 self.__response = None 1039 self.__response = None
968 1040
969 # 1041 #
970 # if a prior response exists, then it must be completed (otherwise, we 1042 # if a prior response exists, then it must be completed (otherwise, we
971 # cannot read this response's header to determine the connection-close 1043 # cannot read this response's header to determine the connection-close
972 # behavior) 1044 # behavior)
973 # 1045 #
974 # note: if a prior response existed, but was connection-close, then the 1046 # note: if a prior response existed, but was connection-close, then the
975 # socket and response were made independent of this HTTPConnection 1047 # socket and response were made independent of this HTTPConnection
976 # object since a new request requires that we open a whole new 1048 # object since a new request requires that we open a whole new
977 # connection 1049 # connection
978 # 1050 #
979 # this means the prior response had one of two states: 1051 # this means the prior response had one of two states:
980 # 1) will_close: this connection was reset and the prior socket and 1052 # 1) will_close: this connection was reset and the prior socket and
981 # response operate independently 1053 # response operate independently
982 # 2) persistent: the response was retained and we await its 1054 # 2) persistent: the response was retained and we await its
983 # isclosed() status to become true. 1055 # isclosed() status to become true.
984 # 1056 #
985 if self.__state != _CS_REQ_SENT or self.__response: 1057 if self.__state != _CS_REQ_SENT or self.__response:
986 raise ResponseNotReady() 1058 raise ResponseNotReady()
987 1059
1060 args = (self.sock,)
1061 kwds = {"strict":self.strict, "method":self._method}
988 if self.debuglevel > 0: 1062 if self.debuglevel > 0:
989 response = self.response_class(self.sock, self.debuglevel, 1063 args += (self.debuglevel,)
990 strict=self.strict, 1064 if buffering:
991 method=self._method) 1065 #only add this keyword if non-default, for compatibility with
992 else: 1066 #other response_classes.
993 response = self.response_class(self.sock, strict=self.strict, 1067 kwds["buffering"] = True;
994 method=self._method) 1068 response = self.response_class(*args, **kwds)
995 1069
996 response.begin() 1070 response.begin()
997 assert response.will_close != _UNKNOWN 1071 assert response.will_close != _UNKNOWN
998 self.__state = _CS_IDLE 1072 self.__state = _CS_IDLE
999 1073
1000 if response.will_close: 1074 if response.will_close:
1001 # this effectively passes the connection to the response 1075 # this effectively passes the connection to the response
1002 self.close() 1076 self.close()
1003 else: 1077 else:
1004 # remember this, so we can tell when it is complete 1078 # remember this, so we can tell when it is complete
(...skipping 12 matching lines...) Expand all
1017 1091
1018 _connection_class = HTTPConnection 1092 _connection_class = HTTPConnection
1019 1093
1020 def __init__(self, host='', port=None, strict=None): 1094 def __init__(self, host='', port=None, strict=None):
1021 "Provide a default host, since the superclass requires one." 1095 "Provide a default host, since the superclass requires one."
1022 1096
1023 # some joker passed 0 explicitly, meaning default port 1097 # some joker passed 0 explicitly, meaning default port
1024 if port == 0: 1098 if port == 0:
1025 port = None 1099 port = None
1026 1100
1027 # Note that we may pass an empty string as the host; this will throw 1101 # Note that we may pass an empty string as the host; this will raise
1028 # an error when we attempt to connect. Presumably, the client code 1102 # an error when we attempt to connect. Presumably, the client code
1029 # will call connect before then, with a proper host. 1103 # will call connect before then, with a proper host.
1030 self._setup(self._connection_class(host, port, strict)) 1104 self._setup(self._connection_class(host, port, strict))
1031 1105
1032 def _setup(self, conn): 1106 def _setup(self, conn):
1033 self._conn = conn 1107 self._conn = conn
1034 1108
1035 # set up delegation to flesh out interface 1109 # set up delegation to flesh out interface
1036 self.send = conn.send 1110 self.send = conn.send
1037 self.putrequest = conn.putrequest 1111 self.putrequest = conn.putrequest
1112 self.putheader = conn.putheader
1038 self.endheaders = conn.endheaders 1113 self.endheaders = conn.endheaders
1039 self.set_debuglevel = conn.set_debuglevel 1114 self.set_debuglevel = conn.set_debuglevel
1040 1115
1041 conn._http_vsn = self._http_vsn 1116 conn._http_vsn = self._http_vsn
1042 conn._http_vsn_str = self._http_vsn_str 1117 conn._http_vsn_str = self._http_vsn_str
1043 1118
1044 self.file = None 1119 self.file = None
1045 1120
1046 def connect(self, host=None, port=None): 1121 def connect(self, host=None, port=None):
1047 "Accept arguments to set the host/port, since the superclass doesn't." 1122 "Accept arguments to set the host/port, since the superclass doesn't."
1048 1123
1049 if host is not None: 1124 if host is not None:
1050 self._conn._set_hostport(host, port) 1125 self._conn._set_hostport(host, port)
1051 self._conn.connect() 1126 self._conn.connect()
1052 1127
1053 def getfile(self): 1128 def getfile(self):
1054 "Provide a getfile, since the superclass' does not use this concept." 1129 "Provide a getfile, since the superclass' does not use this concept."
1055 return self.file 1130 return self.file
1056 1131
1057 def putheader(self, header, *values): 1132 def getreply(self, buffering=False):
1058 "The superclass allows only one value argument."
1059 self._conn.putheader(header, '\r\n\t'.join(values))
1060
1061 def getreply(self):
1062 """Compat definition since superclass does not define it. 1133 """Compat definition since superclass does not define it.
1063 1134
1064 Returns a tuple consisting of: 1135 Returns a tuple consisting of:
1065 - server status code (e.g. '200' if all goes well) 1136 - server status code (e.g. '200' if all goes well)
1066 - server "reason" corresponding to status code 1137 - server "reason" corresponding to status code
1067 - any RFC822 headers in the response from the server 1138 - any RFC822 headers in the response from the server
1068 """ 1139 """
1069 try: 1140 try:
1070 response = self._conn.getresponse() 1141 if not buffering:
1142 response = self._conn.getresponse()
1143 else:
1144 #only add this keyword if non-default for compatibility
1145 #with other connection classes
1146 response = self._conn.getresponse(buffering)
1071 except BadStatusLine, e: 1147 except BadStatusLine, e:
1072 ### hmm. if getresponse() ever closes the socket on a bad request, 1148 ### hmm. if getresponse() ever closes the socket on a bad request,
1073 ### then we are going to have problems with self.sock 1149 ### then we are going to have problems with self.sock
1074 1150
1075 ### should we keep this behavior? do people use it? 1151 ### should we keep this behavior? do people use it?
1076 # keep the socket open (as a file), and return it 1152 # keep the socket open (as a file), and return it
1077 self.file = self._conn.sock.makefile('rb', 0) 1153 self.file = self._conn.sock.makefile('rb', 0)
1078 1154
1079 # close our socket -- we want to restart after any protocol error 1155 # close our socket -- we want to restart after any protocol error
1080 self.close() 1156 self.close()
(...skipping 19 matching lines...) Expand all
1100 import ssl 1176 import ssl
1101 except ImportError: 1177 except ImportError:
1102 pass 1178 pass
1103 else: 1179 else:
1104 class HTTPSConnection(HTTPConnection): 1180 class HTTPSConnection(HTTPConnection):
1105 "This class allows communication via SSL." 1181 "This class allows communication via SSL."
1106 1182
1107 default_port = HTTPS_PORT 1183 default_port = HTTPS_PORT
1108 1184
1109 def __init__(self, host, port=None, key_file=None, cert_file=None, 1185 def __init__(self, host, port=None, key_file=None, cert_file=None,
1110 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): 1186 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
1111 HTTPConnection.__init__(self, host, port, strict, timeout) 1187 source_address=None):
1188 HTTPConnection.__init__(self, host, port, strict, timeout,
1189 source_address)
1112 self.key_file = key_file 1190 self.key_file = key_file
1113 self.cert_file = cert_file 1191 self.cert_file = cert_file
1114 1192
1115 def connect(self): 1193 def connect(self):
1116 "Connect to a host on a given (SSL) port." 1194 "Connect to a host on a given (SSL) port."
1117 1195
1118 sock = socket.create_connection((self.host, self.port), self.timeout ) 1196 sock = self._create_connection((self.host, self.port),
1197 self.timeout, self.source_address)
1119 if self._tunnel_host: 1198 if self._tunnel_host:
1120 self.sock = sock 1199 self.sock = sock
1121 self._tunnel() 1200 self._tunnel()
1122 self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) 1201 self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
1123 1202
1124 __all__.append("HTTPSConnection") 1203 __all__.append("HTTPSConnection")
1125 1204
1126 class HTTPS(HTTP): 1205 class HTTPS(HTTP):
1127 """Compatibility with 1.5 httplib interface 1206 """Compatibility with 1.5 httplib interface
1128 1207
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1199 pass 1278 pass
1200 1279
1201 class CannotSendHeader(ImproperConnectionState): 1280 class CannotSendHeader(ImproperConnectionState):
1202 pass 1281 pass
1203 1282
1204 class ResponseNotReady(ImproperConnectionState): 1283 class ResponseNotReady(ImproperConnectionState):
1205 pass 1284 pass
1206 1285
1207 class BadStatusLine(HTTPException): 1286 class BadStatusLine(HTTPException):
1208 def __init__(self, line): 1287 def __init__(self, line):
1288 if not line:
1289 line = repr(line)
1209 self.args = line, 1290 self.args = line,
1210 self.line = line 1291 self.line = line
1211 1292
1212 1293 class LineTooLong(HTTPException):
1213 class TooManyHeaders(HTTPException): 1294 def __init__(self, line_type):
barry 2013/09/29 19:26:27 We can't introduce a new exception in 2.6.9. Why
1214 def __init__(self): 1295 HTTPException.__init__(self, "got more than %d bytes when reading %s"
1215 HTTPException.__init__(self, "got more than %d headers" % _MAXHEADERS) 1296 % (_MAXLINE, line_type))
1216 1297
1217 # for backwards compatibility 1298 # for backwards compatibility
1218 error = HTTPException 1299 error = HTTPException
1219 1300
1220 class LineAndFileWrapper: 1301 class LineAndFileWrapper:
1221 """A limited file-like object for HTTP/0.9 responses.""" 1302 """A limited file-like object for HTTP/0.9 responses."""
1222 1303
1223 # The status-line parsing code calls readline(), which normally 1304 # The status-line parsing code calls readline(), which normally
1224 # get the HTTP status line. For a 0.9 response, however, this is 1305 # get the HTTP status line. For a 0.9 response, however, this is
1225 # actually the first line of the body! Clients need to get a 1306 # actually the first line of the body! Clients need to get a
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 def readlines(self, size=None): 1358 def readlines(self, size=None):
1278 if self._line_consumed: 1359 if self._line_consumed:
1279 return self._file.readlines(size) 1360 return self._file.readlines(size)
1280 assert self._line_left 1361 assert self._line_left
1281 L = [self._line[self._line_offset:]] 1362 L = [self._line[self._line_offset:]]
1282 self._done() 1363 self._done()
1283 if size is None: 1364 if size is None:
1284 return L + self._file.readlines() 1365 return L + self._file.readlines()
1285 else: 1366 else:
1286 return L + self._file.readlines(size) 1367 return L + self._file.readlines(size)
1287
1288 def test():
1289 """Test this module.
1290
1291 A hodge podge of tests collected here, because they have too many
1292 external dependencies for the regular test suite.
1293 """
1294
1295 import sys
1296 import getopt
1297 opts, args = getopt.getopt(sys.argv[1:], 'd')
1298 dl = 0
1299 for o, a in opts:
1300 if o == '-d': dl = dl + 1
1301 host = 'www.python.org'
1302 selector = '/'
1303 if args[0:]: host = args[0]
1304 if args[1:]: selector = args[1]
1305 h = HTTP()
1306 h.set_debuglevel(dl)
1307 h.connect(host)
1308 h.putrequest('GET', selector)
1309 h.endheaders()
1310 status, reason, headers = h.getreply()
1311 print 'status =', status
1312 print 'reason =', reason
1313 print "read", len(h.getfile().read())
1314 print
1315 if headers:
1316 for header in headers.headers: print header.strip()
1317 print
1318
1319 # minimal test that code to extract host from url works
1320 class HTTP11(HTTP):
1321 _http_vsn = 11
1322 _http_vsn_str = 'HTTP/1.1'
1323
1324 h = HTTP11('www.python.org')
1325 h.putrequest('GET', 'http://www.python.org/~jeremy/')
1326 h.endheaders()
1327 h.getreply()
1328 h.close()
1329
1330 try:
1331 import ssl
1332 except ImportError:
1333 pass
1334 else:
1335
1336 for host, selector in (('sourceforge.net', '/projects/python'),
1337 ):
1338 print "https://%s%s" % (host, selector)
1339 hs = HTTPS()
1340 hs.set_debuglevel(dl)
1341 hs.connect(host)
1342 hs.putrequest('GET', selector)
1343 hs.endheaders()
1344 status, reason, headers = hs.getreply()
1345 print 'status =', status
1346 print 'reason =', reason
1347 print "read", len(hs.getfile().read())
1348 print
1349 if headers:
1350 for header in headers.headers: print header.strip()
1351 print
1352
1353 if __name__ == '__main__':
1354 test()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+