home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 May / maximum-cd-2010-05.iso / DiscContents / boxee-0.9.20.10711.exe / system / python / Lib / urllib.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-07-20  |  43.8 KB  |  1,669 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''Open an arbitrary URL.
  5.  
  6. See the following document for more info on URLs:
  7. "Names and Addresses, URIs, URLs, URNs, URCs", at
  8. http://www.w3.org/pub/WWW/Addressing/Overview.html
  9.  
  10. See also the HTTP spec (from which the error codes are derived):
  11. "HTTP - Hypertext Transfer Protocol", at
  12. http://www.w3.org/pub/WWW/Protocols/
  13.  
  14. Related standards and specs:
  15. - RFC1808: the "relative URL" spec. (authoritative status)
  16. - RFC1738 - the "URL standard". (authoritative status)
  17. - RFC1630 - the "URI spec". (informational status)
  18.  
  19. The object returned by URLopener().open(file) will differ per
  20. protocol.  All you know is that is has methods read(), readline(),
  21. readlines(), fileno(), close() and info().  The read*(), fileno()
  22. and close() methods work like those of open files.
  23. The info() method returns a mimetools.Message object which can be
  24. used to query various info about the object, if available.
  25. (mimetools.Message objects are queried with the getheader() method.)
  26. '''
  27. import string
  28. import socket
  29. import os
  30. import time
  31. import sys
  32. from urlparse import urljoin as basejoin
  33. __all__ = [
  34.     'urlopen',
  35.     'URLopener',
  36.     'FancyURLopener',
  37.     'urlretrieve',
  38.     'urlcleanup',
  39.     'quote',
  40.     'quote_plus',
  41.     'unquote',
  42.     'unquote_plus',
  43.     'urlencode',
  44.     'url2pathname',
  45.     'pathname2url',
  46.     'splittag',
  47.     'localhost',
  48.     'thishost',
  49.     'ftperrors',
  50.     'basejoin',
  51.     'unwrap',
  52.     'splittype',
  53.     'splithost',
  54.     'splituser',
  55.     'splitpasswd',
  56.     'splitport',
  57.     'splitnport',
  58.     'splitquery',
  59.     'splitattr',
  60.     'splitvalue',
  61.     'splitgophertype',
  62.     'getproxies']
  63. __version__ = '1.16'
  64. MAXFTPCACHE = 10
  65. if os.name == 'mac':
  66.     from macurl2path import url2pathname, pathname2url
  67. elif os.name == 'nt':
  68.     from nturl2path import url2pathname, pathname2url
  69. elif os.name == 'riscos':
  70.     from rourl2path import url2pathname, pathname2url
  71. else:
  72.     
  73.     def url2pathname(pathname):
  74.         """OS-specific conversion from a relative URL of the 'file' scheme
  75.         to a file system path; not recommended for general use."""
  76.         return unquote(pathname)
  77.  
  78.     
  79.     def pathname2url(pathname):
  80.         """OS-specific conversion from a file system path to a relative URL
  81.         of the 'file' scheme; not recommended for general use."""
  82.         return quote(pathname)
  83.  
  84. _urlopener = None
  85.  
  86. def urlopen(url, data = None, proxies = None):
  87.     '''urlopen(url [, data]) -> open file-like object'''
  88.     global _urlopener
  89.     if proxies is not None:
  90.         opener = FancyURLopener(proxies = proxies)
  91.     elif not _urlopener:
  92.         opener = FancyURLopener()
  93.         _urlopener = opener
  94.     else:
  95.         opener = _urlopener
  96.     if data is None:
  97.         return opener.open(url)
  98.     else:
  99.         return opener.open(url, data)
  100.  
  101.  
  102. def urlretrieve(url, filename = None, reporthook = None, data = None):
  103.     global _urlopener
  104.     if not _urlopener:
  105.         _urlopener = FancyURLopener()
  106.     
  107.     return _urlopener.retrieve(url, filename, reporthook, data)
  108.  
  109.  
  110. def urlcleanup():
  111.     if _urlopener:
  112.         _urlopener.cleanup()
  113.     
  114.  
  115.  
  116. class ContentTooShortError(IOError):
  117.     
  118.     def __init__(self, message, content):
  119.         IOError.__init__(self, message)
  120.         self.content = content
  121.  
  122.  
  123. ftpcache = { }
  124.  
  125. class URLopener:
  126.     """Class to open URLs.
  127.     This is a class rather than just a subroutine because we may need
  128.     more than one set of global protocol-specific options.
  129.     Note -- this is a base class for those who don't want the
  130.     automatic handling of errors type 302 (relocated) and 401
  131.     (authorization needed)."""
  132.     __tempfiles = None
  133.     version = 'Python-urllib/%s' % __version__
  134.     
  135.     def __init__(self, proxies = None, **x509):
  136.         if proxies is None:
  137.             proxies = getproxies()
  138.         
  139.         self.proxies = proxies
  140.         self.key_file = x509.get('key_file')
  141.         self.cert_file = x509.get('cert_file')
  142.         self.addheaders = [
  143.             ('User-agent', self.version)]
  144.         self._URLopener__tempfiles = []
  145.         self._URLopener__unlink = os.unlink
  146.         self.tempcache = None
  147.         self.ftpcache = ftpcache
  148.  
  149.     
  150.     def __del__(self):
  151.         self.close()
  152.  
  153.     
  154.     def close(self):
  155.         self.cleanup()
  156.  
  157.     
  158.     def cleanup(self):
  159.         if self._URLopener__tempfiles:
  160.             for file in self._URLopener__tempfiles:
  161.                 
  162.                 try:
  163.                     self._URLopener__unlink(file)
  164.                 continue
  165.                 except OSError:
  166.                     continue
  167.                 
  168.  
  169.             
  170.             del self._URLopener__tempfiles[:]
  171.         
  172.         if self.tempcache:
  173.             self.tempcache.clear()
  174.         
  175.  
  176.     
  177.     def addheader(self, *args):
  178.         """Add a header to be used by the HTTP interface only
  179.         e.g. u.addheader('Accept', 'sound/basic')"""
  180.         self.addheaders.append(args)
  181.  
  182.     
  183.     def open(self, fullurl, data = None):
  184.         """Use URLopener().open(file) instead of open(file, 'r')."""
  185.         fullurl = unwrap(toBytes(fullurl))
  186.         if self.tempcache and fullurl in self.tempcache:
  187.             (filename, headers) = self.tempcache[fullurl]
  188.             fp = open(filename, 'rb')
  189.             return addinfourl(fp, headers, fullurl)
  190.         
  191.         (urltype, url) = splittype(fullurl)
  192.         if not urltype:
  193.             urltype = 'file'
  194.         
  195.         if urltype in self.proxies:
  196.             proxy = self.proxies[urltype]
  197.             (urltype, proxyhost) = splittype(proxy)
  198.             (host, selector) = splithost(proxyhost)
  199.             url = (host, fullurl)
  200.         else:
  201.             proxy = None
  202.         name = 'open_' + urltype
  203.         self.type = urltype
  204.         name = name.replace('-', '_')
  205.         if not hasattr(self, name):
  206.             if proxy:
  207.                 return self.open_unknown_proxy(proxy, fullurl, data)
  208.             else:
  209.                 return self.open_unknown(fullurl, data)
  210.         
  211.         
  212.         try:
  213.             if data is None:
  214.                 return getattr(self, name)(url)
  215.             else:
  216.                 return getattr(self, name)(url, data)
  217.         except socket.error:
  218.             msg = None
  219.             raise IOError, ('socket error', msg), sys.exc_info()[2]
  220.  
  221.  
  222.     
  223.     def open_unknown(self, fullurl, data = None):
  224.         '''Overridable interface to open unknown URL type.'''
  225.         (type, url) = splittype(fullurl)
  226.         raise IOError, ('url error', 'unknown url type', type)
  227.  
  228.     
  229.     def open_unknown_proxy(self, proxy, fullurl, data = None):
  230.         '''Overridable interface to open unknown URL type.'''
  231.         (type, url) = splittype(fullurl)
  232.         raise IOError, ('url error', 'invalid proxy for %s' % type, proxy)
  233.  
  234.     
  235.     def retrieve(self, url, filename = None, reporthook = None, data = None):
  236.         '''retrieve(url) returns (filename, headers) for a local object
  237.         or (tempfilename, headers) for a remote object.'''
  238.         url = unwrap(toBytes(url))
  239.         if self.tempcache and url in self.tempcache:
  240.             return self.tempcache[url]
  241.         
  242.         (type, url1) = splittype(url)
  243.         if filename is None:
  244.             if not type or type == 'file':
  245.                 
  246.                 try:
  247.                     fp = self.open_local_file(url1)
  248.                     hdrs = fp.info()
  249.                     del fp
  250.                     return (url2pathname(splithost(url1)[1]), hdrs)
  251.                 except IOError:
  252.                     msg = None
  253.                 except:
  254.                     None<EXCEPTION MATCH>IOError
  255.                 
  256.  
  257.         None<EXCEPTION MATCH>IOError
  258.         fp = self.open(url, data)
  259.         headers = fp.info()
  260.         if filename:
  261.             tfp = open(filename, 'wb')
  262.         else:
  263.             import tempfile
  264.             (garbage, path) = splittype(url)
  265.             if not path:
  266.                 pass
  267.             (garbage, path) = splithost('')
  268.             if not path:
  269.                 pass
  270.             (path, garbage) = splitquery('')
  271.             if not path:
  272.                 pass
  273.             (path, garbage) = splitattr('')
  274.             suffix = os.path.splitext(path)[1]
  275.             (fd, filename) = tempfile.mkstemp(suffix)
  276.             self._URLopener__tempfiles.append(filename)
  277.             tfp = os.fdopen(fd, 'wb')
  278.         result = (filename, headers)
  279.         if self.tempcache is not None:
  280.             self.tempcache[url] = result
  281.         
  282.         bs = 1024 * 8
  283.         size = -1
  284.         read = 0
  285.         blocknum = 0
  286.         if reporthook:
  287.             if 'content-length' in headers:
  288.                 size = int(headers['Content-Length'])
  289.             
  290.             reporthook(blocknum, bs, size)
  291.         
  292.         while None:
  293.             block = fp.read(bs)
  294.             if block == '':
  295.                 break
  296.             
  297.             read += len(block)
  298.             blocknum += 1
  299.             if reporthook:
  300.                 reporthook(blocknum, bs, size)
  301.                 continue
  302.         fp.close()
  303.         tfp.close()
  304.         del fp
  305.         del tfp
  306.         if size >= 0 and read < size:
  307.             raise ContentTooShortError('retrieval incomplete: got only %i out of %i bytes' % (read, size), result)
  308.         
  309.         return result
  310.  
  311.     
  312.     def open_http(self, url, data = None):
  313.         '''Use HTTP protocol.'''
  314.         import httplib
  315.         user_passwd = None
  316.         if isinstance(url, str):
  317.             (host, selector) = splithost(url)
  318.             if host:
  319.                 (user_passwd, host) = splituser(host)
  320.                 host = unquote(host)
  321.             
  322.             realhost = host
  323.         else:
  324.             (host, selector) = url
  325.             (urltype, rest) = splittype(selector)
  326.             url = rest
  327.             user_passwd = None
  328.             if urltype.lower() != 'http':
  329.                 realhost = None
  330.             else:
  331.                 (realhost, rest) = splithost(rest)
  332.                 if realhost:
  333.                     (user_passwd, realhost) = splituser(realhost)
  334.                 
  335.                 if user_passwd:
  336.                     selector = '%s://%s%s' % (urltype, realhost, rest)
  337.                 
  338.                 if proxy_bypass(realhost):
  339.                     host = realhost
  340.                 
  341.         if not host:
  342.             raise IOError, ('http error', 'no host given')
  343.         
  344.         if user_passwd:
  345.             import base64
  346.             auth = base64.encodestring(user_passwd).strip()
  347.         else:
  348.             auth = None
  349.         h = httplib.HTTP(host)
  350.         if data is not None:
  351.             h.putrequest('POST', selector)
  352.             h.putheader('Content-type', 'application/x-www-form-urlencoded')
  353.             h.putheader('Content-length', '%d' % len(data))
  354.         else:
  355.             h.putrequest('GET', selector)
  356.         if auth:
  357.             h.putheader('Authorization', 'Basic %s' % auth)
  358.         
  359.         if realhost:
  360.             h.putheader('Host', realhost)
  361.         
  362.         for args in self.addheaders:
  363.             h.putheader(*args)
  364.         
  365.         h.endheaders()
  366.         if data is not None:
  367.             h.send(data)
  368.         
  369.         (errcode, errmsg, headers) = h.getreply()
  370.         fp = h.getfile()
  371.         if errcode == 200:
  372.             return addinfourl(fp, headers, 'http:' + url)
  373.         elif data is None:
  374.             return self.http_error(url, fp, errcode, errmsg, headers)
  375.         else:
  376.             return self.http_error(url, fp, errcode, errmsg, headers, data)
  377.  
  378.     
  379.     def http_error(self, url, fp, errcode, errmsg, headers, data = None):
  380.         '''Handle http errors.
  381.         Derived class can override this, or provide specific handlers
  382.         named http_error_DDD where DDD is the 3-digit error code.'''
  383.         name = 'http_error_%d' % errcode
  384.         if hasattr(self, name):
  385.             method = getattr(self, name)
  386.             if data is None:
  387.                 result = method(url, fp, errcode, errmsg, headers)
  388.             else:
  389.                 result = method(url, fp, errcode, errmsg, headers, data)
  390.             if result:
  391.                 return result
  392.             
  393.         
  394.         return self.http_error_default(url, fp, errcode, errmsg, headers)
  395.  
  396.     
  397.     def http_error_default(self, url, fp, errcode, errmsg, headers):
  398.         '''Default error handler: close the connection and raise IOError.'''
  399.         void = fp.read()
  400.         fp.close()
  401.         raise IOError, ('http error', errcode, errmsg, headers)
  402.  
  403.     if hasattr(socket, 'ssl'):
  404.         
  405.         def open_https(self, url, data = None):
  406.             '''Use HTTPS protocol.'''
  407.             import httplib
  408.             user_passwd = None
  409.             if isinstance(url, str):
  410.                 (host, selector) = splithost(url)
  411.                 if host:
  412.                     (user_passwd, host) = splituser(host)
  413.                     host = unquote(host)
  414.                 
  415.                 realhost = host
  416.             else:
  417.                 (host, selector) = url
  418.                 (urltype, rest) = splittype(selector)
  419.                 url = rest
  420.                 user_passwd = None
  421.                 if urltype.lower() != 'https':
  422.                     realhost = None
  423.                 else:
  424.                     (realhost, rest) = splithost(rest)
  425.                     if realhost:
  426.                         (user_passwd, realhost) = splituser(realhost)
  427.                     
  428.                     if user_passwd:
  429.                         selector = '%s://%s%s' % (urltype, realhost, rest)
  430.                     
  431.             if not host:
  432.                 raise IOError, ('https error', 'no host given')
  433.             
  434.             if user_passwd:
  435.                 import base64
  436.                 auth = base64.encodestring(user_passwd).strip()
  437.             else:
  438.                 auth = None
  439.             h = httplib.HTTPS(host, 0, key_file = self.key_file, cert_file = self.cert_file)
  440.             if data is not None:
  441.                 h.putrequest('POST', selector)
  442.                 h.putheader('Content-type', 'application/x-www-form-urlencoded')
  443.                 h.putheader('Content-length', '%d' % len(data))
  444.             else:
  445.                 h.putrequest('GET', selector)
  446.             if auth:
  447.                 h.putheader('Authorization', 'Basic %s' % auth)
  448.             
  449.             if realhost:
  450.                 h.putheader('Host', realhost)
  451.             
  452.             for args in self.addheaders:
  453.                 h.putheader(*args)
  454.             
  455.             h.endheaders()
  456.             if data is not None:
  457.                 h.send(data)
  458.             
  459.             (errcode, errmsg, headers) = h.getreply()
  460.             fp = h.getfile()
  461.             if errcode == 200:
  462.                 return addinfourl(fp, headers, 'https:' + url)
  463.             elif data is None:
  464.                 return self.http_error(url, fp, errcode, errmsg, headers)
  465.             else:
  466.                 return self.http_error(url, fp, errcode, errmsg, headers, data)
  467.  
  468.     
  469.     
  470.     def open_gopher(self, url):
  471.         '''Use Gopher protocol.'''
  472.         import gopherlib
  473.         (host, selector) = splithost(url)
  474.         if not host:
  475.             raise IOError, ('gopher error', 'no host given')
  476.         
  477.         host = unquote(host)
  478.         (type, selector) = splitgophertype(selector)
  479.         (selector, query) = splitquery(selector)
  480.         selector = unquote(selector)
  481.         if query:
  482.             query = unquote(query)
  483.             fp = gopherlib.send_query(selector, query, host)
  484.         else:
  485.             fp = gopherlib.send_selector(selector, host)
  486.         return addinfourl(fp, noheaders(), 'gopher:' + url)
  487.  
  488.     
  489.     def open_file(self, url):
  490.         '''Use local file or FTP depending on form of URL.'''
  491.         if url[:2] == '//' and url[2:3] != '/' and url[2:12].lower() != 'localhost/':
  492.             return self.open_ftp(url)
  493.         else:
  494.             return self.open_local_file(url)
  495.  
  496.     
  497.     def open_local_file(self, url):
  498.         '''Use local file.'''
  499.         import mimetypes
  500.         import mimetools
  501.         import email.Utils as email
  502.         
  503.         try:
  504.             StringIO = StringIO
  505.             import cStringIO
  506.         except ImportError:
  507.             StringIO = StringIO
  508.             import StringIO
  509.  
  510.         (host, file) = splithost(url)
  511.         localname = url2pathname(file)
  512.         
  513.         try:
  514.             stats = os.stat(localname)
  515.         except OSError:
  516.             e = None
  517.             raise IOError(e.errno, e.strerror, e.filename)
  518.  
  519.         size = stats.st_size
  520.         modified = email.Utils.formatdate(stats.st_mtime, usegmt = True)
  521.         mtype = mimetypes.guess_type(url)[0]
  522.         if not mtype:
  523.             pass
  524.         headers = mimetools.Message(StringIO('Content-Type: %s\nContent-Length: %d\nLast-modified: %s\n' % ('text/plain', size, modified)))
  525.         if not host:
  526.             urlfile = file
  527.             if file[:1] == '/':
  528.                 urlfile = 'file://' + file
  529.             
  530.             return addinfourl(open(localname, 'rb'), headers, urlfile)
  531.         
  532.         (host, port) = splitport(host)
  533.         if not port and socket.gethostbyname(host) in (localhost(), thishost()):
  534.             urlfile = file
  535.             if file[:1] == '/':
  536.                 urlfile = 'file://' + file
  537.             
  538.             return addinfourl(open(localname, 'rb'), headers, urlfile)
  539.         
  540.         raise IOError, ('local file error', 'not on local host')
  541.  
  542.     
  543.     def open_ftp(self, url):
  544.         '''Use FTP protocol.'''
  545.         import mimetypes
  546.         import mimetools
  547.         
  548.         try:
  549.             StringIO = StringIO
  550.             import cStringIO
  551.         except ImportError:
  552.             StringIO = StringIO
  553.             import StringIO
  554.  
  555.         (host, path) = splithost(url)
  556.         if not host:
  557.             raise IOError, ('ftp error', 'no host given')
  558.         
  559.         (host, port) = splitport(host)
  560.         (user, host) = splituser(host)
  561.         if user:
  562.             (user, passwd) = splitpasswd(user)
  563.         else:
  564.             passwd = None
  565.         host = unquote(host)
  566.         if not user:
  567.             pass
  568.         user = unquote('')
  569.         if not passwd:
  570.             pass
  571.         passwd = unquote('')
  572.         host = socket.gethostbyname(host)
  573.         if not port:
  574.             import ftplib
  575.             port = ftplib.FTP_PORT
  576.         else:
  577.             port = int(port)
  578.         (path, attrs) = splitattr(path)
  579.         path = unquote(path)
  580.         dirs = path.split('/')
  581.         dirs = dirs[:-1]
  582.         file = dirs[-1]
  583.         if dirs and not dirs[0]:
  584.             dirs = dirs[1:]
  585.         
  586.         if dirs and not dirs[0]:
  587.             dirs[0] = '/'
  588.         
  589.         key = (user, host, port, '/'.join(dirs))
  590.         if len(self.ftpcache) > MAXFTPCACHE:
  591.             for k in self.ftpcache.keys():
  592.                 if k != key:
  593.                     v = self.ftpcache[k]
  594.                     del self.ftpcache[k]
  595.                     v.close()
  596.                     continue
  597.             
  598.         
  599.         
  600.         try:
  601.             if key not in self.ftpcache:
  602.                 self.ftpcache[key] = ftpwrapper(user, passwd, host, port, dirs)
  603.             
  604.             if not file:
  605.                 type = 'D'
  606.             else:
  607.                 type = 'I'
  608.             for attr in attrs:
  609.                 (attr, value) = splitvalue(attr)
  610.                 if attr.lower() == 'type' and value in ('a', 'A', 'i', 'I', 'd', 'D'):
  611.                     type = value.upper()
  612.                     continue
  613.             
  614.             (fp, retrlen) = self.ftpcache[key].retrfile(file, type)
  615.             mtype = mimetypes.guess_type('ftp:' + url)[0]
  616.             headers = ''
  617.             if mtype:
  618.                 headers += 'Content-Type: %s\n' % mtype
  619.             
  620.             if retrlen is not None and retrlen >= 0:
  621.                 headers += 'Content-Length: %d\n' % retrlen
  622.             
  623.             headers = mimetools.Message(StringIO(headers))
  624.             return addinfourl(fp, headers, 'ftp:' + url)
  625.         except ftperrors():
  626.             msg = None
  627.             raise IOError, ('ftp error', msg), sys.exc_info()[2]
  628.  
  629.  
  630.     
  631.     def open_data(self, url, data = None):
  632.         '''Use "data" URL.'''
  633.         import mimetools
  634.         
  635.         try:
  636.             StringIO = StringIO
  637.             import cStringIO
  638.         except ImportError:
  639.             StringIO = StringIO
  640.             import StringIO
  641.  
  642.         
  643.         try:
  644.             (type, data) = url.split(',', 1)
  645.         except ValueError:
  646.             raise IOError, ('data error', 'bad data URL')
  647.  
  648.         if not type:
  649.             type = 'text/plain;charset=US-ASCII'
  650.         
  651.         semi = type.rfind(';')
  652.         if semi >= 0 and '=' not in type[semi:]:
  653.             encoding = type[semi + 1:]
  654.             type = type[:semi]
  655.         else:
  656.             encoding = ''
  657.         msg = []
  658.         msg.append('Date: %s' % time.strftime('%a, %d %b %Y %T GMT', time.gmtime(time.time())))
  659.         msg.append('Content-type: %s' % type)
  660.         if encoding == 'base64':
  661.             import base64
  662.             data = base64.decodestring(data)
  663.         else:
  664.             data = unquote(data)
  665.         msg.append('Content-length: %d' % len(data))
  666.         msg.append('')
  667.         msg.append(data)
  668.         msg = '\n'.join(msg)
  669.         f = StringIO(msg)
  670.         headers = mimetools.Message(f, 0)
  671.         return addinfourl(f, headers, url)
  672.  
  673.  
  674.  
  675. class FancyURLopener(URLopener):
  676.     '''Derived class with handlers for errors we can handle (perhaps).'''
  677.     
  678.     def __init__(self, *args, **kwargs):
  679.         URLopener.__init__(self, *args, **kwargs)
  680.         self.auth_cache = { }
  681.         self.tries = 0
  682.         self.maxtries = 10
  683.  
  684.     
  685.     def http_error_default(self, url, fp, errcode, errmsg, headers):
  686.         """Default error handling -- don't raise an exception."""
  687.         return addinfourl(fp, headers, 'http:' + url)
  688.  
  689.     
  690.     def http_error_302(self, url, fp, errcode, errmsg, headers, data = None):
  691.         '''Error 302 -- relocated (temporarily).'''
  692.         self.tries += 1
  693.         result = self.redirect_internal(url, fp, errcode, errmsg, headers, data)
  694.         self.tries = 0
  695.         return result
  696.  
  697.     
  698.     def redirect_internal(self, url, fp, errcode, errmsg, headers, data):
  699.         if 'location' in headers:
  700.             newurl = headers['location']
  701.         elif 'uri' in headers:
  702.             newurl = headers['uri']
  703.         else:
  704.             return None
  705.         void = fp.read()
  706.         fp.close()
  707.         newurl = basejoin(self.type + ':' + url, newurl)
  708.         return self.open(newurl)
  709.  
  710.     
  711.     def http_error_301(self, url, fp, errcode, errmsg, headers, data = None):
  712.         '''Error 301 -- also relocated (permanently).'''
  713.         return self.http_error_302(url, fp, errcode, errmsg, headers, data)
  714.  
  715.     
  716.     def http_error_303(self, url, fp, errcode, errmsg, headers, data = None):
  717.         '''Error 303 -- also relocated (essentially identical to 302).'''
  718.         return self.http_error_302(url, fp, errcode, errmsg, headers, data)
  719.  
  720.     
  721.     def http_error_307(self, url, fp, errcode, errmsg, headers, data = None):
  722.         '''Error 307 -- relocated, but turn POST into error.'''
  723.         if data is None:
  724.             return self.http_error_302(url, fp, errcode, errmsg, headers, data)
  725.         else:
  726.             return self.http_error_default(url, fp, errcode, errmsg, headers)
  727.  
  728.     
  729.     def http_error_401(self, url, fp, errcode, errmsg, headers, data = None):
  730.         '''Error 401 -- authentication required.
  731.         See this URL for a description of the basic authentication scheme:
  732.         http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt'''
  733.         if 'www-authenticate' not in headers:
  734.             URLopener.http_error_default(self, url, fp, errcode, errmsg, headers)
  735.         
  736.         stuff = headers['www-authenticate']
  737.         import re
  738.         match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
  739.         if not match:
  740.             URLopener.http_error_default(self, url, fp, errcode, errmsg, headers)
  741.         
  742.         (scheme, realm) = match.groups()
  743.         if scheme.lower() != 'basic':
  744.             URLopener.http_error_default(self, url, fp, errcode, errmsg, headers)
  745.         
  746.         name = 'retry_' + self.type + '_basic_auth'
  747.         if data is None:
  748.             return getattr(self, name)(url, realm)
  749.         else:
  750.             return getattr(self, name)(url, realm, data)
  751.  
  752.     
  753.     def retry_http_basic_auth(self, url, realm, data = None):
  754.         (host, selector) = splithost(url)
  755.         i = host.find('@') + 1
  756.         host = host[i:]
  757.         (user, passwd) = self.get_user_passwd(host, realm, i)
  758.         if not user or passwd:
  759.             return None
  760.         
  761.         host = quote(user, safe = '') + ':' + quote(passwd, safe = '') + '@' + host
  762.         newurl = 'http://' + host + selector
  763.         if data is None:
  764.             return self.open(newurl)
  765.         else:
  766.             return self.open(newurl, data)
  767.  
  768.     
  769.     def retry_https_basic_auth(self, url, realm, data = None):
  770.         (host, selector) = splithost(url)
  771.         i = host.find('@') + 1
  772.         host = host[i:]
  773.         (user, passwd) = self.get_user_passwd(host, realm, i)
  774.         if not user or passwd:
  775.             return None
  776.         
  777.         host = quote(user, safe = '') + ':' + quote(passwd, safe = '') + '@' + host
  778.         newurl = '//' + host + selector
  779.         return self.open_https(newurl, data)
  780.  
  781.     
  782.     def get_user_passwd(self, host, realm, clear_cache = 0):
  783.         key = realm + '@' + host.lower()
  784.         if key in self.auth_cache:
  785.             if clear_cache:
  786.                 del self.auth_cache[key]
  787.             else:
  788.                 return self.auth_cache[key]
  789.         
  790.         (user, passwd) = self.prompt_user_passwd(host, realm)
  791.         if user or passwd:
  792.             self.auth_cache[key] = (user, passwd)
  793.         
  794.         return (user, passwd)
  795.  
  796.     
  797.     def prompt_user_passwd(self, host, realm):
  798.         '''Override this in a GUI environment!'''
  799.         import getpass
  800.         
  801.         try:
  802.             user = raw_input('Enter username for %s at %s: ' % (realm, host))
  803.             passwd = getpass.getpass('Enter password for %s in %s at %s: ' % (user, realm, host))
  804.             return (user, passwd)
  805.         except KeyboardInterrupt:
  806.             print 
  807.             return (None, None)
  808.  
  809.  
  810.  
  811. _localhost = None
  812.  
  813. def localhost():
  814.     """Return the IP address of the magic hostname 'localhost'."""
  815.     global _localhost
  816.     if _localhost is None:
  817.         _localhost = socket.gethostbyname('localhost')
  818.     
  819.     return _localhost
  820.  
  821. _thishost = None
  822.  
  823. def thishost():
  824.     '''Return the IP address of the current host.'''
  825.     global _thishost
  826.     if _thishost is None:
  827.         _thishost = socket.gethostbyname(socket.gethostname())
  828.     
  829.     return _thishost
  830.  
  831. _ftperrors = None
  832.  
  833. def ftperrors():
  834.     '''Return the set of errors raised by the FTP class.'''
  835.     global _ftperrors
  836.     if _ftperrors is None:
  837.         import ftplib
  838.         _ftperrors = ftplib.all_errors
  839.     
  840.     return _ftperrors
  841.  
  842. _noheaders = None
  843.  
  844. def noheaders():
  845.     '''Return an empty mimetools.Message object.'''
  846.     global _noheaders
  847.     if _noheaders is None:
  848.         import mimetools
  849.         
  850.         try:
  851.             StringIO = StringIO
  852.             import cStringIO
  853.         except ImportError:
  854.             StringIO = StringIO
  855.             import StringIO
  856.  
  857.         _noheaders = mimetools.Message(StringIO(), 0)
  858.         _noheaders.fp.close()
  859.     
  860.     return _noheaders
  861.  
  862.  
  863. class ftpwrapper:
  864.     '''Class used by open_ftp() for cache of open FTP connections.'''
  865.     
  866.     def __init__(self, user, passwd, host, port, dirs):
  867.         self.user = user
  868.         self.passwd = passwd
  869.         self.host = host
  870.         self.port = port
  871.         self.dirs = dirs
  872.         self.init()
  873.  
  874.     
  875.     def init(self):
  876.         import ftplib
  877.         self.busy = 0
  878.         self.ftp = ftplib.FTP()
  879.         self.ftp.connect(self.host, self.port)
  880.         self.ftp.login(self.user, self.passwd)
  881.         for dir in self.dirs:
  882.             self.ftp.cwd(dir)
  883.         
  884.  
  885.     
  886.     def retrfile(self, file, type):
  887.         import ftplib
  888.         self.endtransfer()
  889.         if type in ('d', 'D'):
  890.             cmd = 'TYPE A'
  891.             isdir = 1
  892.         else:
  893.             cmd = 'TYPE ' + type
  894.             isdir = 0
  895.         
  896.         try:
  897.             self.ftp.voidcmd(cmd)
  898.         except ftplib.all_errors:
  899.             self.init()
  900.             self.ftp.voidcmd(cmd)
  901.  
  902.         conn = None
  903.         if file and not isdir:
  904.             
  905.             try:
  906.                 self.ftp.nlst(file)
  907.             except ftplib.error_perm:
  908.                 reason = None
  909.                 raise IOError, ('ftp error', reason), sys.exc_info()[2]
  910.  
  911.             self.ftp.voidcmd(cmd)
  912.             
  913.             try:
  914.                 cmd = 'RETR ' + file
  915.                 conn = self.ftp.ntransfercmd(cmd)
  916.             except ftplib.error_perm:
  917.                 reason = None
  918.                 if str(reason)[:3] != '550':
  919.                     raise IOError, ('ftp error', reason), sys.exc_info()[2]
  920.                 
  921.             except:
  922.                 str(reason)[:3] != '550'
  923.             
  924.  
  925.         None<EXCEPTION MATCH>ftplib.error_perm
  926.         if not conn:
  927.             self.ftp.voidcmd('TYPE A')
  928.             if file:
  929.                 cmd = 'LIST ' + file
  930.             else:
  931.                 cmd = 'LIST'
  932.             conn = self.ftp.ntransfercmd(cmd)
  933.         
  934.         self.busy = 1
  935.         return (addclosehook(conn[0].makefile('rb'), self.endtransfer), conn[1])
  936.  
  937.     
  938.     def endtransfer(self):
  939.         if not self.busy:
  940.             return None
  941.         
  942.         self.busy = 0
  943.         
  944.         try:
  945.             self.ftp.voidresp()
  946.         except ftperrors():
  947.             pass
  948.  
  949.  
  950.     
  951.     def close(self):
  952.         self.endtransfer()
  953.         
  954.         try:
  955.             self.ftp.close()
  956.         except ftperrors():
  957.             pass
  958.  
  959.  
  960.  
  961.  
  962. class addbase:
  963.     '''Base class for addinfo and addclosehook.'''
  964.     
  965.     def __init__(self, fp):
  966.         self.fp = fp
  967.         self.read = self.fp.read
  968.         self.readline = self.fp.readline
  969.         if hasattr(self.fp, 'readlines'):
  970.             self.readlines = self.fp.readlines
  971.         
  972.         if hasattr(self.fp, 'fileno'):
  973.             self.fileno = self.fp.fileno
  974.         else:
  975.             
  976.             self.fileno = lambda : pass
  977.         if hasattr(self.fp, '__iter__'):
  978.             self.__iter__ = self.fp.__iter__
  979.             if hasattr(self.fp, 'next'):
  980.                 self.next = self.fp.next
  981.             
  982.         
  983.  
  984.     
  985.     def __repr__(self):
  986.         return '<%s at %r whose fp = %r>' % (self.__class__.__name__, id(self), self.fp)
  987.  
  988.     
  989.     def close(self):
  990.         self.read = None
  991.         self.readline = None
  992.         self.readlines = None
  993.         self.fileno = None
  994.         if self.fp:
  995.             self.fp.close()
  996.         
  997.         self.fp = None
  998.  
  999.  
  1000.  
  1001. class addclosehook(addbase):
  1002.     '''Class to add a close hook to an open file.'''
  1003.     
  1004.     def __init__(self, fp, closehook, *hookargs):
  1005.         addbase.__init__(self, fp)
  1006.         self.closehook = closehook
  1007.         self.hookargs = hookargs
  1008.  
  1009.     
  1010.     def close(self):
  1011.         addbase.close(self)
  1012.         if self.closehook:
  1013.             self.closehook(*self.hookargs)
  1014.             self.closehook = None
  1015.             self.hookargs = None
  1016.         
  1017.  
  1018.  
  1019.  
  1020. class addinfo(addbase):
  1021.     '''class to add an info() method to an open file.'''
  1022.     
  1023.     def __init__(self, fp, headers):
  1024.         addbase.__init__(self, fp)
  1025.         self.headers = headers
  1026.  
  1027.     
  1028.     def info(self):
  1029.         return self.headers
  1030.  
  1031.  
  1032.  
  1033. class addinfourl(addbase):
  1034.     '''class to add info() and geturl() methods to an open file.'''
  1035.     
  1036.     def __init__(self, fp, headers, url):
  1037.         addbase.__init__(self, fp)
  1038.         self.headers = headers
  1039.         self.url = url
  1040.  
  1041.     
  1042.     def info(self):
  1043.         return self.headers
  1044.  
  1045.     
  1046.     def geturl(self):
  1047.         return self.url
  1048.  
  1049.  
  1050.  
  1051. try:
  1052.     unicode
  1053. except NameError:
  1054.     
  1055.     def _is_unicode(x):
  1056.         return 0
  1057.  
  1058.  
  1059.  
  1060. def _is_unicode(x):
  1061.     return isinstance(x, unicode)
  1062.  
  1063.  
  1064. def toBytes(url):
  1065.     '''toBytes(u"URL") --> \'URL\'.'''
  1066.     if _is_unicode(url):
  1067.         
  1068.         try:
  1069.             url = url.encode('ASCII')
  1070.         except UnicodeError:
  1071.             raise UnicodeError('URL ' + repr(url) + ' contains non-ASCII characters')
  1072.         except:
  1073.             None<EXCEPTION MATCH>UnicodeError
  1074.         
  1075.  
  1076.     None<EXCEPTION MATCH>UnicodeError
  1077.     return url
  1078.  
  1079.  
  1080. def unwrap(url):
  1081.     """unwrap('<URL:type://host/path>') --> 'type://host/path'."""
  1082.     url = url.strip()
  1083.     if url[:1] == '<' and url[-1:] == '>':
  1084.         url = url[1:-1].strip()
  1085.     
  1086.     if url[:4] == 'URL:':
  1087.         url = url[4:].strip()
  1088.     
  1089.     return url
  1090.  
  1091. _typeprog = None
  1092.  
  1093. def splittype(url):
  1094.     """splittype('type:opaquestring') --> 'type', 'opaquestring'."""
  1095.     global _typeprog
  1096.     if _typeprog is None:
  1097.         import re
  1098.         _typeprog = re.compile('^([^/:]+):')
  1099.     
  1100.     match = _typeprog.match(url)
  1101.     if match:
  1102.         scheme = match.group(1)
  1103.         return (scheme.lower(), url[len(scheme) + 1:])
  1104.     
  1105.     return (None, url)
  1106.  
  1107. _hostprog = None
  1108.  
  1109. def splithost(url):
  1110.     """splithost('//host[:port]/path') --> 'host[:port]', '/path'."""
  1111.     global _hostprog
  1112.     if _hostprog is None:
  1113.         import re
  1114.         _hostprog = re.compile('^//([^/]*)(.*)$')
  1115.     
  1116.     match = _hostprog.match(url)
  1117.     if match:
  1118.         return match.group(1, 2)
  1119.     
  1120.     return (None, url)
  1121.  
  1122. _userprog = None
  1123.  
  1124. def splituser(host):
  1125.     """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
  1126.     global _userprog
  1127.     if _userprog is None:
  1128.         import re
  1129.         _userprog = re.compile('^(.*)@(.*)$')
  1130.     
  1131.     match = _userprog.match(host)
  1132.     if match:
  1133.         return map(unquote, match.group(1, 2))
  1134.     
  1135.     return (None, host)
  1136.  
  1137. _passwdprog = None
  1138.  
  1139. def splitpasswd(user):
  1140.     """splitpasswd('user:passwd') -> 'user', 'passwd'."""
  1141.     global _passwdprog
  1142.     if _passwdprog is None:
  1143.         import re
  1144.         _passwdprog = re.compile('^([^:]*):(.*)$')
  1145.     
  1146.     match = _passwdprog.match(user)
  1147.     if match:
  1148.         return match.group(1, 2)
  1149.     
  1150.     return (user, None)
  1151.  
  1152. _portprog = None
  1153.  
  1154. def splitport(host):
  1155.     """splitport('host:port') --> 'host', 'port'."""
  1156.     global _portprog
  1157.     if _portprog is None:
  1158.         import re
  1159.         _portprog = re.compile('^(.*):([0-9]+)$')
  1160.     
  1161.     match = _portprog.match(host)
  1162.     if match:
  1163.         return match.group(1, 2)
  1164.     
  1165.     return (host, None)
  1166.  
  1167. _nportprog = None
  1168.  
  1169. def splitnport(host, defport = -1):
  1170.     """Split host and port, returning numeric port.
  1171.     Return given default port if no ':' found; defaults to -1.
  1172.     Return numerical port if a valid number are found after ':'.
  1173.     Return None if ':' but not a valid number."""
  1174.     global _nportprog
  1175.     if _nportprog is None:
  1176.         import re
  1177.         _nportprog = re.compile('^(.*):(.*)$')
  1178.     
  1179.     match = _nportprog.match(host)
  1180.     if match:
  1181.         (host, port) = match.group(1, 2)
  1182.         
  1183.         try:
  1184.             if not port:
  1185.                 raise ValueError, 'no digits'
  1186.             
  1187.             nport = int(port)
  1188.         except ValueError:
  1189.             nport = None
  1190.  
  1191.         return (host, nport)
  1192.     
  1193.     return (host, defport)
  1194.  
  1195. _queryprog = None
  1196.  
  1197. def splitquery(url):
  1198.     """splitquery('/path?query') --> '/path', 'query'."""
  1199.     global _queryprog
  1200.     if _queryprog is None:
  1201.         import re
  1202.         _queryprog = re.compile('^(.*)\\?([^?]*)$')
  1203.     
  1204.     match = _queryprog.match(url)
  1205.     if match:
  1206.         return match.group(1, 2)
  1207.     
  1208.     return (url, None)
  1209.  
  1210. _tagprog = None
  1211.  
  1212. def splittag(url):
  1213.     """splittag('/path#tag') --> '/path', 'tag'."""
  1214.     global _tagprog
  1215.     if _tagprog is None:
  1216.         import re
  1217.         _tagprog = re.compile('^(.*)#([^#]*)$')
  1218.     
  1219.     match = _tagprog.match(url)
  1220.     if match:
  1221.         return match.group(1, 2)
  1222.     
  1223.     return (url, None)
  1224.  
  1225.  
  1226. def splitattr(url):
  1227.     """splitattr('/path;attr1=value1;attr2=value2;...') ->
  1228.         '/path', ['attr1=value1', 'attr2=value2', ...]."""
  1229.     words = url.split(';')
  1230.     return (words[0], words[1:])
  1231.  
  1232. _valueprog = None
  1233.  
  1234. def splitvalue(attr):
  1235.     """splitvalue('attr=value') --> 'attr', 'value'."""
  1236.     global _valueprog
  1237.     if _valueprog is None:
  1238.         import re
  1239.         _valueprog = re.compile('^([^=]*)=(.*)$')
  1240.     
  1241.     match = _valueprog.match(attr)
  1242.     if match:
  1243.         return match.group(1, 2)
  1244.     
  1245.     return (attr, None)
  1246.  
  1247.  
  1248. def splitgophertype(selector):
  1249.     """splitgophertype('/Xselector') --> 'X', 'selector'."""
  1250.     if selector[:1] == '/' and selector[1:2]:
  1251.         return (selector[1], selector[2:])
  1252.     
  1253.     return (None, selector)
  1254.  
  1255. _hextochr = dict((lambda [outmost-iterable]: for i in [outmost-iterable]:
  1256. ('%02x' % i, chr(i)))(range(256)))
  1257. _hextochr.update((lambda [outmost-iterable]: for i in [outmost-iterable]:
  1258. ('%02X' % i, chr(i)))(range(256)))
  1259.  
  1260. def unquote(s):
  1261.     """unquote('abc%20def') -> 'abc def'."""
  1262.     res = s.split('%')
  1263.     for i in xrange(1, len(res)):
  1264.         item = res[i]
  1265.         
  1266.         try:
  1267.             res[i] = _hextochr[item[:2]] + item[2:]
  1268.         continue
  1269.         except KeyError:
  1270.             res[i] = '%' + item
  1271.             continue
  1272.             except UnicodeDecodeError:
  1273.                 res[i] = unichr(int(item[:2], 16)) + item[2:]
  1274.                 continue
  1275.             
  1276.         return ''.join(res)
  1277.  
  1278.  
  1279.  
  1280. def unquote_plus(s):
  1281.     """unquote('%7e/abc+def') -> '~/abc def'"""
  1282.     s = s.replace('+', ' ')
  1283.     return unquote(s)
  1284.  
  1285. always_safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.-'
  1286. _safemaps = { }
  1287.  
  1288. def quote(s, safe = '/'):
  1289.     '''quote(\'abc def\') -> \'abc%20def\'
  1290.  
  1291.     Each part of a URL, e.g. the path info, the query, etc., has a
  1292.     different set of reserved characters that must be quoted.
  1293.  
  1294.     RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
  1295.     the following reserved characters.
  1296.  
  1297.     reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
  1298.                   "$" | ","
  1299.  
  1300.     Each of these characters is reserved in some component of a URL,
  1301.     but not necessarily in all of them.
  1302.  
  1303.     By default, the quote function is intended for quoting the path
  1304.     section of a URL.  Thus, it will not encode \'/\'.  This character
  1305.     is reserved, but in typical usage the quote function is being
  1306.     called on a path where the existing slash characters are used as
  1307.     reserved characters.
  1308.     '''
  1309.     cachekey = (safe, always_safe)
  1310.     
  1311.     try:
  1312.         safe_map = _safemaps[cachekey]
  1313.     except KeyError:
  1314.         safe += always_safe
  1315.         safe_map = { }
  1316.         for i in range(256):
  1317.             c = chr(i)
  1318.             if not c in safe or c:
  1319.                 pass
  1320.             safe_map[c] = '%%%02X' % i
  1321.         
  1322.         _safemaps[cachekey] = safe_map
  1323.  
  1324.     res = map(safe_map.__getitem__, s)
  1325.     return ''.join(res)
  1326.  
  1327.  
  1328. def quote_plus(s, safe = ''):
  1329.     """Quote the query fragment of a URL; replacing ' ' with '+'"""
  1330.     if ' ' in s:
  1331.         s = quote(s, safe + ' ')
  1332.         return s.replace(' ', '+')
  1333.     
  1334.     return quote(s, safe)
  1335.  
  1336.  
  1337. def urlencode(query, doseq = 0):
  1338.     '''Encode a sequence of two-element tuples or dictionary into a URL query string.
  1339.  
  1340.     If any values in the query arg are sequences and doseq is true, each
  1341.     sequence element is converted to a separate parameter.
  1342.  
  1343.     If the query arg is a sequence of two-element tuples, the order of the
  1344.     parameters in the output will match the order of parameters in the
  1345.     input.
  1346.     '''
  1347.     if hasattr(query, 'items'):
  1348.         query = query.items()
  1349.     else:
  1350.         
  1351.         try:
  1352.             if len(query) and not isinstance(query[0], tuple):
  1353.                 raise TypeError
  1354.         except TypeError:
  1355.             (ty, va, tb) = sys.exc_info()
  1356.             raise TypeError, 'not a valid non-string sequence or mapping object', tb
  1357.  
  1358.     l = []
  1359.     if not doseq:
  1360.         for k, v in query:
  1361.             k = quote_plus(str(k))
  1362.             v = quote_plus(str(v))
  1363.             l.append(k + '=' + v)
  1364.         
  1365.     else:
  1366.         for k, v in query:
  1367.             k = quote_plus(str(k))
  1368.             if isinstance(v, str):
  1369.                 v = quote_plus(v)
  1370.                 l.append(k + '=' + v)
  1371.                 continue
  1372.             if _is_unicode(v):
  1373.                 v = quote_plus(v.encode('ASCII', 'replace'))
  1374.                 l.append(k + '=' + v)
  1375.                 continue
  1376.             
  1377.             try:
  1378.                 x = len(v)
  1379.             except TypeError:
  1380.                 v = quote_plus(str(v))
  1381.                 l.append(k + '=' + v)
  1382.                 continue
  1383.  
  1384.             for elt in v:
  1385.                 l.append(k + '=' + quote_plus(str(elt)))
  1386.             
  1387.         
  1388.     return '&'.join(l)
  1389.  
  1390.  
  1391. def getproxies_environment():
  1392.     '''Return a dictionary of scheme -> proxy server URL mappings.
  1393.  
  1394.     Scan the environment for variables named <scheme>_proxy;
  1395.     this seems to be the standard convention.  If you need a
  1396.     different way, you can pass a proxies dictionary to the
  1397.     [Fancy]URLopener constructor.
  1398.  
  1399.     '''
  1400.     proxies = { }
  1401.     for name, value in os.environ.items():
  1402.         name = name.lower()
  1403.         if value and name[-6:] == '_proxy':
  1404.             proxies[name[:-6]] = value
  1405.             continue
  1406.     
  1407.     return proxies
  1408.  
  1409. if sys.platform == 'darwin':
  1410.     
  1411.     def getproxies_internetconfig():
  1412.         '''Return a dictionary of scheme -> proxy server URL mappings.
  1413.  
  1414.         By convention the mac uses Internet Config to store
  1415.         proxies.  An HTTP proxy, for instance, is stored under
  1416.         the HttpProxy key.
  1417.  
  1418.         '''
  1419.         
  1420.         try:
  1421.             import ic
  1422.         except ImportError:
  1423.             return { }
  1424.  
  1425.         
  1426.         try:
  1427.             config = ic.IC()
  1428.         except ic.error:
  1429.             return { }
  1430.  
  1431.         proxies = { }
  1432.         if 'UseHTTPProxy' in config and config['UseHTTPProxy']:
  1433.             
  1434.             try:
  1435.                 value = config['HTTPProxyHost']
  1436.             except ic.error:
  1437.                 pass
  1438.  
  1439.             proxies['http'] = 'http://%s' % value
  1440.         
  1441.         return proxies
  1442.  
  1443.     
  1444.     def proxy_bypass(x):
  1445.         return 0
  1446.  
  1447.     
  1448.     def getproxies():
  1449.         if not getproxies_environment():
  1450.             pass
  1451.         return getproxies_internetconfig()
  1452.  
  1453. elif os.name == 'nt':
  1454.     
  1455.     def getproxies_registry():
  1456.         '''Return a dictionary of scheme -> proxy server URL mappings.
  1457.  
  1458.         Win32 uses the registry to store proxies.
  1459.  
  1460.         '''
  1461.         proxies = { }
  1462.         
  1463.         try:
  1464.             import _winreg
  1465.         except ImportError:
  1466.             return proxies
  1467.  
  1468.         
  1469.         try:
  1470.             internetSettings = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
  1471.             proxyEnable = _winreg.QueryValueEx(internetSettings, 'ProxyEnable')[0]
  1472.             if proxyEnable:
  1473.                 proxyServer = str(_winreg.QueryValueEx(internetSettings, 'ProxyServer')[0])
  1474.                 if '=' in proxyServer:
  1475.                     for p in proxyServer.split(';'):
  1476.                         (protocol, address) = p.split('=', 1)
  1477.                         import re
  1478.                         if not re.match('^([^/:]+)://', address):
  1479.                             address = '%s://%s' % (protocol, address)
  1480.                         
  1481.                         proxies[protocol] = address
  1482.                     
  1483.                 elif proxyServer[:5] == 'http:':
  1484.                     proxies['http'] = proxyServer
  1485.                 else:
  1486.                     proxies['http'] = 'http://%s' % proxyServer
  1487.                     proxies['ftp'] = 'ftp://%s' % proxyServer
  1488.             
  1489.             internetSettings.Close()
  1490.         except (WindowsError, ValueError, TypeError):
  1491.             pass
  1492.  
  1493.         return proxies
  1494.  
  1495.     
  1496.     def getproxies():
  1497.         '''Return a dictionary of scheme -> proxy server URL mappings.
  1498.  
  1499.         Returns settings gathered from the environment, if specified,
  1500.         or the registry.
  1501.  
  1502.         '''
  1503.         if not getproxies_environment():
  1504.             pass
  1505.         return getproxies_registry()
  1506.  
  1507.     
  1508.     def proxy_bypass(host):
  1509.         
  1510.         try:
  1511.             import _winreg
  1512.             import re
  1513.         except ImportError:
  1514.             return 0
  1515.  
  1516.         
  1517.         try:
  1518.             internetSettings = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
  1519.             proxyEnable = _winreg.QueryValueEx(internetSettings, 'ProxyEnable')[0]
  1520.             proxyOverride = str(_winreg.QueryValueEx(internetSettings, 'ProxyOverride')[0])
  1521.         except WindowsError:
  1522.             return 0
  1523.  
  1524.         if not proxyEnable or not proxyOverride:
  1525.             return 0
  1526.         
  1527.         host = [
  1528.             host]
  1529.         
  1530.         try:
  1531.             addr = socket.gethostbyname(host[0])
  1532.             if addr != host:
  1533.                 host.append(addr)
  1534.         except socket.error:
  1535.             pass
  1536.  
  1537.         proxyOverride = proxyOverride.split(';')
  1538.         i = 0
  1539.         while i < len(proxyOverride):
  1540.             if proxyOverride[i] == '<local>':
  1541.                 proxyOverride[i:i + 1] = [
  1542.                     'localhost',
  1543.                     '127.0.0.1',
  1544.                     socket.gethostname(),
  1545.                     socket.gethostbyname(socket.gethostname())]
  1546.             
  1547.             i += 1
  1548.         for test in proxyOverride:
  1549.             test = test.replace('.', '\\.')
  1550.             test = test.replace('*', '.*')
  1551.             test = test.replace('?', '.')
  1552.             for val in host:
  1553.                 if re.match(test, val, re.I):
  1554.                     return 1
  1555.                     continue
  1556.             
  1557.         
  1558.         return 0
  1559.  
  1560. else:
  1561.     getproxies = getproxies_environment
  1562.     
  1563.     def proxy_bypass(host):
  1564.         return 0
  1565.  
  1566.  
  1567. def test1():
  1568.     s = ''
  1569.     for i in range(256):
  1570.         s = s + chr(i)
  1571.     
  1572.     s = s * 4
  1573.     t0 = time.time()
  1574.     qs = quote(s)
  1575.     uqs = unquote(qs)
  1576.     t1 = time.time()
  1577.     if uqs != s:
  1578.         print 'Wrong!'
  1579.     
  1580.     print repr(s)
  1581.     print repr(qs)
  1582.     print repr(uqs)
  1583.     print round(t1 - t0, 3), 'sec'
  1584.  
  1585.  
  1586. def reporthook(blocknum, blocksize, totalsize):
  1587.     print 'Block number: %d, Block size: %d, Total size: %d' % (blocknum, blocksize, totalsize)
  1588.  
  1589.  
  1590. def test(args = []):
  1591.     if not args:
  1592.         args = [
  1593.             '/etc/passwd',
  1594.             'file:/etc/passwd',
  1595.             'file://localhost/etc/passwd',
  1596.             'ftp://ftp.python.org/pub/python/README',
  1597.             'http://www.python.org/index.html']
  1598.         if hasattr(URLopener, 'open_https'):
  1599.             args.append('https://synergy.as.cmu.edu/~geek/')
  1600.         
  1601.     
  1602.     
  1603.     try:
  1604.         for url in args:
  1605.             print '-' * 10, url, '-' * 10
  1606.             (fn, h) = urlretrieve(url, None, reporthook)
  1607.             print fn
  1608.             if h:
  1609.                 print '======'
  1610.                 for k in h.keys():
  1611.                     print k + ':', h[k]
  1612.                 
  1613.                 print '======'
  1614.             
  1615.             fp = open(fn, 'rb')
  1616.             data = fp.read()
  1617.             del fp
  1618.             if '\r' in data:
  1619.                 table = string.maketrans('', '')
  1620.                 data = data.translate(table, '\r')
  1621.             
  1622.             print data
  1623.             (fn, h) = (None, None)
  1624.         
  1625.         print '-' * 40
  1626.     finally:
  1627.         urlcleanup()
  1628.  
  1629.  
  1630.  
  1631. def main():
  1632.     import getopt
  1633.     import sys
  1634.     
  1635.     try:
  1636.         (opts, args) = getopt.getopt(sys.argv[1:], 'th')
  1637.     except getopt.error:
  1638.         msg = None
  1639.         print msg
  1640.         print 'Use -h for help'
  1641.         return None
  1642.  
  1643.     t = 0
  1644.     for o, a in opts:
  1645.         if o == '-t':
  1646.             t = t + 1
  1647.         
  1648.         if o == '-h':
  1649.             print 'Usage: python urllib.py [-t] [url ...]'
  1650.             print '-t runs self-test;', 'otherwise, contents of urls are printed'
  1651.             return None
  1652.             continue
  1653.     
  1654.     if t:
  1655.         if t > 1:
  1656.             test1()
  1657.         
  1658.         test(args)
  1659.     elif not args:
  1660.         print 'Use -h for help'
  1661.     
  1662.     for url in args:
  1663.         print urlopen(url).read(),
  1664.     
  1665.  
  1666. if __name__ == '__main__':
  1667.     main()
  1668.  
  1669.