Какой тип URL не соответствует RFC 3986, но соответствует RFC 1808, RFC 1738 и RFC 2732? - PullRequest
2 голосов
/ 10 апреля 2019

Документ URLComponents.init(url:resolvingAgainstBaseURL:) говорит:

Возвращает инициализированный объект компонентов URL или nil, если URL не может быть проанализирован.

Зная, что:

Я предполагаю, что инициализация URLComponents завершится неудачно, когда URL соответствует RFC 1808/1738/2732, но не RFC 3986. Что это за URL? Любой пример?

Единственная подсказка, которая у меня есть, поскольку разница может быть связана с разными зарезервированными символами?

1 Ответ

2 голосов
/ 11 апреля 2019

Давайте рассмотрим его из его исходного кода, поскольку Swift Foundation является открытым исходным кодом.

  1. Инициализатор URLComponents реализован в apple / swift - URLComponents.swift и apple / swift-corelibs-foundation - URLComponents.swift и просто вызывает инициализатор NSURLComponents.

  2. Инициализатор NSURLComponents реализован в apple / swift-corelibs-foundation - NSURL.swift и просто вызывает _CFURLComponentsCreateWithURL.

  3. _CFURLComponentsCreateWithURL реализовано в apple / swift-corelibs-foundation - CFURLComponents.c и делает:

    • ошибочную копию с CFURLCopyAbsoluteURL
    • неудачное создание с _CFURLComponentsCreateWithString, которая вызывает:
      • _CFURIParserParseURIReference + неисправный _CFURIParserURLStringIsValid
  4. CFURLCopyAbsoluteURL реализован в apple / swift-corelibs-foundation - CFURL.c и не работает только для:

    #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
        if ( base && CFURLIsFileReferenceURL(base) && !CFURLHasDirectoryPath(base) ) {
            // 16695827 - If the base URL is a file reference URL which doesn't end with a slash, we have to convert it to a file path URL before we can make it absolute.
            base = CFURLCreateFilePathURL(alloc, base, NULL);
            if ( !base ) {
                // could not convert file reference URL to file path URL -- fail will NULL
                return NULL;
            }
        }
    #endif
    

    Реализация CFURLCreateFilePathURL находится в opensource.apple.com / source / CF - CFURL.c , и я понимаюЭто означает, что он потерпит неудачу только в том случае, если отсутствует схема или отсутствует путь, что не должно быть возможным, поскольку мы ранее проверяли схему файла или существование файла с CFURLIsFileReferenceURL.

  5. _CFURIParserParseURIReference реализовано в apple / swift-corelibs-foundation - CFURLComponents_URIParser.c и завершится ошибкой только в том случае, если длина URL-адреса превышает 2 ГБ, что, я считаю, не связано со спецификациями RFC.

  6. _CFURIParserURLStringIsValid по существу вызовет _CFURIParserValidateComponent для каждого компонента и завершится ошибкой для недопустимых символов или escape-последовательностей. Возможно, это самая важная часть.

Теперь, немного поэкспериментировав, мы знаем, что нам нужна схема (например, https:// или просто a://) и мы поиграем с зарезервированными символами, чтобы найти примеры, такие как:

// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!

Попытка альтернативного инициализатора URLComponents также не удастся, так что не пытайтесь думать, что это не так:

// CRASH
let components = URLComponents(string: url.absoluteString)!

Заключение

"a://@@" - пример действительного NSURL, но недействительного RFC 3986.


В дополнение к этому некоторые Swift люди, кажется, желаютбудущее для унификации поддержки URL и URLComponents (больше никаких различий в RFC) как видно в URL.swift :

// Примечание о будущей реализации:
// NSURL(на самом деле CFURL, который обеспечивает его реализацию) имеет довольно много особенностей при обработке некоторых более эзотерических (и некоторых не очень эзотерических) строк.Мы хотели бы перенести большую часть этого на более современные NSURLComponents, но проблемы двоичного компатации сделали это трудным.
// Надеемся, что скоро мы сможем заменить некоторые из нижеприведенного делегирования в NSURL делегированием вместо NSURLComponents.Это не может быть сделано по частям, потому что в противном случае мы получим противоречивые результаты от API.

Я не уверен, как они планируют это сделать, поскольку это будет означать, что либо URL(string: "a://@@") потерпит неудачу, либоURLComponents(string: "a://@@") будет успешным.

...