Inspector de codare procentuală

Codificarea procentuală nu este o singură regulă, ci mai multe, iar ele nu sunt de acord la vreo duzină de caractere. Pagina trece același text prin encodeURIComponent, encodeURI și serializarea application/x-www-form-urlencoded, alăturat, marchează caracterele la care nu sunt de acord, afișează câte un rând pentru fiecare caracter cu octeții săi UTF-8 și cu clasa sa RFC 3986 și spune de câte ori a fost codificat un șir. Partea de decodare citește un șir după o regulă strictă sau permisivă și spune ce escape este stricat și unde, în loc să returneze în liniște un rezultat greșit.
Toate prelucrările au loc local, în browser — datele nu se încarcă pe niciun server.

Ce este codificarea procentuală? Codificarea procentuală explicată în termeni simpli — ce este, de ce un spațiu devine %20 sau +, și ce înseamnă când un URL arată %25.
Ce face aceasta:
Cum se citesc escape-urile:
encodeURIComponent
encodeURI
formular (application/x-www-form-urlencoded)
Ctrl+Enter în intrare rulează modul activ.
Se alege un mod și se face clic pe butonul de acțiune. Codificare & inspecție arată cele trei codificări ale textului plus câte un rând pentru fiecare caracter; Decodare citește escape-urile înapoi și numără straturile. Butonul Autotest reia fiecare exemplu documentat, fiecare caracter ASCII tipăribil și lanțurile de straturi înregistrate în fișierul de date al paginii, și raportează aici numărul.
Unde nu sunt de acord codificatoarele:doar caracterele de mai jos sunt tratate diferit de cele trei metode. Restul trec prin toate trei neschimbate sau sunt escapate identic de toate trei.
Fiecare caracter, câte un rând:octeții UTF-8 în care se transformă un caracter, clasa în care îl plasează RFC 3986 și escape-ul pe care îl scrie fiecare context. Cele patru coloane de context sunt mulțimile de codificare procentuală WHATWG, pe care le folosește un browser la construirea unei căi, a unei interogări sau a unui fragment; un rând umbrit este un caracter pe care cele trei codificatoare îl tratează diferit.
Mulțimea exactă pe care o escapează această pagină pentru fiecare parte a unui URL:tipărit direct din codificatorul însuși, deci acest tabel și codul care completează coloanele de mai sus nu pot devia unul de celălalt. Fiecare mulțime escapează, de asemenea, caracterele de control C0 (U+0000 până la U+001F) și fiecare punct de cod peste U+007E, motiv pentru care textul non-ASCII este mereu escapat în fiecare context.
Aceste mulțimi derivă din mulțimile de codificare procentuală WHATWG și diferă de ele în două locuri deliberate, care fac asamblarea manuală sigură: un hash este escapat în interogare, deoarece unul brut ar începe fragmentul; iar mulțimea componentei este fixată exact la caracterele pe care le escapează encodeURIComponent, apostrof inclus, în timp ce mulțimea de formular este fixată la ce escapează URLSearchParams. Cele două coloane din tabelul de mai sus sunt deci comportamentul propriu al platformei, nu o reimplementare a lui. Aceeași listă explică un rezultat pe care oamenii îl găsesc surprinzător: semnul procentual este escapat de encodeURIComponent și de encodeURI, dar nu se află în niciuna dintre mulțimile de context WHATWG, deci coloanele cale, interogare și fragment din tabelul pe caractere îl lasă neatins. Un semn procentual brut într-un URL asamblat manual rămâne un risc, pentru că standardul presupune că intrarea a fost validată mai întâi: %41 dintr-o interogare înseamnă un singur A pentru multe framework-uri de server, iar citirea strictă a acestei pagini tratează un % singur ca escape stricat. Escaparea lui manuală ca %25 este obiceiul mai sigur, iar tabelul pe caractere arată ambele forme alăturat.
De câte ori a fost codificat acest șir:fiecare rundă de decodare este un strat. O valoare codificată de două ori începe cu%25unde o singură codificare ar lăsa%20, iar o valoare codificată de trei ori începe cu%2525.
Caracterele pe care le poate purta un URL așa cum sunt:RFC 3986 împarte domeniul ASCII în trei grupuri, iar regulile de escape au sens doar în raport cu această împărțire.
Caracterele rezervate nu sunt interzise, ci ocupate: înseamnă ceva pentru analizorul URL. Regula care rezultă din listă este scurtă — dacă un caracter este rezervat și îl vrei ca date, îl escapezi; dacă este nerezervat, nu ai nevoie niciodată de escape pentru el.
Cele trei metode și ce lasă fiecare neatins:
Listele sunt mulțimile exacte pe care fiecare metodă le lasă neescapate în domeniul ASCII; Autotestul verifică fiecare caracter ASCII tipăribil față de ele, deci tabelul nu poate devia de la codificatoarele pe care le descrie.
Cât de mare intrare acceptă această pagină și de ce:Codificarea procentuală este o singură trecere peste text, deci spre deosebire de convertoarele de baze radix de pe acest site, costul crește liniar, nu pătratic: nu există o lungime la care aritmetica însăși să devină problema. Limitele de mai jos există pentru că tabelul pe caractere este desenat în document, iar un tabel cu un milion de rânduri este exact ceea ce oprește de fapt un browser.
Ce este codificarea procentuală?

