Inspektør for prosentkoding

Prosentkoding er ikke én regel, men flere, og de er uenige om et dusin tegn. Denne siden kjører den samme teksten gjennom encodeURIComponent, encodeURI og application/x-www-form-urlencoded-serialiseringen side om side, markerer tegnene der de er uenige, skriver en rad per tegn med UTF-8-bytene og RFC 3986-klassen, og sier hvor mange ganger en streng er kodet. Dekodingssiden leser en streng med en streng eller en tolerant regel og sier hvilken escape som er ødelagt og hvor, i stedet for å gi tilbake et stille feil resultat.
All behandling skjer lokalt i nettleseren — data lastes aldri opp til noen server.

Usikker på hva prosentkoding er? Prosentkoding forklart på enkelt språk — hva det er, hvorfor et mellomrom blir %20 eller +, og hva det betyr når en URL viser %25.
Hva dette gjør:
Slik leses escapene:
encodeURIComponent
encodeURI
skjema (application/x-www-form-urlencoded)
Ctrl+Enter i inndataen kjører den aktive modusen.
Velg en modus og klikk handlingsknappen. Koding og inspeksjon viser de tre kodingene av teksten pluss en rad per tegn; Dekoding leser escapene tilbake og teller lagene. Selvtest-knappen kjører på nytt hvert dokumentert eksempel, hvert utskrivbare ASCII-tegn og lagkjedene som er registrert i denne sidens datafil, og rapporterer antallet her.
Der koderne er uenige:bare tegnene nedenfor behandles ulikt av de tre metodene. Alt annet går gjennom alle tre uendret, eller escapes likt av alle tre.
Hvert tegn, én rad hver:UTF-8-bytene et tegn blir til, klassen RFC 3986 setter det i, og escapen hver kontekst skriver. De fire kontekstkolonnene er WHATWG-prosentkodingssettene, som er det en nettleser bruker når den bygger en sti, en søkestreng eller et fragment; en skravert rad er et tegn de tre koderne behandler ulikt.
Det nøyaktige settet denne siden escaper for hver del av en URL:skrevet ut fra koderen selv, slik at denne tabellen og koden som fyller kolonnene over ikke kan drive fra hverandre. Hvert sett escaper også C0-kontrolltegnene (U+0000 til U+001F) og hvert kodepunkt over U+007E, og det er derfor ikke-ASCII-tekst alltid escapes i hver kontekst.
Disse settene er avledet fra WHATWG-prosentkodingssettene og avviker fra dem på to bevisste punkter, som begge gjør håndsammensetning trygg: en hash escapes inne i en søkestreng, fordi en rå hash ville starte fragmentet; og komponentsettet er festet til nøyaktig de tegnene encodeURIComponent escaper, apostrof og alt, mens skjemasettet er festet til det URLSearchParams escaper. De to kolonnene i tabellen over er derfor plattformens egen oppførsel og ikke en reimplementering av den. Den listen forklarer også et resultat folk ofte finner overraskende: et prosenttegn escapes av encodeURIComponent og av encodeURI, men det står i ingen av WHATWG-kontekstsettene, så sti-, søkestreng- og fragmentkolonnene i tabellen per tegn lar det være. Et rått prosenttegn i en URL man har satt sammen for hånd er fortsatt en risiko, fordi standarden forventer at innsatsen er validert først: %41 inne i en søkestreng er én enkelt A for mange serverrammeverk, og denne sidens egen strenge lesing behandler et alene stående % som en ødelagt escape. Å escape det selv som %25 er den tryggere vanen, og tabellen per tegn viser begge skrivemåtene side om side.
Hvor mange ganger denne strengen er kodet:hver runde med dekoding er ett lag. En verdi som er kodet to ganger starter med%25der en enkelt koding ville etterlatt%20, og en verdi som er kodet tre ganger starter med%2525.
Tegnene en URL kan bære som de er:RFC 3986 deler ASCII-området i tre grupper, og escaperegelene gir bare mening mot den inndelingen.
De reserverte tegnene er ikke forbudt, de er tatt: de betyr noe for URL-parseren. Regelen som følger av listen er kort — hvis et tegn er reservert og man mener det som data, escap det; er det uforbeholdent, trenger man aldri det.
De tre metodene, og hva hver lar være:
Listene er de nøyaktige settene hver metode lar være uescapet i ASCII-området; Selvtesten sjekker hvert utskrivbare ASCII-tegn mot dem, så tabellen kan ikke drive bort fra koderne den beskriver.
Hvor stor inndata denne siden godtar, og hvorfor:prosentkoding er ett pass over teksten, så i motsetning til radixkonverterere på dette nettstedet vokser kostnaden lineært og ikke kvadratisk: det finnes ingen lengde der regnestykket i seg selv blir problemet. Grensene nedenfor finnes fordi tabellen per tegn tegnes i dokumentet, og en tabell med en million rader er det som faktisk stopper en nettleser.
Hva er prosentkoding?

