python urllib.parse.urljoin по пути, начинающемуся с цифр и двоеточия - PullRequest
2 голосов
/ 17 марта 2019

Простите, какого черта?

>>> import urllib.parse
>>> base = 'http://example.com'
>>> urllib.parse.urljoin(base, 'abc:123')
'http://example.com/abc:123'
>>> urllib.parse.urljoin(base, '123:abc')
'123:abc'
>>> urllib.parse.urljoin(base + '/', './123:abc')
'http://example.com/123:abc'

python3.7 документация гласит:

Изменено в версии 3.5: поведение обновлено в соответствии с семантикой, определенной в RFC 3986.

Какая часть этого RFC вызывает такое безумие, и следует ли это считать ошибкой?

1 Ответ

1 голос
/ 17 марта 2019

Какая часть этого RFC вызывает такое безумие?

Это поведение правильно и соответствует с другими реализациями, как указано RFC3986 :

Сегмент пути, который содержит символ двоеточия (например, «this: that»), нельзя использовать в качестве первого сегмента ссылки относительного пути , так как он будет ошибочно принят за имя схемы. Такому сегменту должен предшествовать точечный сегмент (например, "./this:that"), чтобы сделать ссылку на относительный путь.

Это уже обсуждалось в другой записи :

Двоеточия разрешены в пути URI. Но вы должны быть осторожны, когда пишете относительные пути URI с двоеточием, так как это не разрешено при использовании так:

<a href="tag:sample">

В этом случае тег будет интерпретироваться как схема URI. Вместо этого вам нужно написать это так:

<a href="./tag:sample">

Использование urljoin

Функция urljoin просто обрабатывает оба аргумента как URL (без какого-либо предположения). Требуется, чтобы их схемы были идентичными или вторая представляла относительный путь URI . В противном случае он возвращает только второй аргумент (хотя, ИМХО, это должно вызвать ошибку). Вы можете лучше понять логику, посмотрев на источник urljoin .

def urljoin(base, url, allow_fragments=True):
    """Join a base URL and a possibly relative URL to form an absolute
    interpretation of the latter."""
    ...
    bscheme, bnetloc, bpath, bparams, bquery, bfragment = \
            urlparse(base, '', allow_fragments)
    scheme, netloc, path, params, query, fragment = \
            urlparse(url, bscheme, allow_fragments)

    if scheme != bscheme or scheme not in uses_relative:
        return _coerce_result(url)

Результаты процедуры синтаксического анализа urlparse следующие:

>>> from urllib.parse import urlparse
>>> urlparse('123:abc')
ParseResult(scheme='123', netloc='', path='abc', params='', query='', fragment='')
>>> urlparse('abc:123')
ParseResult(scheme='', netloc='', path='abc:123', params='', query='', fragment='')
>>> urlparse('abc:a123')
ParseResult(scheme='abc', netloc='', path='a123', params='', query='', fragment='')
...