Codificarea procentuală — numită și codificare URL, iar în documentele mai vechi escapare — este regula care permite unui URL să poarte caractere pe care nu are voie să le conțină. Un escape procentual are trei caractere ASCII: un semn procentual și două cifre hexazecimale, care reprezintă un octet. %20 este octetul 0x20, adică un spațiu. %2F este octetul 0x2F, adică o bară oblică. Nimic altceva nu intervine: escape-ul numește un octet, nu un caracter.

Pentru că numește octeți, textul trebuie transformat mai întâi în octeți, iar codificarea octeților este UTF-8. De aici vin escape-urile lungi: un caracter chinezesc are trei octeți UTF-8 și deci trei escape-uri, iar un emoji are patru octeți și douăsprezece caractere ASCII.

Versiunea de 30 de secunde: un spațiu este %20 ca valoare de URL, dar + în datele de formular; # este %23; un semn procentual literal este %25. Cele trei codificatoare de pe pagină sunt de acord asupra literelor, cifrelor și -_., și nu sunt de acord la vreo duzină de semne de punctuație, printre care tilda — tocmai de aceea encodeURIComponent și encodeURI produc șiruri diferite pentru același text, iar folosirea funcției greșite dintre cele două poate împărți o valoare în doi parametri de interogare.
De ce are nevoie un URL de ea

Un URI este definit ca o succesiune de caractere ASCII (RFC 3986 secțiunea 2.1), iar în interiorul acestui domeniu ASCII unele caractere sunt rezervate: sunt semnele de punctuație care dau structura URL-ului. Două puncte și două bare oblice separă schema, un semn @ separă informația de utilizator de gazdă, un semn de întrebare începe interogarea, un diez începe fragmentul, un ampersand separă parametrii de interogare, iar un semn procentual introduce un escape.

Asta creează o problemă și o portiță. Problema: o valoare care conține ea însăși unul dintre aceste caractere — un câmp de căutare cu "a&b", un nume de fișier cu o bară oblică, o parolă cu două puncte — ar schimba altfel structura URL-ului în care călătorește. Portița: chiar semnul procentual, astfel încât codificatorul își poate extinde propriul alfabet. % se scrie ca %25, iar cele două cifre hexazecimale de după el sunt caractere nerezervate obișnuite.

Exemple lucrate

Acestea sunt rezultatele exacte ale celor trei codificatoare pe care le rulează pagina, pentru intrări alese pentru că se comportă diferit unele de altele. Pagina le recalculează în fața utilizatorului, iar Autotestul reverifică fiecare rând față de implementările proprii ale platformei.

Cele trei metode și când este potrivită fiecare

Scurta versiune care previne majoritatea erorilor: orice intră într-o singură valoare de parametru trece prin encodeURIComponent (sau printr-un serializator de formular, care face aceeași treabă cu o mulțime sigură diferită), iar un URL complet deja asamblat trece prin encodeURI dacă are nevoie deloc de escapare. Alegerea funcției greșite dintre cele două este cea mai frecventă greșeală de codificare procentuală din codul web.

Caracterele pe care le poate purta un URL, complet
Două semne plus, două sensuri

Spațiul este singurul caracter a cărui codificare depinde de locul în care merge textul, iar semnul plus este motivul.