Prosentkoding — også kalt URL-koding, og i eldre dokumenter escaping — er regelen som lar en URL bære tegn den ikke har lov til å inneholde. En prosentescape er tre ASCII-tegn: et prosenttegn og to heksadesimale sifre, som står for én byte. %20 er byten 0x20, som er et mellomrom. %2F er byten 0x2F, som er en skråstrek. Ingenting annet er involvert: escapen navngir en byte, ikke et tegn.

Fordi det navngir byte, må teksten først gjøres om til byte, og byte-kodingen er UTF-8. Der kommer de lange escapene fra: ett kinesisk tegn er tre UTF-8-byte og dermed tre escapes, og én emoji er fire byte og tolv ASCII-tegn.

Versjonen på 30 sekunder: et mellomrom er %20 som URL-verdi, men + i skjemadata; # er %23; et bokstavelig prosenttegn er %25. De tre kodingene på denne siden er enige om bokstavene, sifrene og -_., og er uenige om et dusin tegnsettingstegn, tildelingen av tilde blant dem — og det er nettopp derfor encodeURIComponent og encodeURI gir ulike strenger for samme tekst, og hvorfor den feile av de to kan dele en verdi i to søkeparametere.
Hvorfor en URL trenger det i det hele tatt

En URI er definert som en sekvens av ASCII-tegn (RFC 3986 avsnitt 2.1), og innenfor det ASCII-området er noen tegn reserverte: de er tegnsettingen som gir URL-en struktur. Et kolon og to skråstreker skiller skjemaet, et at-tegn skiller brukerinformasjonen fra verten, et spørsmålstegn starter søkestrengen, en hash starter fragmentet, et og-tegn skiller søkeparametere, og et prosenttegn innleder en escape.

Det skaper ett problem og ett smutthull. Problemet: en verdi som selv inneholder ett av disse tegnene — en søkeboks med «a&b», et filnavn med en skråstrek, et passord med et kolon — ville ellers endre strukturen på URL-en den reiser i. Smutthullet: prosenttegnet selv, så koderen kan ganske enkelt utvide sitt eget alfabet. % skrives som %25, og de to heksadesimale sifrene etter det er vanlige uforbeholdne tegn.

Utarbeidede eksempler

Dette er de nøyaktige utdataene fra de tre koderne denne siden kjører, på inndata valgt fordi de oppfører seg ulikt hverandre. Siden beregner dem på nytt foran brukeren, og Selvtesten kontrollerer hver rad mot plattformens egne implementasjoner.

De tre metodene, og når hver er riktig

Den korte versjonen som sparer de fleste feilene: alt som går inn i en enkelt parameterverdi går gjennom encodeURIComponent (eller gjennom en skjemaserialiserer, som gjør samme jobb med et annet sikkert sett), og en ferdig sammensatt URL går gjennom encodeURI hvis den i det hele tatt trenger escaping. Å ta den feile av disse to er den vanligste prosentkodingsfeilen i webkode.

Tegnene en URL kan bære, fullstendig
To plusstegn, to betydninger

Et mellomrom er det ene tegnet hvis koding avhenger av hvor teksten skal, og plusstegnet er grunnen til det.

Fellen ligger midt i den tabellen. I skjemadata betyr et plusstegn et mellomrom, så en verdi som virkelig inneholder et plusstegn — et telefonnummer skrevet som +44 20 7946 0958, et aritmetisk uttrykk, en e-postadresse med en plusstagg — må reise som %2B. Hvis den reiser som et bokstavelig plusstegn, leser mottakeren den tilbake som et mellomrom, og +44 kommer frem som « 44».

