Мій URL — це не ваш URL



Коли давним-давно в 1996 році я приступив до роботи над програмою httpget, попередницею проекту Curl, я написав свій перший синтаксичний аналізатор URL. Якраз тоді цей універсальний адреса отримав назву URL: Uniform Resource Locator (єдиний покажчик ресурсів). Його специфікація була опублікована IETF в 1994 році. Абревіатура «URL» була потім використана як джерело натхнення для назви інструменту і проекту Curl.

Термін «URL» пізніше був змінений; його стали називати URI (Uniform Resource Identifier — єдиний ідентифікатор ресурсів), згідно специфікації, опублікованій у 2005 році, проте основне збереглося: синтаксис для рядка, що задає онлайн-ресурс і вказує протокол для отримання цього ресурсу. Ми вимагаємо, щоб curl брав покажчики URL, як визначено даної специфікації RFC 3986. Нижче я розповім, чому насправді це не зовсім так.

Був ще споріднений RFC, що описує IRI: Internationalized Resource Identifier (міжнародний ідентифікатор ресурсів). IRI, по суті, те ж саме, що URI, але IRI дозволяють використовувати символи, що не входять в ASCII.

Консорціум WHATWG пізніше створив свою власну специфікацію URL, в основному, звівши разом формати та ідеї від URI і IRI з сильним акцентом на браузери (що не дивно). Одна з оголошених ними цілей — «Модернізувати RFC 3986 і RFC 3987 у відповідності з сучасними реалізаціями і поступово вивести їх з ужитку». Вони хочуть повернутися до використання терміна «URL», справедливо заявляючи, що терміни URI і IRI просто заплутують ситуацію, і що люди так і не зрозуміли їх (або часто навіть не знають, що ці терміни існують).

Специфікація WHATWG написана в дусі старої доброї мантри браузерів: бути як можна більш ліберальними з користувачами, завжди намагатися вгадати, що вони мають на увазі, і вивертатися навиворіт, намагаючись зробити це. Хоча при цьому ми всі знаємо, що закон Постела — не найкращий підхід до справи. На ділі це означає, що специфікація дозволяє використовувати URL занадто багато слэшей, пробіли і символи, що не входять в ASCII.

З моєї точки зору, таку специфікацію також дуже важко читати і дотримуватись, оскільки вона не дуже докладно описує синтаксис або формат, але при цьому нав'язує обов'язковий алгоритм парсингу. Щоб перевірити моє твердження: подивіться, що це специфікація говорить про кінцевій точці після імені хоста в URL.

Крім того, до всіх цих стандартів і специфікацій, в інтерфейсі всіх браузерів є адресна рядок (яку часто називають і по-іншому), яка дозволяє користувачам вводити будь-які кумедні рядки і перетворює їх в URL. Якщо ввести "
http://localhost/%41
" в адресний рядок, то ділянка з відсотком буде перетворений в «A» (оскільки 41 в шістнадцятковому обчисленні є заголовною буквою A в ASCII), але якщо ввести "
http://localhost/A A
", то фактично у вихідний HTTP-запит GET буде відправлено "
/A%20A
" (з пропуском в URL-кодування). Я кажу про це, так як люди часто думають, що все, що можна ввести в рядок — і є URL.

Зазначене вище — в основному моє (спотворене) уявлення, з якими специфікацій і стандартів нам поки що доводиться працювати. Тепер давайте додамо реальності і подивимося, які проблеми ми отримуємо, коли мій URL — це не ваш URL.

Так що ж таке URL?

Або, більш конкретно — як ми пишемо їх? Який синтаксис використовуємо?

Думаю, одна з найбільших помилок у специфікації WHATWG (і в ній причина, чому я виступаю проти цієї специфікації в її поточної формі з твердим переконанням, що вони неправі) полягає в тому, що вони вважають, ніби тільки їм дозволено працювати з URL і давати їм визначення; вони обмежують своє уявлення про URL виключно браузерами, HTML і адресними рядками. Звичайно, WHATWG створений великими компаніями, що представляють браузери, які використовують майже кожен, а в цих браузерах широко працюють покажчики URL, але самі URL — явище значно більше.

Уявлення про URL, існуюче у WHATWG, не надто широко приймається за межами браузерів.

Двокрапка-слеш-слеш

Якщо запитати користувачів — пересічних людей без будь-якого особливого знання протоколів або мережі — про те, що таке URL, то що вони скажуть? Послідовність "://" (двокрапка-слеш-слеш) була би на початку списку відповідей; кілька років тому, коли браузери показували URL більш повно, це було б ще помітніше. Побачивши цю послідовність, ми відразу розуміємо, що перед нами саме URL.

Однак давайте відійдемо від користувачів і озирнімося — у світі існують поштові клієнти, емулятори терміналів, текстові редактори, Perl скрипти та багато-багато іншого, що здатне розпізнавати URL і працювати з ними. Наприклад, " відкрити URL в браузері, перетворити в активне посилання у створеному HTML і так далі. Величезна кількість названих скриптів і програм буде використовувати саме послідовність «двокрапка-слеш-слеш» як головна ознака.

