/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/urlutils.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-02-03 23:21:15 UTC
  • mfrom: (7290.42.6 paramiko-compat)
  • Revision ID: breezy.the.bot@gmail.com-20200203232115-g7k11bhsfeiqcprv
Fix compatibility with newer versions of paramiko, which break on noise before keys in pem files.

Merged from https://code.launchpad.net/~jelmer/brz/paramiko-compat/+merge/378480

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import re
23
23
import sys
24
24
 
25
 
from urllib import parse as urlparse
 
25
try:
 
26
    import urlparse
 
27
except ImportError:
 
28
    from urllib import parse as urlparse
26
29
 
27
30
from . import (
28
31
    errors,
34
37
from posixpath import split as _posix_split
35
38
""")
36
39
 
 
40
from .sixish import (
 
41
    int2byte,
 
42
    PY3,
 
43
    text_type,
 
44
    unichr,
 
45
    )
37
46
 
38
47
 
39
48
class InvalidURL(errors.PathError):
90
99
    return split(url, exclude_trailing_slash=exclude_trailing_slash)[0]
91
100
 
92
101
 
93
 
quote_from_bytes = urlparse.quote_from_bytes
94
 
quote = urlparse.quote
95
 
unquote_to_bytes = urlparse.unquote_to_bytes
 
102
if PY3:
 
103
    quote_from_bytes = urlparse.quote_from_bytes
 
104
    quote = urlparse.quote
 
105
    unquote_to_bytes = urlparse.unquote_to_bytes
 
106
else:
 
107
    # Private copies of quote and unquote, copied from Python's urllib module
 
108
    # because urllib unconditionally imports socket, which imports ssl.
 
109
 
 
110
    always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
111
                   'abcdefghijklmnopqrstuvwxyz'
 
112
                   '0123456789' '_.-')
 
113
    _safe_map = {}
 
114
    for i, c in zip(range(256), ''.join(map(chr, range(256)))):
 
115
        _safe_map[c] = c if (
 
116
            i < 128 and c in always_safe) else '%{0:02X}'.format(i)
 
117
    _safe_quoters = {}
 
118
 
 
119
    def quote_from_bytes(s, safe='/'):
 
120
        """quote('abc def') -> 'abc%20def'
 
121
 
 
122
        Each part of a URL, e.g. the path info, the query, etc., has a
 
123
        different set of reserved characters that must be quoted.
 
124
 
 
125
        RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
 
126
        the following reserved characters.
 
127
 
 
128
        reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
 
129
                      "$" | ","
 
130
 
 
131
        Each of these characters is reserved in some component of a URL,
 
132
        but not necessarily in all of them.
 
133
 
 
134
        By default, the quote function is intended for quoting the path
 
135
        section of a URL.  Thus, it will not encode '/'.  This character
 
136
        is reserved, but in typical usage the quote function is being
 
137
        called on a path where the existing slash characters are used as
 
138
        reserved characters.
 
139
        """
 
140
        # fastpath
 
141
        if not s:
 
142
            if s is None:
 
143
                raise TypeError('None object cannot be quoted')
 
144
            return s
 
145
        cachekey = (safe, always_safe)
 
146
        try:
 
147
            (quoter, safe) = _safe_quoters[cachekey]
 
148
        except KeyError:
 
149
            safe_map = _safe_map.copy()
 
150
            safe_map.update([(c, c) for c in safe])
 
151
            quoter = safe_map.__getitem__
 
152
            safe = always_safe + safe
 
153
            _safe_quoters[cachekey] = (quoter, safe)
 
154
        if not s.rstrip(safe):
 
155
            return s
 
156
        return ''.join(map(quoter, s))
 
157
 
 
158
    quote = quote_from_bytes
 
159
    unquote_to_bytes = urlparse.unquote
 
160
 
 
161
 
96
162
unquote = urlparse.unquote
97
163
 
98
164
 
99
165
def escape(relpath, safe='/~'):
100
166
    """Escape relpath to be a valid url."""
 
167
    if not isinstance(relpath, str) and sys.version_info[0] == 2:
 
168
        # GZ 2019-06-16: Should use _fs_enc instead here really?
 
169
        relpath = relpath.encode('utf-8')
101
170
    return quote(relpath, safe=safe)
102
171
 
103
172
 
342
411
        return local_path_to_url(url)
343
412
    prefix = url[:path_start]
344
413
    path = url[path_start:]
345
 
    if not isinstance(url, str):
 
414
    if not isinstance(url, text_type):
346
415
        for c in url:
347
416
            if c not in _url_safe_characters:
348
417
                raise InvalidURL(url, 'URLs can only contain specific'
622
691
    #       try to encode the UNICODE => ASCII, and then decode
623
692
    #       it into utf-8.
624
693
 
625
 
    if isinstance(url, str):
 
694
    if PY3:
 
695
        if isinstance(url, text_type):
 
696
            try:
 
697
                url.encode("ascii")
 
698
            except UnicodeError as e:
 
699
                raise InvalidURL(
 
700
                    url, 'URL was not a plain ASCII url: %s' % (e,))
 
701
        return urlparse.unquote(url)
 
702
    else:
 
703
        if isinstance(url, text_type):
 
704
            try:
 
705
                url = url.encode("ascii")
 
706
            except UnicodeError as e:
 
707
                raise InvalidURL(
 
708
                    url, 'URL was not a plain ASCII url: %s' % (e,))
 
709
        unquoted = unquote(url)
626
710
        try:
627
 
            url.encode("ascii")
 
711
            unicode_path = unquoted.decode('utf-8')
628
712
        except UnicodeError as e:
629
713
            raise InvalidURL(
630
 
                url, 'URL was not a plain ASCII url: %s' % (e,))
631
 
    return urlparse.unquote(url)
 
714
                url, 'Unable to encode the URL as utf-8: %s' % (e,))
 
715
        return unicode_path
632
716
 
633
717
 
634
718
# These are characters that if escaped, should stay that way
636
720
_no_decode_ords = [ord(c) for c in _no_decode_chars]
637
721
_no_decode_hex = (['%02x' % o for o in _no_decode_ords]
638
722
                  + ['%02X' % o for o in _no_decode_ords])
639
 
_hex_display_map = dict(([('%02x' % o, bytes([o])) for o in range(256)]
640
 
                         + [('%02X' % o, bytes([o])) for o in range(256)]))
 
723
_hex_display_map = dict(([('%02x' % o, int2byte(o)) for o in range(256)]
 
724
                         + [('%02X' % o, int2byte(o)) for o in range(256)]))
641
725
# These entries get mapped to themselves
642
726
_hex_display_map.update((hex, b'%' + hex.encode('ascii'))
643
727
                        for hex in _no_decode_hex)
681
765
            escaped_chunks[j] = _hex_display_map[item[:2]]
682
766
        except KeyError:
683
767
            # Put back the percent symbol
684
 
            escaped_chunks[j] = b'%' + (item[:2].encode('utf-8'))
 
768
            escaped_chunks[j] = b'%' + \
 
769
                (item[:2].encode('utf-8') if PY3 else item[:2])
685
770
        except UnicodeDecodeError:
686
 
            escaped_chunks[j] = chr(int(item[:2], 16)).encode('utf-8')
687
 
        escaped_chunks[j] += (item[2:].encode('utf-8'))
 
771
            escaped_chunks[j] = unichr(int(item[:2], 16)).encode('utf-8')
 
772
        escaped_chunks[j] += (item[2:].encode('utf-8') if PY3 else item[2:])
688
773
    unescaped = b''.join(escaped_chunks)
689
774
    try:
690
775
        decoded = unescaped.decode('utf-8')
848
933
        # unicode.
849
934
        if isinstance(url, str):
850
935
            pass
851
 
        elif isinstance(url, str):
 
936
        elif isinstance(url, text_type):
852
937
            try:
853
938
                url = url.encode()
854
939
            except UnicodeEncodeError:
919
1004
        # unicode.
920
1005
        if isinstance(relpath, str):
921
1006
            pass
922
 
        elif isinstance(relpath, str):
 
1007
        elif isinstance(relpath, text_type):
923
1008
            try:
924
1009
                relpath = relpath.encode()
925
1010
            except UnicodeEncodeError:
957
1042
        """
958
1043
        if offset is not None:
959
1044
            relative = unescape(offset)
 
1045
            if sys.version_info[0] == 2:
 
1046
                relative = relative.encode('utf-8')
960
1047
            path = self._combine_paths(self.path, relative)
961
1048
            path = quote(path, safe="/~")
962
1049
        else: