Mercurial > public > mercurial-scm > hg
comparison tests/test-url.py @ 37875:078c3eec2d5c
tests: port test-url.py to Python 3
# skip-blame it's all b prefixes and pycompat.bytestr() wrappers
Differential Revision: https://phab.mercurial-scm.org/D3470
author | Augie Fackler <augie@google.com> |
---|---|
date | Fri, 27 Apr 2018 00:08:48 -0400 |
parents | 0dcd03637d36 |
children | d088810c496e |
comparison
equal
deleted
inserted
replaced
37874:0dcd03637d36 | 37875:078c3eec2d5c |
---|---|
18 _verifycert = sslutil._verifycert | 18 _verifycert = sslutil._verifycert |
19 # Test non-wildcard certificates | 19 # Test non-wildcard certificates |
20 check(_verifycert(cert('example.com'), 'example.com'), | 20 check(_verifycert(cert('example.com'), 'example.com'), |
21 None) | 21 None) |
22 check(_verifycert(cert('example.com'), 'www.example.com'), | 22 check(_verifycert(cert('example.com'), 'www.example.com'), |
23 'certificate is for example.com') | 23 b'certificate is for example.com') |
24 check(_verifycert(cert('www.example.com'), 'example.com'), | 24 check(_verifycert(cert('www.example.com'), 'example.com'), |
25 'certificate is for www.example.com') | 25 b'certificate is for www.example.com') |
26 | 26 |
27 # Test wildcard certificates | 27 # Test wildcard certificates |
28 check(_verifycert(cert('*.example.com'), 'www.example.com'), | 28 check(_verifycert(cert('*.example.com'), 'www.example.com'), |
29 None) | 29 None) |
30 check(_verifycert(cert('*.example.com'), 'example.com'), | 30 check(_verifycert(cert('*.example.com'), 'example.com'), |
31 'certificate is for *.example.com') | 31 b'certificate is for *.example.com') |
32 check(_verifycert(cert('*.example.com'), 'w.w.example.com'), | 32 check(_verifycert(cert('*.example.com'), 'w.w.example.com'), |
33 'certificate is for *.example.com') | 33 b'certificate is for *.example.com') |
34 | 34 |
35 # Test subjectAltName | 35 # Test subjectAltName |
36 san_cert = {'subject': ((('commonName', 'example.com'),),), | 36 san_cert = {'subject': ((('commonName', 'example.com'),),), |
37 'subjectAltName': (('DNS', '*.example.net'), | 37 'subjectAltName': (('DNS', '*.example.net'), |
38 ('DNS', 'example.net'))} | 38 ('DNS', 'example.net'))} |
40 None) | 40 None) |
41 check(_verifycert(san_cert, 'foo.example.net'), | 41 check(_verifycert(san_cert, 'foo.example.net'), |
42 None) | 42 None) |
43 # no fallback to subject commonName when subjectAltName has DNS | 43 # no fallback to subject commonName when subjectAltName has DNS |
44 check(_verifycert(san_cert, 'example.com'), | 44 check(_verifycert(san_cert, 'example.com'), |
45 'certificate is for *.example.net, example.net') | 45 b'certificate is for *.example.net, example.net') |
46 # fallback to subject commonName when no DNS in subjectAltName | 46 # fallback to subject commonName when no DNS in subjectAltName |
47 san_cert = {'subject': ((('commonName', 'example.com'),),), | 47 san_cert = {'subject': ((('commonName', 'example.com'),),), |
48 'subjectAltName': (('IP Address', '8.8.8.8'),)} | 48 'subjectAltName': (('IP Address', '8.8.8.8'),)} |
49 check(_verifycert(san_cert, 'example.com'), None) | 49 check(_verifycert(san_cert, 'example.com'), None) |
50 | 50 |
51 # Avoid some pitfalls | 51 # Avoid some pitfalls |
52 check(_verifycert(cert('*.foo'), 'foo'), | 52 check(_verifycert(cert('*.foo'), 'foo'), |
53 'certificate is for *.foo') | 53 b'certificate is for *.foo') |
54 check(_verifycert(cert('*o'), 'foo'), None) | 54 check(_verifycert(cert('*o'), 'foo'), None) |
55 | 55 |
56 check(_verifycert({'subject': ()}, | 56 check(_verifycert({'subject': ()}, |
57 'example.com'), | 57 'example.com'), |
58 'no commonName or subjectAltName found in certificate') | 58 b'no commonName or subjectAltName found in certificate') |
59 check(_verifycert(None, 'example.com'), | 59 check(_verifycert(None, 'example.com'), |
60 'no certificate received') | 60 b'no certificate received') |
61 | 61 |
62 # Unicode (IDN) certname isn't supported | 62 # Unicode (IDN) certname isn't supported |
63 check(_verifycert(cert(u'\u4f8b.jp'), 'example.jp'), | 63 check(_verifycert(cert(u'\u4f8b.jp'), 'example.jp'), |
64 'IDN in certificate not supported') | 64 b'IDN in certificate not supported') |
65 | 65 |
66 # The following tests are from CPython's test_ssl.py. | 66 # The following tests are from CPython's test_ssl.py. |
67 check(_verifycert(cert('example.com'), 'example.com'), None) | 67 check(_verifycert(cert('example.com'), 'example.com'), None) |
68 check(_verifycert(cert('example.com'), 'ExAmple.cOm'), None) | 68 check(_verifycert(cert('example.com'), 'ExAmple.cOm'), None) |
69 check(_verifycert(cert('example.com'), 'www.example.com'), | 69 check(_verifycert(cert('example.com'), 'www.example.com'), |
70 'certificate is for example.com') | 70 b'certificate is for example.com') |
71 check(_verifycert(cert('example.com'), '.example.com'), | 71 check(_verifycert(cert('example.com'), '.example.com'), |
72 'certificate is for example.com') | 72 b'certificate is for example.com') |
73 check(_verifycert(cert('example.com'), 'example.org'), | 73 check(_verifycert(cert('example.com'), 'example.org'), |
74 'certificate is for example.com') | 74 b'certificate is for example.com') |
75 check(_verifycert(cert('example.com'), 'exampleXcom'), | 75 check(_verifycert(cert('example.com'), 'exampleXcom'), |
76 'certificate is for example.com') | 76 b'certificate is for example.com') |
77 check(_verifycert(cert('*.a.com'), 'foo.a.com'), None) | 77 check(_verifycert(cert('*.a.com'), 'foo.a.com'), None) |
78 check(_verifycert(cert('*.a.com'), 'bar.foo.a.com'), | 78 check(_verifycert(cert('*.a.com'), 'bar.foo.a.com'), |
79 'certificate is for *.a.com') | 79 b'certificate is for *.a.com') |
80 check(_verifycert(cert('*.a.com'), 'a.com'), | 80 check(_verifycert(cert('*.a.com'), 'a.com'), |
81 'certificate is for *.a.com') | 81 b'certificate is for *.a.com') |
82 check(_verifycert(cert('*.a.com'), 'Xa.com'), | 82 check(_verifycert(cert('*.a.com'), 'Xa.com'), |
83 'certificate is for *.a.com') | 83 b'certificate is for *.a.com') |
84 check(_verifycert(cert('*.a.com'), '.a.com'), | 84 check(_verifycert(cert('*.a.com'), '.a.com'), |
85 'certificate is for *.a.com') | 85 b'certificate is for *.a.com') |
86 | 86 |
87 # only match one left-most wildcard | 87 # only match one left-most wildcard |
88 check(_verifycert(cert('f*.com'), 'foo.com'), None) | 88 check(_verifycert(cert('f*.com'), 'foo.com'), None) |
89 check(_verifycert(cert('f*.com'), 'f.com'), None) | 89 check(_verifycert(cert('f*.com'), 'f.com'), None) |
90 check(_verifycert(cert('f*.com'), 'bar.com'), | 90 check(_verifycert(cert('f*.com'), 'bar.com'), |
91 'certificate is for f*.com') | 91 b'certificate is for f*.com') |
92 check(_verifycert(cert('f*.com'), 'foo.a.com'), | 92 check(_verifycert(cert('f*.com'), 'foo.a.com'), |
93 'certificate is for f*.com') | 93 b'certificate is for f*.com') |
94 check(_verifycert(cert('f*.com'), 'bar.foo.com'), | 94 check(_verifycert(cert('f*.com'), 'bar.foo.com'), |
95 'certificate is for f*.com') | 95 b'certificate is for f*.com') |
96 | 96 |
97 # NULL bytes are bad, CVE-2013-4073 | 97 # NULL bytes are bad, CVE-2013-4073 |
98 check(_verifycert(cert('null.python.org\x00example.org'), | 98 check(_verifycert(cert('null.python.org\x00example.org'), |
99 'null.python.org\x00example.org'), None) | 99 'null.python.org\x00example.org'), None) |
100 check(_verifycert(cert('null.python.org\x00example.org'), | 100 check(_verifycert(cert('null.python.org\x00example.org'), |
101 'example.org'), | 101 'example.org'), |
102 'certificate is for null.python.org\x00example.org') | 102 b'certificate is for null.python.org\x00example.org') |
103 check(_verifycert(cert('null.python.org\x00example.org'), | 103 check(_verifycert(cert('null.python.org\x00example.org'), |
104 'null.python.org'), | 104 'null.python.org'), |
105 'certificate is for null.python.org\x00example.org') | 105 b'certificate is for null.python.org\x00example.org') |
106 | 106 |
107 # error cases with wildcards | 107 # error cases with wildcards |
108 check(_verifycert(cert('*.*.a.com'), 'bar.foo.a.com'), | 108 check(_verifycert(cert('*.*.a.com'), 'bar.foo.a.com'), |
109 'certificate is for *.*.a.com') | 109 b'certificate is for *.*.a.com') |
110 check(_verifycert(cert('*.*.a.com'), 'a.com'), | 110 check(_verifycert(cert('*.*.a.com'), 'a.com'), |
111 'certificate is for *.*.a.com') | 111 b'certificate is for *.*.a.com') |
112 check(_verifycert(cert('*.*.a.com'), 'Xa.com'), | 112 check(_verifycert(cert('*.*.a.com'), 'Xa.com'), |
113 'certificate is for *.*.a.com') | 113 b'certificate is for *.*.a.com') |
114 check(_verifycert(cert('*.*.a.com'), '.a.com'), | 114 check(_verifycert(cert('*.*.a.com'), '.a.com'), |
115 'certificate is for *.*.a.com') | 115 b'certificate is for *.*.a.com') |
116 | 116 |
117 check(_verifycert(cert('a.*.com'), 'a.foo.com'), | 117 check(_verifycert(cert('a.*.com'), 'a.foo.com'), |
118 'certificate is for a.*.com') | 118 b'certificate is for a.*.com') |
119 check(_verifycert(cert('a.*.com'), 'a..com'), | 119 check(_verifycert(cert('a.*.com'), 'a..com'), |
120 'certificate is for a.*.com') | 120 b'certificate is for a.*.com') |
121 check(_verifycert(cert('a.*.com'), 'a.com'), | 121 check(_verifycert(cert('a.*.com'), 'a.com'), |
122 'certificate is for a.*.com') | 122 b'certificate is for a.*.com') |
123 | 123 |
124 # wildcard doesn't match IDNA prefix 'xn--' | 124 # wildcard doesn't match IDNA prefix 'xn--' |
125 idna = u'püthon.python.org'.encode('idna').decode('ascii') | 125 idna = u'püthon.python.org'.encode('idna').decode('ascii') |
126 check(_verifycert(cert(idna), idna), None) | 126 check(_verifycert(cert(idna), idna), None) |
127 check(_verifycert(cert('x*.python.org'), idna), | 127 check(_verifycert(cert('x*.python.org'), idna), |
128 'certificate is for x*.python.org') | 128 b'certificate is for x*.python.org') |
129 check(_verifycert(cert('xn--p*.python.org'), idna), | 129 check(_verifycert(cert('xn--p*.python.org'), idna), |
130 'certificate is for xn--p*.python.org') | 130 b'certificate is for xn--p*.python.org') |
131 | 131 |
132 # wildcard in first fragment and IDNA A-labels in sequent fragments | 132 # wildcard in first fragment and IDNA A-labels in sequent fragments |
133 # are supported. | 133 # are supported. |
134 idna = u'www*.pythön.org'.encode('idna').decode('ascii') | 134 idna = u'www*.pythön.org'.encode('idna').decode('ascii') |
135 check(_verifycert(cert(idna), | 135 check(_verifycert(cert(idna), |
138 check(_verifycert(cert(idna), | 138 check(_verifycert(cert(idna), |
139 u'www1.pythön.org'.encode('idna').decode('ascii')), | 139 u'www1.pythön.org'.encode('idna').decode('ascii')), |
140 None) | 140 None) |
141 check(_verifycert(cert(idna), | 141 check(_verifycert(cert(idna), |
142 u'ftp.pythön.org'.encode('idna').decode('ascii')), | 142 u'ftp.pythön.org'.encode('idna').decode('ascii')), |
143 'certificate is for www*.xn--pythn-mua.org') | 143 b'certificate is for www*.xn--pythn-mua.org') |
144 check(_verifycert(cert(idna), | 144 check(_verifycert(cert(idna), |
145 u'pythön.org'.encode('idna').decode('ascii')), | 145 u'pythön.org'.encode('idna').decode('ascii')), |
146 'certificate is for www*.xn--pythn-mua.org') | 146 b'certificate is for www*.xn--pythn-mua.org') |
147 | 147 |
148 c = { | 148 c = { |
149 'notAfter': 'Jun 26 21:41:46 2011 GMT', | 149 'notAfter': 'Jun 26 21:41:46 2011 GMT', |
150 'subject': (((u'commonName', u'linuxfrz.org'),),), | 150 'subject': (((u'commonName', u'linuxfrz.org'),),), |
151 'subjectAltName': ( | 151 'subjectAltName': ( |
156 } | 156 } |
157 check(_verifycert(c, 'linuxfr.org'), None) | 157 check(_verifycert(c, 'linuxfr.org'), None) |
158 check(_verifycert(c, 'linuxfr.com'), None) | 158 check(_verifycert(c, 'linuxfr.com'), None) |
159 # Not a "DNS" entry | 159 # Not a "DNS" entry |
160 check(_verifycert(c, '<unsupported>'), | 160 check(_verifycert(c, '<unsupported>'), |
161 'certificate is for linuxfr.org, linuxfr.com') | 161 b'certificate is for linuxfr.org, linuxfr.com') |
162 # When there is a subjectAltName, commonName isn't used | 162 # When there is a subjectAltName, commonName isn't used |
163 check(_verifycert(c, 'linuxfrz.org'), | 163 check(_verifycert(c, 'linuxfrz.org'), |
164 'certificate is for linuxfr.org, linuxfr.com') | 164 b'certificate is for linuxfr.org, linuxfr.com') |
165 | 165 |
166 # A pristine real-world example | 166 # A pristine real-world example |
167 c = { | 167 c = { |
168 'notAfter': 'Dec 18 23:59:59 2011 GMT', | 168 'notAfter': 'Dec 18 23:59:59 2011 GMT', |
169 'subject': ( | 169 'subject': ( |
173 ((u'organizationName', u'Google Inc'),), | 173 ((u'organizationName', u'Google Inc'),), |
174 ((u'commonName', u'mail.google.com'),), | 174 ((u'commonName', u'mail.google.com'),), |
175 ), | 175 ), |
176 } | 176 } |
177 check(_verifycert(c, 'mail.google.com'), None) | 177 check(_verifycert(c, 'mail.google.com'), None) |
178 check(_verifycert(c, 'gmail.com'), 'certificate is for mail.google.com') | 178 check(_verifycert(c, 'gmail.com'), b'certificate is for mail.google.com') |
179 | 179 |
180 # Only commonName is considered | 180 # Only commonName is considered |
181 check(_verifycert(c, 'California'), 'certificate is for mail.google.com') | 181 check(_verifycert(c, 'California'), b'certificate is for mail.google.com') |
182 | 182 |
183 # Neither commonName nor subjectAltName | 183 # Neither commonName nor subjectAltName |
184 c = { | 184 c = { |
185 'notAfter': 'Dec 18 23:59:59 2011 GMT', | 185 'notAfter': 'Dec 18 23:59:59 2011 GMT', |
186 'subject': ( | 186 'subject': ( |
189 ((u'localityName', u'Mountain View'),), | 189 ((u'localityName', u'Mountain View'),), |
190 ((u'organizationName', u'Google Inc'),), | 190 ((u'organizationName', u'Google Inc'),), |
191 ), | 191 ), |
192 } | 192 } |
193 check(_verifycert(c, 'mail.google.com'), | 193 check(_verifycert(c, 'mail.google.com'), |
194 'no commonName or subjectAltName found in certificate') | 194 b'no commonName or subjectAltName found in certificate') |
195 | 195 |
196 # No DNS entry in subjectAltName but a commonName | 196 # No DNS entry in subjectAltName but a commonName |
197 c = { | 197 c = { |
198 'notAfter': 'Dec 18 23:59:59 2099 GMT', | 198 'notAfter': 'Dec 18 23:59:59 2099 GMT', |
199 'subject': ( | 199 'subject': ( |
216 ((u'organizationName', u'Google Inc'),), | 216 ((u'organizationName', u'Google Inc'),), |
217 ), | 217 ), |
218 'subjectAltName': (('othername', 'blabla'),), | 218 'subjectAltName': (('othername', 'blabla'),), |
219 } | 219 } |
220 check(_verifycert(c, 'google.com'), | 220 check(_verifycert(c, 'google.com'), |
221 'no commonName or subjectAltName found in certificate') | 221 b'no commonName or subjectAltName found in certificate') |
222 | 222 |
223 # Empty cert / no cert | 223 # Empty cert / no cert |
224 check(_verifycert(None, 'example.com'), 'no certificate received') | 224 check(_verifycert(None, 'example.com'), b'no certificate received') |
225 check(_verifycert({}, 'example.com'), 'no certificate received') | 225 check(_verifycert({}, 'example.com'), b'no certificate received') |
226 | 226 |
227 # avoid denials of service by refusing more than one | 227 # avoid denials of service by refusing more than one |
228 # wildcard per fragment. | 228 # wildcard per fragment. |
229 check(_verifycert({'subject': (((u'commonName', u'a*b.com'),),)}, | 229 check(_verifycert({'subject': (((u'commonName', u'a*b.com'),),)}, |
230 'axxb.com'), None) | 230 'axxb.com'), None) |
231 check(_verifycert({'subject': (((u'commonName', u'a*b.co*'),),)}, | 231 check(_verifycert({'subject': (((u'commonName', u'a*b.co*'),),)}, |
232 'axxb.com'), 'certificate is for a*b.co*') | 232 'axxb.com'), b'certificate is for a*b.co*') |
233 check(_verifycert({'subject': (((u'commonName', u'a*b*.com'),),)}, | 233 check(_verifycert({'subject': (((u'commonName', u'a*b*.com'),),)}, |
234 'axxbxxc.com'), | 234 'axxbxxc.com'), |
235 'too many wildcards in certificate DNS name: a*b*.com') | 235 b'too many wildcards in certificate DNS name: a*b*.com') |
236 | 236 |
237 def test_url(): | 237 def test_url(): |
238 """ | 238 """ |
239 >>> from mercurial import error, pycompat | 239 >>> from mercurial import error, pycompat |
240 >>> from mercurial.util import forcebytestr, url | 240 >>> from mercurial.util import forcebytestr, url |
243 these aren't useful for documentation purposes, so they aren't | 243 these aren't useful for documentation purposes, so they aren't |
244 part of the class's doc tests. | 244 part of the class's doc tests. |
245 | 245 |
246 Query strings and fragments: | 246 Query strings and fragments: |
247 | 247 |
248 >>> url('http://host/a?b#c') | 248 >>> url(b'http://host/a?b#c') |
249 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> | 249 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> |
250 >>> url('http://host/a?') | 250 >>> url(b'http://host/a?') |
251 <url scheme: 'http', host: 'host', path: 'a'> | 251 <url scheme: 'http', host: 'host', path: 'a'> |
252 >>> url('http://host/a#b#c') | 252 >>> url(b'http://host/a#b#c') |
253 <url scheme: 'http', host: 'host', path: 'a', fragment: 'b#c'> | 253 <url scheme: 'http', host: 'host', path: 'a', fragment: 'b#c'> |
254 >>> url('http://host/a#b?c') | 254 >>> url(b'http://host/a#b?c') |
255 <url scheme: 'http', host: 'host', path: 'a', fragment: 'b?c'> | 255 <url scheme: 'http', host: 'host', path: 'a', fragment: 'b?c'> |
256 >>> url('http://host/?a#b') | 256 >>> url(b'http://host/?a#b') |
257 <url scheme: 'http', host: 'host', path: '', query: 'a', fragment: 'b'> | 257 <url scheme: 'http', host: 'host', path: '', query: 'a', fragment: 'b'> |
258 >>> url('http://host/?a#b', parsequery=False) | 258 >>> url(b'http://host/?a#b', parsequery=False) |
259 <url scheme: 'http', host: 'host', path: '?a', fragment: 'b'> | 259 <url scheme: 'http', host: 'host', path: '?a', fragment: 'b'> |
260 >>> url('http://host/?a#b', parsefragment=False) | 260 >>> url(b'http://host/?a#b', parsefragment=False) |
261 <url scheme: 'http', host: 'host', path: '', query: 'a#b'> | 261 <url scheme: 'http', host: 'host', path: '', query: 'a#b'> |
262 >>> url('http://host/?a#b', parsequery=False, parsefragment=False) | 262 >>> url(b'http://host/?a#b', parsequery=False, parsefragment=False) |
263 <url scheme: 'http', host: 'host', path: '?a#b'> | 263 <url scheme: 'http', host: 'host', path: '?a#b'> |
264 | 264 |
265 IPv6 addresses: | 265 IPv6 addresses: |
266 | 266 |
267 >>> url('ldap://[2001:db8::7]/c=GB?objectClass?one') | 267 >>> url(b'ldap://[2001:db8::7]/c=GB?objectClass?one') |
268 <url scheme: 'ldap', host: '[2001:db8::7]', path: 'c=GB', | 268 <url scheme: 'ldap', host: '[2001:db8::7]', path: 'c=GB', |
269 query: 'objectClass?one'> | 269 query: 'objectClass?one'> |
270 >>> url('ldap://joe:xxx@[2001:db8::7]:80/c=GB?objectClass?one') | 270 >>> url(b'ldap://joe:xxx@[2001:db8::7]:80/c=GB?objectClass?one') |
271 <url scheme: 'ldap', user: 'joe', passwd: 'xxx', host: '[2001:db8::7]', | 271 <url scheme: 'ldap', user: 'joe', passwd: 'xxx', host: '[2001:db8::7]', |
272 port: '80', path: 'c=GB', query: 'objectClass?one'> | 272 port: '80', path: 'c=GB', query: 'objectClass?one'> |
273 | 273 |
274 Missing scheme, host, etc.: | 274 Missing scheme, host, etc.: |
275 | 275 |
276 >>> url('://192.0.2.16:80/') | 276 >>> url(b'://192.0.2.16:80/') |
277 <url path: '://192.0.2.16:80/'> | 277 <url path: '://192.0.2.16:80/'> |
278 >>> url('https://mercurial-scm.org') | 278 >>> url(b'https://mercurial-scm.org') |
279 <url scheme: 'https', host: 'mercurial-scm.org'> | 279 <url scheme: 'https', host: 'mercurial-scm.org'> |
280 >>> url('/foo') | 280 >>> url(b'/foo') |
281 <url path: '/foo'> | 281 <url path: '/foo'> |
282 >>> url('bundle:/foo') | 282 >>> url(b'bundle:/foo') |
283 <url scheme: 'bundle', path: '/foo'> | 283 <url scheme: 'bundle', path: '/foo'> |
284 >>> url('a?b#c') | 284 >>> url(b'a?b#c') |
285 <url path: 'a?b', fragment: 'c'> | 285 <url path: 'a?b', fragment: 'c'> |
286 >>> url('http://x.com?arg=/foo') | 286 >>> url(b'http://x.com?arg=/foo') |
287 <url scheme: 'http', host: 'x.com', query: 'arg=/foo'> | 287 <url scheme: 'http', host: 'x.com', query: 'arg=/foo'> |
288 >>> url('http://joe:xxx@/foo') | 288 >>> url(b'http://joe:xxx@/foo') |
289 <url scheme: 'http', user: 'joe', passwd: 'xxx', path: 'foo'> | 289 <url scheme: 'http', user: 'joe', passwd: 'xxx', path: 'foo'> |
290 | 290 |
291 Just a scheme and a path: | 291 Just a scheme and a path: |
292 | 292 |
293 >>> url('mailto:John.Doe@example.com') | 293 >>> url(b'mailto:John.Doe@example.com') |
294 <url scheme: 'mailto', path: 'John.Doe@example.com'> | 294 <url scheme: 'mailto', path: 'John.Doe@example.com'> |
295 >>> url('a:b:c:d') | 295 >>> url(b'a:b:c:d') |
296 <url path: 'a:b:c:d'> | 296 <url path: 'a:b:c:d'> |
297 >>> url('aa:bb:cc:dd') | 297 >>> url(b'aa:bb:cc:dd') |
298 <url scheme: 'aa', path: 'bb:cc:dd'> | 298 <url scheme: 'aa', path: 'bb:cc:dd'> |
299 | 299 |
300 SSH examples: | 300 SSH examples: |
301 | 301 |
302 >>> url('ssh://joe@host//home/joe') | 302 >>> url(b'ssh://joe@host//home/joe') |
303 <url scheme: 'ssh', user: 'joe', host: 'host', path: '/home/joe'> | 303 <url scheme: 'ssh', user: 'joe', host: 'host', path: '/home/joe'> |
304 >>> url('ssh://joe:xxx@host/src') | 304 >>> url(b'ssh://joe:xxx@host/src') |
305 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', path: 'src'> | 305 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', path: 'src'> |
306 >>> url('ssh://joe:xxx@host') | 306 >>> url(b'ssh://joe:xxx@host') |
307 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host'> | 307 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host'> |
308 >>> url('ssh://joe@host') | 308 >>> url(b'ssh://joe@host') |
309 <url scheme: 'ssh', user: 'joe', host: 'host'> | 309 <url scheme: 'ssh', user: 'joe', host: 'host'> |
310 >>> url('ssh://host') | 310 >>> url(b'ssh://host') |
311 <url scheme: 'ssh', host: 'host'> | 311 <url scheme: 'ssh', host: 'host'> |
312 >>> url('ssh://') | 312 >>> url(b'ssh://') |
313 <url scheme: 'ssh'> | 313 <url scheme: 'ssh'> |
314 >>> url('ssh:') | 314 >>> url(b'ssh:') |
315 <url scheme: 'ssh'> | 315 <url scheme: 'ssh'> |
316 | 316 |
317 Non-numeric port: | 317 Non-numeric port: |
318 | 318 |
319 >>> url('http://example.com:dd') | 319 >>> url(b'http://example.com:dd') |
320 <url scheme: 'http', host: 'example.com', port: 'dd'> | 320 <url scheme: 'http', host: 'example.com', port: 'dd'> |
321 >>> url('ssh://joe:xxx@host:ssh/foo') | 321 >>> url(b'ssh://joe:xxx@host:ssh/foo') |
322 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', port: 'ssh', | 322 <url scheme: 'ssh', user: 'joe', passwd: 'xxx', host: 'host', port: 'ssh', |
323 path: 'foo'> | 323 path: 'foo'> |
324 | 324 |
325 Bad authentication credentials: | 325 Bad authentication credentials: |
326 | 326 |
327 >>> url('http://joe@joeville:123@4:@host/a?b#c') | 327 >>> url(b'http://joe@joeville:123@4:@host/a?b#c') |
328 <url scheme: 'http', user: 'joe@joeville', passwd: '123@4:', | 328 <url scheme: 'http', user: 'joe@joeville', passwd: '123@4:', |
329 host: 'host', path: 'a', query: 'b', fragment: 'c'> | 329 host: 'host', path: 'a', query: 'b', fragment: 'c'> |
330 >>> url('http://!*#?/@!*#?/:@host/a?b#c') | 330 >>> url(b'http://!*#?/@!*#?/:@host/a?b#c') |
331 <url scheme: 'http', host: '!*', fragment: '?/@!*#?/:@host/a?b#c'> | 331 <url scheme: 'http', host: '!*', fragment: '?/@!*#?/:@host/a?b#c'> |
332 >>> url('http://!*#?@!*#?:@host/a?b#c') | 332 >>> url(b'http://!*#?@!*#?:@host/a?b#c') |
333 <url scheme: 'http', host: '!*', fragment: '?@!*#?:@host/a?b#c'> | 333 <url scheme: 'http', host: '!*', fragment: '?@!*#?:@host/a?b#c'> |
334 >>> url('http://!*@:!*@@host/a?b#c') | 334 >>> url(b'http://!*@:!*@@host/a?b#c') |
335 <url scheme: 'http', user: '!*@', passwd: '!*@', host: 'host', | 335 <url scheme: 'http', user: '!*@', passwd: '!*@', host: 'host', |
336 path: 'a', query: 'b', fragment: 'c'> | 336 path: 'a', query: 'b', fragment: 'c'> |
337 | 337 |
338 File paths: | 338 File paths: |
339 | 339 |
340 >>> url('a/b/c/d.g.f') | 340 >>> url(b'a/b/c/d.g.f') |
341 <url path: 'a/b/c/d.g.f'> | 341 <url path: 'a/b/c/d.g.f'> |
342 >>> url('/x///z/y/') | 342 >>> url(b'/x///z/y/') |
343 <url path: '/x///z/y/'> | 343 <url path: '/x///z/y/'> |
344 >>> url('/foo:bar') | 344 >>> url(b'/foo:bar') |
345 <url path: '/foo:bar'> | 345 <url path: '/foo:bar'> |
346 >>> url('\\\\foo:bar') | 346 >>> url(b'\\\\foo:bar') |
347 <url path: '\\\\foo:bar'> | 347 <url path: '\\\\foo:bar'> |
348 >>> url('./foo:bar') | 348 >>> url(b'./foo:bar') |
349 <url path: './foo:bar'> | 349 <url path: './foo:bar'> |
350 | 350 |
351 Non-localhost file URL: | 351 Non-localhost file URL: |
352 | 352 |
353 >>> try: | 353 >>> try: |
356 ... forcebytestr(e) | 356 ... forcebytestr(e) |
357 'file:// URLs can only refer to localhost' | 357 'file:// URLs can only refer to localhost' |
358 | 358 |
359 Empty URL: | 359 Empty URL: |
360 | 360 |
361 >>> u = url('') | 361 >>> u = url(b'') |
362 >>> u | 362 >>> u |
363 <url path: ''> | 363 <url path: ''> |
364 >>> str(u) | 364 >>> str(u) |
365 '' | 365 '' |
366 | 366 |
367 Empty path with query string: | 367 Empty path with query string: |
368 | 368 |
369 >>> str(url('http://foo/?bar')) | 369 >>> str(url(b'http://foo/?bar')) |
370 'http://foo/?bar' | 370 'http://foo/?bar' |
371 | 371 |
372 Invalid path: | 372 Invalid path: |
373 | 373 |
374 >>> u = url('http://foo/bar') | 374 >>> u = url(b'http://foo/bar') |
375 >>> u.path = 'bar' | 375 >>> u.path = b'bar' |
376 >>> str(u) | 376 >>> str(u) |
377 'http://foo/bar' | 377 'http://foo/bar' |
378 | 378 |
379 >>> u = url('file:/foo/bar/baz') | 379 >>> u = url(b'file:/foo/bar/baz') |
380 >>> u | 380 >>> u |
381 <url scheme: 'file', path: '/foo/bar/baz'> | 381 <url scheme: 'file', path: '/foo/bar/baz'> |
382 >>> str(u) | 382 >>> str(u) |
383 'file:///foo/bar/baz' | 383 'file:///foo/bar/baz' |
384 >>> u.localpath() | 384 >>> pycompat.bytestr(u.localpath()) |
385 '/foo/bar/baz' | 385 '/foo/bar/baz' |
386 | 386 |
387 >>> u = url('file:///foo/bar/baz') | 387 >>> u = url(b'file:///foo/bar/baz') |
388 >>> u | 388 >>> u |
389 <url scheme: 'file', path: '/foo/bar/baz'> | 389 <url scheme: 'file', path: '/foo/bar/baz'> |
390 >>> str(u) | 390 >>> str(u) |
391 'file:///foo/bar/baz' | 391 'file:///foo/bar/baz' |
392 >>> u.localpath() | 392 >>> pycompat.bytestr(u.localpath()) |
393 '/foo/bar/baz' | 393 '/foo/bar/baz' |
394 | 394 |
395 >>> u = url('file:///f:oo/bar/baz') | 395 >>> u = url(b'file:///f:oo/bar/baz') |
396 >>> u | 396 >>> u |
397 <url scheme: 'file', path: 'f:oo/bar/baz'> | 397 <url scheme: 'file', path: 'f:oo/bar/baz'> |
398 >>> str(u) | 398 >>> str(u) |
399 'file:///f:oo/bar/baz' | 399 'file:///f:oo/bar/baz' |
400 >>> u.localpath() | 400 >>> pycompat.bytestr(u.localpath()) |
401 'f:oo/bar/baz' | 401 'f:oo/bar/baz' |
402 | 402 |
403 >>> u = url('file://localhost/f:oo/bar/baz') | 403 >>> u = url(b'file://localhost/f:oo/bar/baz') |
404 >>> u | 404 >>> u |
405 <url scheme: 'file', host: 'localhost', path: 'f:oo/bar/baz'> | 405 <url scheme: 'file', host: 'localhost', path: 'f:oo/bar/baz'> |
406 >>> str(u) | 406 >>> str(u) |
407 'file://localhost/f:oo/bar/baz' | 407 'file://localhost/f:oo/bar/baz' |
408 >>> u.localpath() | 408 >>> pycompat.bytestr(u.localpath()) |
409 'f:oo/bar/baz' | 409 'f:oo/bar/baz' |
410 | 410 |
411 >>> u = url('file:foo/bar/baz') | 411 >>> u = url(b'file:foo/bar/baz') |
412 >>> u | 412 >>> u |
413 <url scheme: 'file', path: 'foo/bar/baz'> | 413 <url scheme: 'file', path: 'foo/bar/baz'> |
414 >>> str(u) | 414 >>> str(u) |
415 'file:foo/bar/baz' | 415 'file:foo/bar/baz' |
416 >>> u.localpath() | 416 >>> pycompat.bytestr(u.localpath()) |
417 'foo/bar/baz' | 417 'foo/bar/baz' |
418 """ | 418 """ |
419 | 419 |
420 if 'TERM' in os.environ: | 420 if 'TERM' in os.environ: |
421 del os.environ['TERM'] | 421 del os.environ['TERM'] |