Специфікація WHATWG говорить, що повинен бути як мінімум один слеш і що парсер при цьому зобов'язаний приймати яке завгодно кількість слэшей. Це означає, що "
http:/example.com
" і "
http:///////////////example.com
" — повністю підходящі варіанти. RFC 3986 і багато хто інші з цим не згодні. Ну, дійсно, більшість людей, з якими я сперечався останні кілька днів, навіть ті, хто працює в інтернеті, говорить, думає і переконане, що URL має два слеша. Просто подивіться уважніше на скріншот результату пошуку картинок в Гуглі за запитом «URL» вище в цій статті.

Ми просто знаємо, що в URL є два слеша (хоча, так, URL типу file: зазвичай мають три слеша, але давайте поки проігноруємо це). Не один. Не три. Два. Але WHATWG з цим не згоден.

«Є хоч одна справжня причина приймати більше двох слэшей для не-файлових URL?» (питаю я роздратовано у членів WHATWG)

"Факт в тому, що це роблять всі браузери."

Специфікація говорить це, тому що браузери реалізували її саме так.

Ніяке краще пояснення не було дано навіть після того, як я вказав, що це твердження неправильне і далеко не всі браузери роблять так. Можливо, ця гілка обговорення здасться вам дуже пізнавальною.

У проекті Curl ми якраз недавно почали обговорювати, як поводитися з покажчиками URL, які мають число слэшей, відмінне від двох, тому що, виявляється, вже є сервери, що передають назад URL заголовку «Location:», і деякі браузери без заперечень приймають їх. Curl — ні, так само як і більшість з безлічі інших бібліотек та інструментів командного рядка. Кого нам підтримати?

Прогалини

Символ пробілу (код 32 в ASCII, шістнадцятковий код 0x20) не може бути частиною URL. Якщо потрібно відправити його, то використовувати URL-кодування, як це роблять з будь-яким іншим неприпустимим символом, який треба зробити частиною URL. URL-кодування — це байтове значення в шістнадцятковому обчисленні зі знаком відсотка перед ним. Таким чином, "%20" означає пробіл. Це також означає, що синтаксичний аналізатор, наприклад, скануючий текст на предмет покажчиків URL, дізнається, що досяг кінця URL, коли він виявляє неприпустимий символ. Наприклад, пробіл.

Браузери зазвичай перетворюють усе %20 у своїх адресних рядках символ пробілу, щоб посилання виглядали пристойно. При копіюванні адреси в буфер обміну і вставити його в текстовий редактор ми бачимо пробіли %20, що і потрібно.

Я не впевнений, чи в цьому причина, але браузери також беруть прогалини як частина URL, отримуючи, наприклад, переадресацію HTTP-відповіді. URL передаються від сервера до клієнта в заголовку «Location:». Браузери без проблем допускають пропуски в них URL, кодуючи їх у вигляді %20 і відправляючи наступний запит. Це змушує curl приймати прогалини в перенаправляемых «URL».

Не-ASCII

Підтримка URL мов, включають символи, що не входять в ASCII, звичайно, важливо, особливо для незахідних спільнот, і я згоден, що специфікація IRI ніколи не була достатньо хороша. Особисто Я далеко не експерт в інтернаціоналізації, тому я керуюся тим, що чув від інших. Але, звичайно, користувачі нелатинських алфавітів і систем друку повинні мати можливість записувати свої «інтернет-адреси» ресурси і використовувати їх як посилання.

В ідеальному випадку у нас була б интернационализированная версія для показу користувачеві, і версія в кодуванні ASCII для внутрішнього використання в мережних запитах.

Для міжнародних доменних імен ім'я перетворюється в кодування punycode так, щоб воно могло бути прочитане звичайними серерами DNS, які нічого не знають про імена в кодуванні, відмінної від ASCII. Ідентифікатори URI не мають IDN-імен; IRI та URL за версією WHATWG — мають. Сurl підтримує IDN-імена хостів.

WHATWG заявляє, що URL можуть використовувати UTF-8, тоді як URI — тільки ASCII. Curl не сприймає не-ASCII-символи в частині адреси, задає шлях, але кодує їх відсотком у вихідних запитах; це породжує “цікаві" побічні ефекти, коли не-ASCII-символи представлені в коді, відмінному від UTF-8, що є, наприклад, стандартним для Windows.

Подібно до того, що я написав вище, це призводить до серверів, відправляв назад не-ASCII-коди в HTTP заголовках, які браузери охоче приймають, і не-браузерам теж доводиться працювати з ними.

Стандарту URL не існує

Я не намагався представити повний список проблем або невідповідностей — тут просто деяка добірка труднощів, з якими я недавно зіткнувся. «URL», виданий в одному місці, звичайно, зовсім необов'язково буде прийнятий або зрозумілий в іншому місці як «URL».

У наші дні навіть curl вже не слід строго жодної опублікованої специфікації — ми повільно деградуємо в догоду «веб-сумісності».

Єдиний стандарт URL немає, і яка-небудь робота в цьому напрямку не ведеться. Я не можу вважати, що WHATWG докладає справжні зусилля до цього, оскільки вона пише специфікацію закритою групою без серйозних спроб залучити більш широке співтовариство.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.