Kodet to ganger, og hvordan det gjenkjennes

Dobbel koding skjer når en streng allerede er escapet og deretter escapes igjen. Prosenttegnet i den første escapen er et tegn som alle andre, så det blir %25, og laget under det overlever som synlig tekst.

Å gjenkjenne det er et spørsmål om å telle: dekod strengen én gang og se på resultatet. Hvis det fortsatt inneholder escapes som ser bevisste ut — en gyldig %XX eller et skjema-plusstegn der et mellomrom forventes — er det et lag til. Hvis det inneholder %25 etterfulgt av to heksadesimale sifre, er neste lag helt sikkert en escape.

To praktiske merknader. For det første er ikke dekoding to ganger uskadelig: det er en velkjent måte å få et sikkerhetsfilter og koden bak det til å se ulike strenger, så et filter som kjører før en andre dekoding filtrerer feil tekst. For det andre er lagtallet her en egenskap ved strengen, ikke et løfte om hensikt: en legitim verdi kan være ett lag dyp, og en ødelagt kan være to.

Feilene denne siden er bygget for å fange
  • En verdi kodet med encodeURI. Skilletegnene overlever, så en verdi som inneholder & eller = deles i flere parametere på den andre siden. Sammenlign de to kolonnene øverst på denne siden med inndataene a&b=c: komponentkolonnen escaper begge tegnene, encodeURI-kolonnen beholder dem.
  • Et bokstavelig plusstegn sendt som skjemadata. Det kommer frem som et mellomrom. Bruk %2B.
  • En verdi escapet to ganger «for sikkerhets skyld». Det er ikke tryggere. Mottakeren dekoder én gang og får en streng som fortsatt inneholder prosentescapes, som er den samme feilen som et feil tegnsett, bare ett lag lenger ned.
  • Å dekode noe som aldri ble kodet. Et bokstavelig prosenttegn i tekst — 100% sure — er ikke en escape. I en streng lesing er det en ødelagt en, på posisjonen denne siden rapporterer; i en tolerant lesing overlever det, og det er derfor tolerant er standarden her og ikke omvendt.
  • Å anta at escapen må være med store bokstaver. Dekoding behandler %2f og %2F som samme byte, og begge er gyldige. Store bokstaver er bare den kanoniske skrivemåten RFC 3986 anbefaler, og den andre verktøy vil produsere.
  • Å anta at prosentkoding gjør tekst trygg. Den gjør tekst entydig inne i en URL. Den stopper ikke injeksjon, den er ikke kryptering, og den er ikke en sanitizer: escapingen må være siste steg før sammensetning, for konteksten teksten skal inn i.
Raske svar

“Er et plusstegn et mellomrom i en URL?”

Bare i skjemadata, og bare i søkedelen av en skjemainnsending. I en sti, i et fragment og i søkestrengen til en vanlig lenke er et plusstegn et bokstavelig plusstegn. Derfor har denne siden en bryter for det i stedet for å gjette.

“Hvorfor viser lenken min %25?”

Fordi noe kodet et prosenttegn. Enten gikk et bokstavelig prosenttegn gjennom en koder — 100% sure blir 100%25%20sure — eller en streng som allerede inneholdt en escape ble kodet en gang til. Dekod strengen én gang og se hva som kommer tilbake: hvis resultatet fortsatt inneholder %XX, er det et lag til.

“Har det noe å si om en skråstrek inne i en søkeverdi er %2F eller /?”

For URL-parseren, nei: begge når serveren som en skråstrek, og WHATWG-søkesettet lar en skråstrek være. For interoperabilitet, noen ganger ja: mange serverrammeverk kjører egen dekoding over en rå søkestreng, og noen av dem er uenige om tegn som aldri ble escapet. Når en verdi settes sammen for hånd i stedet for av en serialiserer, er det den tryggere vanen å escape de reserverte tegnene eksplisitt.

“Hvorfor escaper skjemakolonnen en tilde som de to andre lar være?”

Fordi skjemakoderens sikre sett er smalere: bare bokstaver, sifre og -_.*. WHATWG-skjemakoderen escaper ~ ! ' ( ) selv om RFC 3986 lister ~ som uforbeholden. Begge skrivemåtene dekodes til samme verdi; forskjellen betyr bare noe når man sammenligner strenger byte for byte.