Capcana stă chiar în mijlocul acelui tabel. În datele de formular, un semn plus înseamnă spațiu, deci o valoare care conține cu adevărat un semn plus — un număr de telefon scris +44 20 7946 0958, o expresie aritmetică, o adresă de e-mail cu etichetă plus — trebuie să călătorească ca %2B. Dacă călătorește ca semn plus literal, receptorul o citește ca spațiu, iar +44 ajunge ca " 44".

Codificat de două ori și cum se recunoaște

O dublă codificare apare când un șir este deja escapat și apoi este escapat din nou. Semnul procentual al primului escape este un caracter ca oricare altul, deci devine %25, iar stratul de dedesubt supraviețuiește ca text vizibil.

Recunoașterea este o chestiune de numărare: se decodează șirul o dată și se verifică rezultatul. Dacă mai conține escape-uri care par intenționate — un %XX valid sau un semn plus de formular acolo unde se așteaptă un spațiu — mai există un strat. Dacă conține %25 urmat de două cifre hexazecimale, următorul strat este cu siguranță un escape.

Două note practice. Întâi, decodarea de două ori nu este inofensivă: este o cale cunoscută prin care un filtru de securitate și codul din spatele lui ajung să vadă șiruri diferite, deci un filtru care rulează înaintea unei a doua decodări filtrează textul greșit. Apoi, numărul de straturi de aici este o proprietate a șirului, nu o promisiune despre intenție: o valoare legitimă poate avea un singur strat, iar una stricată poate avea două.

Greșelile pentru care este construită această pagină
  • O valoare codificată cu encodeURI. Separatorii rămân neatinși, deci o valoare care conține & sau = se împarte în mai mulți parametri de cealaltă parte. Se compară cele două coloane de sus ale acestei pagini pentru intrarea a&b=c: coloana componentă escapează ambele caractere, coloana encodeURI le păstrează.
  • Un semn plus trimis ca date de formular. Ajunge ca spațiu. Se folosește %2B.
  • O valoare escapată de două ori „pentru siguranță”. Nu este mai sigură. Receptorul decodează o dată și primește un șir care mai conține escape-uri procentuale, adică aceeași eroare ca un set de caractere greșit, cu un strat mai jos.
  • Decodarea a ceva ce nu a fost niciodată codificat. Un semn procentual literal în text — 100% sure — nu este un escape. Într-o citire strictă este unul stricat, în poziția raportată de pagină; într-o citire permisivă supraviețuiește, de aceea permisivă este implicită aici și nu invers.
  • Presupunerea că escape-ul trebuie scris cu majuscule. Decodarea tratează %2f și %2F ca același octet, iar ambele sunt valide. Majusculele sunt doar forma canonică recomandată de RFC 3986 și cea pe care o produc celelalte unelte.
  • Presupunerea că codificarea procentuală face textul sigur. Îl face fără ambiguitate într-un URL. Nu oprește injectarea, nu este criptare și nu este un sanitizator: escaparea trebuie să fie ultimul pas înainte de asamblare, pentru contextul în care intră textul.
Răspunsuri rapide

„Un semn plus este spațiu într-un URL?”

Doar în datele de formular și doar în partea de interogare a unei trimiteri de formular. Într-o cale, într-un fragment și în interogarea unui link obișnuit, un semn plus este un semn plus literal. De aceea pagina are un comutator pentru el, în loc să ghicească.

„De ce linkul arată %25?”

Pentru că ceva a codificat un semn procentual. Fie un semn procentual literal a trecut printr-un codificator — 100% sure devine 100%25%20sure — fie un șir care conținea deja un escape a fost codificat a doua oară. Se decodează șirul o dată și se verifică ce iese: dacă rezultatul mai conține %XX, există încă un strat.

„Contează dacă o bară oblică dintr-o valoare de interogare este %2F sau /?”

Pentru analizorul de URL, nu: ambele ajung la server ca bară oblică, iar mulțimea WHATWG pentru interogare lasă o bară oblică neatinsă. Pentru interoperabilitate, uneori da: multe framework-uri de server rulează propria decodare peste un șir de interogare brut, iar unele dintre ele nu sunt de acord asupra caracterelor care nu au fost niciodată escapate. Când o valoare este asamblată manual, în loc de un serializator, escaparea explicită a caracterelor rezervate este obiceiul mai sigur.

„De ce coloana formularului escapează o tildă pe care celelalte două o lasă neatinsă?”

