home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Python 1.1 / Lib / urlparse.py < prev    next >
Encoding:
Text File  |  1994-09-12  |  5.6 KB  |  196 lines  |  [TEXT/R*ch]

  1. # Parse (absolute and relative) URLs according to latest internet draft:
  2.  
  3. # Uniform Resource Identifiers Working Group                  R. Fielding
  4. # INTERNET-DRAFT                                                UC Irvine
  5. # Expires February 24, 1995                               August 24, 1994
  6. #
  7. #                   Relative Uniform Resource Locators
  8. #                  <draft-ietf-uri-relative-url-00.txt>
  9.  
  10. # Standard/builtin Python modules
  11. import string
  12.  
  13. # A classification of schemes ('' means apply by default)
  14. uses_relative = ['ftp', 'http', 'gopher', 'nntp', 'wais', 'file',
  15.          'prospero', '']
  16. uses_netloc = ['ftp', 'http', 'gopher', 'nntp', 'telnet', 'wais',
  17.            'file', 'prospero', '']
  18. non_hierarchical = ['gopher', 'mailto', 'news', 'telnet', 'wais']
  19. uses_params = ['ftp', 'prospero', '']
  20. uses_query = ['http', 'wais', '']
  21. uses_fragment = ['ftp', 'http', 'gopher', 'news', 'nntp', 'wais',
  22.          'file', 'prospero', '']
  23.  
  24. # Characters valid in scheme names
  25. scheme_chars = string.letters + string.digits + '+-.'
  26.  
  27. # Parse a URL into 6 components:
  28. # <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
  29. # Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
  30. # Note that we don't break the components up in smaller bits
  31. # (e.g. netloc is a single string) and we don't expand % escapes.
  32. def urlparse(url, scheme = '', allow_framents = 1):
  33.     netloc = ''
  34.     path = ''
  35.     params = ''
  36.     query = ''
  37.     fragment = ''
  38.     i = string.find(url, ':')
  39.     if i > 0:
  40.         for c in url[:i]:
  41.             if c not in scheme_chars:
  42.                 break
  43.         else:
  44.             scheme, url = string.lower(url[:i]), url[i+1:]
  45.     if scheme in uses_netloc:
  46.         if url[:2] == '//':
  47.             i = string.find(url, '/', 2)
  48.             if i < 0:
  49.                 i = len(url)
  50.             netloc, url = url[2:i], url[i:]
  51.     if allow_framents and scheme in uses_fragment:
  52.         i = string.rfind(url, '#')
  53.         if i >= 0:
  54.             url, fragment = url[:i], url[i+1:]
  55.     if scheme in uses_query:
  56.         i = string.find(url, '?')
  57.         if i >= 0:
  58.             url, query = url[:i], url[i+1:]
  59.     if scheme in uses_params:
  60.         i = string.find(url, ';')
  61.         if i >= 0:
  62.             url, params = url[:i], url[i+1:]
  63.     return scheme, netloc, url, params, query, fragment
  64.  
  65. # Put a parsed URL back together again.  This may result in a slightly
  66. # different, but equivalent URL, if the URL that was parsed originally
  67. # had redundant delimiters, e.g. a ? with an empty query (the draft
  68. # states that these are equivalent).
  69. def urlunparse((scheme, netloc, url, params, query, fragment)):
  70.     if netloc:
  71.         url = '//' + netloc + url
  72.     if scheme:
  73.         url = scheme + ':' + url
  74.     if params:
  75.         url = url + ';' + params
  76.     if query:
  77.         url = url + '?' + query
  78.     if fragment:
  79.         url = url + '#' + fragment
  80.     return url
  81.  
  82. # Join a base URL and a possibly relative URL to form an absolute
  83. # interpretation of the latter.
  84. def urljoin(base, url, allow_framents = 1):
  85.     if not base:
  86.         return url
  87.     bscheme, bnetloc, bpath, bparams, bquery, bfragment = \
  88.           urlparse(base, '', allow_framents)
  89.     scheme, netloc, path, params, query, fragment = \
  90.         urlparse(url, bscheme, allow_framents)
  91.     if scheme != bscheme or scheme not in uses_relative:
  92.         return urlunparse((scheme, netloc, path,
  93.                    params, query, fragment))
  94.     if scheme in uses_netloc:
  95.         if netloc:
  96.             return urlunparse((scheme, netloc, path,
  97.                        params, query, fragment))
  98.         netloc = bnetloc
  99.     if path[:1] == '/':
  100.         return urlunparse((scheme, netloc, path,
  101.                    params, query, fragment))
  102.     if not path:
  103.         path = bpath
  104.         if not query:
  105.             query = bquery
  106.         return urlunparse((scheme, netloc, path,
  107.                    params, query, fragment))
  108.     i = string.rfind(bpath, '/')
  109.     if i < 0:
  110.         i = len(bpath)
  111.     path = bpath[:i] + '/' + path
  112.     segments = string.splitfields(path, '/')
  113.     if segments[-1] == '.':
  114.         segments[-1] = ''
  115.     while '.' in segments:
  116.         segments.remove('.')
  117.     while 1:
  118.         i = 1
  119.         n = len(segments) - 1
  120.         while i < n:
  121.             if segments[i] == '..' and segments[i-1]:
  122.                 del segments[i-1:i+1]
  123.                 break
  124.             i = i+1
  125.         else:
  126.             break
  127.     if len(segments) >= 2 and segments[-1] == '..':
  128.         segments[-2:] = ['']
  129.     path = string.joinfields(segments, '/')
  130.     return urlunparse((scheme, netloc, path,
  131.                params, query, fragment))
  132.  
  133. test_input = """
  134.       http://a/b/c/d
  135.  
  136.       g:h        = <URL:g:h>
  137.       http:g     = <URL:http://a/b/c/g>
  138.       http:      = <URL:http://a/b/c/d>
  139.       g          = <URL:http://a/b/c/g>
  140.       ./g        = <URL:http://a/b/c/g>
  141.       g/         = <URL:http://a/b/c/g/>
  142.       /g         = <URL:http://a/g>
  143.       //g        = <URL:http://g>
  144.       ?y         = <URL:http://a/b/c/d?y>
  145.       g?y        = <URL:http://a/b/c/g?y>
  146.       g?y/./x    = <URL:http://a/b/c/g?y/./x>
  147.       .          = <URL:http://a/b/c/>
  148.       ./         = <URL:http://a/b/c/>
  149.       ..         = <URL:http://a/b/>
  150.       ../        = <URL:http://a/b/>
  151.       ../g       = <URL:http://a/b/g>
  152.       ../..      = <URL:http://a/>
  153.       ../../g    = <URL:http://a/g>
  154.       ../../../g = <URL:http://a/../g>
  155.       ./../g     = <URL:http://a/b/g>
  156.       ./g/.      = <URL:http://a/b/c/g/>
  157.       /./g       = <URL:http://a/./g>
  158.       g/./h      = <URL:http://a/b/c/g/h>
  159.       g/../h     = <URL:http://a/b/c/h>
  160.       http:g     = <URL:http://a/b/c/g>
  161.       http:      = <URL:http://a/b/c/d>
  162. """
  163.  
  164. def test():
  165.     import sys
  166.     base = ''
  167.     if sys.argv[1:]:
  168.         fn = sys.argv[1]
  169.         if fn == '-':
  170.             fp = sys.stdin
  171.         else:
  172.             fp = open(fn)
  173.     else:
  174.         import StringIO
  175.         fp = StringIO.StringIO(test_input)
  176.     while 1:
  177.         line = fp.readline()
  178.         if not line: break
  179.         words = string.split(line)
  180.         if not words:
  181.             continue
  182.         url = words[0]
  183.         parts = urlparse(url)
  184.         print '%-10s : %s' % (url, parts)
  185.         abs = urljoin(base, url)
  186.         if not base:
  187.             base = abs
  188.         wrapped = '<URL:%s>' % abs
  189.         print '%-10s = %s' % (url, wrapped)
  190.         if len(words) == 3 and words[1] == '=':
  191.             if wrapped != words[2]:
  192.                 print 'EXPECTED', words[2], '!!!!!!!!!!'
  193.  
  194. if __name__ == '__main__':
  195.     test()
  196.