|
18 | 18 | urlparse, |
19 | 19 | ) |
20 | 20 |
|
| 21 | +if six.PY2: |
| 22 | + from urlparse import ( |
| 23 | + ParseResult, SplitResult, _splitnetloc, _splitparams, scheme_chars, |
| 24 | + uses_params, |
| 25 | + ) |
| 26 | + _coerce_args = None |
| 27 | +else: |
| 28 | + from urllib.parse import ( |
| 29 | + ParseResult, SplitResult, _coerce_args, _splitnetloc, _splitparams, |
| 30 | + scheme_chars, uses_params, |
| 31 | + ) |
| 32 | + |
21 | 33 | ETAG_MATCH = re.compile(r'(?:W/)?"((?:\\.|[^"])*)"') |
22 | 34 |
|
23 | 35 | MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split() |
@@ -287,12 +299,64 @@ def is_safe_url(url, host=None): |
287 | 299 | return _is_safe_url(url, host) and _is_safe_url(url.replace('\\', '/'), host) |
288 | 300 |
|
289 | 301 |
|
| 302 | +# Copied from urllib.parse.urlparse() but uses fixed urlsplit() function. |
| 303 | +def _urlparse(url, scheme='', allow_fragments=True): |
| 304 | + """Parse a URL into 6 components: |
| 305 | + <scheme>://<netloc>/<path>;<params>?<query>#<fragment> |
| 306 | + Return a 6-tuple: (scheme, netloc, path, params, query, fragment). |
| 307 | + Note that we don't break the components up in smaller bits |
| 308 | + (e.g. netloc is a single string) and we don't expand % escapes.""" |
| 309 | + if _coerce_args: |
| 310 | + url, scheme, _coerce_result = _coerce_args(url, scheme) |
| 311 | + splitresult = _urlsplit(url, scheme, allow_fragments) |
| 312 | + scheme, netloc, url, query, fragment = splitresult |
| 313 | + if scheme in uses_params and ';' in url: |
| 314 | + url, params = _splitparams(url) |
| 315 | + else: |
| 316 | + params = '' |
| 317 | + result = ParseResult(scheme, netloc, url, params, query, fragment) |
| 318 | + return _coerce_result(result) if _coerce_args else result |
| 319 | + |
| 320 | + |
| 321 | +# Copied from urllib.parse.urlsplit() with |
| 322 | +# https://github.com/python/cpython/pull/661 applied. |
| 323 | +def _urlsplit(url, scheme='', allow_fragments=True): |
| 324 | + """Parse a URL into 5 components: |
| 325 | + <scheme>://<netloc>/<path>?<query>#<fragment> |
| 326 | + Return a 5-tuple: (scheme, netloc, path, query, fragment). |
| 327 | + Note that we don't break the components up in smaller bits |
| 328 | + (e.g. netloc is a single string) and we don't expand % escapes.""" |
| 329 | + if _coerce_args: |
| 330 | + url, scheme, _coerce_result = _coerce_args(url, scheme) |
| 331 | + allow_fragments = bool(allow_fragments) |
| 332 | + netloc = query = fragment = '' |
| 333 | + i = url.find(':') |
| 334 | + if i > 0: |
| 335 | + for c in url[:i]: |
| 336 | + if c not in scheme_chars: |
| 337 | + break |
| 338 | + else: |
| 339 | + scheme, url = url[:i].lower(), url[i + 1:] |
| 340 | + |
| 341 | + if url[:2] == '//': |
| 342 | + netloc, url = _splitnetloc(url, 2) |
| 343 | + if (('[' in netloc and ']' not in netloc) or |
| 344 | + (']' in netloc and '[' not in netloc)): |
| 345 | + raise ValueError("Invalid IPv6 URL") |
| 346 | + if allow_fragments and '#' in url: |
| 347 | + url, fragment = url.split('#', 1) |
| 348 | + if '?' in url: |
| 349 | + url, query = url.split('?', 1) |
| 350 | + v = SplitResult(scheme, netloc, url, query, fragment) |
| 351 | + return _coerce_result(v) if _coerce_args else v |
| 352 | + |
| 353 | + |
290 | 354 | def _is_safe_url(url, host): |
291 | 355 | # Chrome considers any URL with more than two slashes to be absolute, but |
292 | 356 | # urlparse is not so flexible. Treat any url with three slashes as unsafe. |
293 | 357 | if url.startswith('///'): |
294 | 358 | return False |
295 | | - url_info = urlparse(url) |
| 359 | + url_info = _urlparse(url) |
296 | 360 | # Forbid URLs like http:///example.com - with a scheme, but without a hostname. |
297 | 361 | # In that URL, example.com is not the hostname but, a path component. However, |
298 | 362 | # Chrome will still consider example.com to be the hostname, so we must not |
|
0 commit comments