Pentru că mulțimea sigură a codificatorului de formular este mai restrânsă: doar litere, cifre și -_.*. Codificatorul de formular WHATWG escapează ~ ! ' ( ), deși RFC 3986 listează ~ ca nerezervat. Ambele forme se decodează la aceeași valoare; diferența contează doar când șirurile se compară octet cu octet.

„Pot apărea aceleași caractere neescapate în bara de adrese a browserului?”

Da, și acesta este ce se vede în bara de adrese, nu URL-ul. Browserele afișează o formă citibilă a unui URL și o codifică la trimitere, deci 中文 dintr-un link devine %E4%B8%AD%E6%96%87 pe cablu. Copiind URL-ul din bara de adrese se poate obține oricare dintre forme, în funcție de browser.

„Fiecare escape de aici pare valid, dar caracterul care iese nu este cel așteptat. De ce?”

În spatele expresiei „s-a decodat greșit” se ascund două defecțiuni diferite, pe care pagina le raportează diferit. Prima este un escape stricat: un semn procentual nu urmat de două cifre hexazecimale, precum un 100% la final sau un %zz. Aceasta este o problemă de sintaxă; citirea strictă o refuză și spune unde se află, iar citirea permisivă o păstrează ca text literal și o listează. A doua este un escape al cărui octet este perfect legal, dar ai cărui octeți nu alcătuiesc un caracter UTF-8 valid, ca %FF singur sau un caracter din trei octeți tăiat scurt ca %E4%B8. Aceasta nu este o problemă de sintaxă, deci ambele citiri returnează textul, înlocuiesc octeții care nu pot fi decodate cu caracterul de înlocuire U+FFFD („�”) și listează un avertisment care o spune. Acest avertisment este partea utilă: textul care sosește cu caractere de înlocuire înseamnă de obicei că expeditorul a folosit un alt set de caractere sau că șirul a fost escapat o dată în plus. Codificarea procentuală numește octeți, iar această pagină, ca standardul URL, citește mereu acești octeți ca UTF-8.

„Ce nu face această pagină?”

Nu desparte un URL în schemă, gazdă, cale și interogare — pentru asta există Analizorul URL. Nu verifică dacă un link poate fi deschis în siguranță, nu contactează nimic și nu ghicește setul de caractere al octeților din spatele unui escape: îi citește mereu ca UTF-8, cum cere standardul URL.

„Ce variantă de rezervă îi trebuie decodării și de unde se știe că este corectă?”

Se apasă Autotest. Compară codificatoarele paginii cu encodeURIComponent, encodeURI și URLSearchParams ale platformei, pentru fiecare caracter ASCII tipăribil, reia fiecare exemplu din tabelele de mai sus, reverifică lanțurile de straturi înregistrate și raportează aici numărul verificărilor.

Standarde și domeniu

Codificarea procentuală este specificată în RFC 3986 secțiunea 2.1, cu definiția caracterelor rezervate și nerezervate în secțiunile 2.2 și 2.3 și regula privind majusculele în secțiunea 6.2.2.1. Mulțimile pe care le folosește efectiv un browser la construirea unui URL sunt în Standardul URL WHATWG, care le împarte după context: una pentru fragment, una pentru interogare, una pentru interogare specială, una pentru cale, una pentru informația de utilizator și cea mai restrânsă, folosită pentru o singură componentă. Trimiterea formularelor, inclusiv semnul plus, este în Standardul HTML la application/x-www-form-urlencoded. Cele două funcții encodeURI și encodeURIComponent fac parte din ECMAScript însuși.

Pagina completează coloanele pentru cale, interogare și fragment din propriile sale mulțimi pe context și afișează lista exactă pentru fiecare context lângă rezultat. Aceste mulțimi derivă din cele WHATWG și diferă de ele în două locuri deliberate: un hash este escapat în interogare, deoarece un hash brut ar începe fragmentul, iar mulțimea componentei este fixată exact la caracterele pe care le escapează encodeURIComponent. Acolo unde o funcție a platformei este definiția răspunsului — encodeURIComponent, encodeURI și serializarea de formular — funcția este apelată direct, deci acele coloane sunt comportamentul propriu al browserului, nu o reimplementare a lui.

Textul paginii a fost scris pentru acest site. Fiecare valoare din tabelele de mai sus este produsă de codul paginii la încărcare și a fost verificată față de implementările platformei prin uneltele de test ale acestui site; Autotestul repetă comparația în browser.