“Kan de samme tegnene dukke opp uescapet i en nettleser-adresselinje?”

Ja, og det er adresselinjen, ikke URL-en. Nettlesere viser en lesbar form av en URL og koder den når den sendes, så 中文 i en lenke blir %E4%B8%AD%E6%96%87 på ledningen. Kopierer man URL-en fra adresselinjen, kan man få begge former avhengig av nettleseren.

“Hver escape her ser gyldig ut, men tegnet som kommer ut er ikke det jeg forventet. Hvorfor?”

Det er to ulike feil bak «det ble dekodet feil», og siden rapporterer dem ulikt. Den første er en ødelagt escape: et prosenttegn som ikke etterfølges av to heksadesimale sifre, som et avsluttende 100% eller en %zz. Det er et syntaksproblem, og den strenge lesingen avviser det og sier hvor det sitter, mens den tolerante lesingen beholder det som bokstavelig tekst og lister det. Den andre er en escape hvis byte er helt lovlig, men hvis byte ikke staver en gyldig UTF-8-tegn, som %FF alene eller et tre byte langt tegn kuttet som %E4%B8. Det er ikke et syntaksproblem, så begge lesingene returnerer teksten, erstatter byte som ikke kan dekodes med erstatningstegnet U+FFFD ("�"), og lister en advarsel som sier det. Den advarselen er det nyttige: tekst som kommer som erstatningstegn betyr vanligvis at avsenderen brukte et annet tegnsett, eller at strengen ble escapet én gang for mye. Prosentkoding navngir byte, og denne siden leser alltid disse byte som UTF-8, slik URL-standarden gjør.

“Hva gjør ikke denne siden?”

Den deler ikke en URL i skjema, vert, sti og søkestreng — det er det URL-parseren er til for. Den sjekker ikke om en lenke er trygg å åpne, den kontakter ingenting, og den gjetter ikke tegnsettet til byte bak en escape: den leser dem alltid som UTF-8, slik URL-standarden krever.

“Hvilken reserveløsning trenger dekoding, og hvordan vet jeg at den er riktig?”

Trykk Selvtest. Den sammenligner sidens egne kodere med plattformens encodeURIComponent, encodeURI og URLSearchParams for hvert utskrivbare ASCII-tegn, kjører hvert eksempel i tabellene over på nytt, sjekker de registrerte lagkjedene på nytt, og rapporterer antallet kontroller her.

Standarder og omfang

Prosentkoding er spesifisert i RFC 3986 avsnitt 2.1, med definisjonen av reserverte og uforbeholdne tegn i avsnitt 2.2 og 2.3 og skriveregelen i avsnitt 6.2.2.1. Settene en nettleser faktisk bruker når den bygger en URL, står i WHATWG URL-standarden, som deler dem etter kontekst: ett sett for et fragment, ett for en søkestreng, ett for en spesiell søkestreng, ett for en sti, ett for brukerinformasjon, og det smalere som brukes for en enkelt komponent. Skjemainnsending, inkludert plusstegnet, står i HTML-standarden under application/x-www-form-urlencoded. De to funksjonene encodeURI og encodeURIComponent er en del av selve ECMAScript.

Denne siden fyller sti-, søkestreng- og fragmentkolonnene fra sine egne sett per kontekst, og skriver ut den nøyaktige listen for hver kontekst ved siden av resultatet. Disse settene er avledet fra WHATWG-settene og avviker fra dem på to bevisste punkter: en hash escapes inne i en søkestreng, fordi en rå hash ville starte fragmentet, og komponentsettet er festet til nøyaktig de tegnene encodeURIComponent escaper. Der en plattformfunksjon er definisjonen av svaret — encodeURIComponent, encodeURI og skjemaserialiseringen — kalles den funksjonen direkte, så de kolonnene er nettleserens egen oppførsel og ikke en reimplementering av den.

Teksten på denne siden er skrevet for dette nettstedet. Hver verdi i tabellene over produseres av sidens egen kode når den lastes, og er kontrollert mot plattformens implementasjoner i dette nettstedets testverktøy; Selvtesten gjentar den sammenligningen i nettleseren.