Socket.IO/SockJS a kódování do UTF-8

tell me why

Socket.IO/SockJS a kódování do UTF-8
« kdy: 21. 08. 2014, 02:27:13 »
Socket.io/Engine.io a Sock.js jsou knihovny, kter umožňují realtime komunikaci na webu, zjednodušeně to programátorovi dává možnost navázat pomocí javascriptu spojení se serverem, které se bude tvářit, že má vlastnosti klasického tcp socketu. Interně se pak vybere ta nejlepší dostupná transportní vrstva (např. websockety).

Engine.io i Sock.js vlastní data před odesláním ještě zakódují.
Sock.js na datech (musí to být string, pokud není, vynutí se přes explicitní konverzi skrz výraz (''+data)) provede json encoding.
Engine.io data převádí na utf8 pomocí této knihovny https://github.com/mathiasbynens/utf8.js/


No na co se mi pořád nedaří přijít a nenašel jsem odpověď ani na netu (ani na SO nikdo asi neví):
Proč je nutné ty data kódovat do utf-8, wtf? Tomu vůbec nerozumím. Přece ajaxový požadavek je defaultně utf-8, takže
data se z js kódování ucs-2/utf-16 převedou na utf-8 a server je dostane jako utf-8.

Jediná věc, co mě nějak ještě napadá je, jestli není nějaký problém v tom, když je v meta tagu html stránky nastavéné nějaké jiné kódování než utf-8, že by to pak nešlo tím ajaxem poslat jako utf-8 (to by pak způsobovalo problémy při podpoře znaků, které nelze kódovat tím kódováním ve kterém je ta stránka).

Nemá někdo nějaké typy, proč se prostě nevezmou ty data co se mají odeslat a neodešlo se v té podobě v jaké jsou?
« Poslední změna: 21. 08. 2014, 10:16:14 od Petr Krčmář »


Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #1 kdy: 21. 08. 2014, 09:25:11 »
JavaScript v prohlížečích dlouho neuměl pracovat s binárními daty, takže nemá smysl mluvit o nějakém kódování textů v JavaScriptu. Jakým způsobem texty kóduje interpret je jeho interní věc, která kód v JavaScriptu nijak neovlivní. V JavaScriptu prostě pracujete s textem, posloupností Unicode znaků - a teprve pokud se má text převést na bajty (třeba pro HTTP), musí se převést podle nějakého kódování. A v takovém případě musíte kódování vždy uvést, nebo se použije nějaké výchozí kódování.
To, co dělá ta knihovna utf8.js, je podle mne nesmysl. Ona vezme Unicode znak, převede jej na posloupnost "bajtů" podle kódování UTF-8, vezme ASCII znaky odpovídající těm bajtům, a ty jako Unicode znaky zapíše do výstupního řetězce. Je to stejný postup, jako když máte soubor v UTF-8, a omylem jej necháte zkonvertovat z kódování ASCII do UTF-8. Takový soubor je pak také nutné dekódovat dvakrát.
Napadají mne dva možné důvody. Buď se tím snaží obejít chybu v nějakém prohlížeči, nebo byl autor pilný a rozhodl se, že ta data přece musí nějak kódovat a dekódovat. (V tom druhém případě bych se té knihovně raději vyhnul.)

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #2 kdy: 21. 08. 2014, 09:28:57 »
No na co se mi pořád nedaří přijít a nenašel jsem odpověď ani na netu (ani na SO nikdo asi neví):
Proč je nutné ty data kódovat do utf-8, wtf? Tomu vůbec nerozumím. Přece ajaxový požadavek je defaultně utf-8, takže
data se z js kódování ucs-2/utf-16 převedou na utf-8 a server je dostane jako utf-8.
Nevím, jak přesně tyhle knihovny komunikují, když WS není k dispozici, ale co se týče WS, tak to není ajax požadavek - prvně se provede handshake, který je ještě relativně korektní HTTP, a potom následuje stream dat, který už není HTTP vůbec. No a u toho streamu norma jasně říká, že to musí být platný UTF8 a pokud není, server MUSÍ spojení zavřít (http://tools.ietf.org/html/rfc6455#section-8.1).

Takže pokud nějaký data knihovně předáš, musela by vždycky kontrolovat, jestli se jedná o korektní UTF8 data a v případě že ne, musela by je nějak zakódovat. Což je zbytečný - lepší je říct, že prostě bere jenom UTF8 a když chceš předat něco jinýho, tak si to do UTF8 zakóduj sám.

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #3 kdy: 21. 08. 2014, 09:50:13 »
Takže pokud nějaký data knihovně předáš, musela by vždycky kontrolovat, jestli se jedná o korektní UTF8 data a v případě že ne, musela by je nějak zakódovat. Což je zbytečný - lepší je říct, že prostě bere jenom UTF8 a když chceš předat něco jinýho, tak si to do UTF8 zakóduj sám.
Ale jaká data můžete mít v JavaScriptu? Čísla, ale ta se nepošlou přímo, nejprve se převedou na text. Další objekty, ty se také nejprve převádějí na text. A potom text samotný. Text je ale v JavaScriptu posloupnost Unicode znaků, o žádném kódování tam nemá smysl mluvit. Z textu se to pomocí nějakého kódování převede na bajty až v okamžiku odesílání.

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #4 kdy: 21. 08. 2014, 10:02:26 »
Ale jaká data můžete mít v JavaScriptu? Čísla, ale ta se nepošlou přímo, nejprve se převedou na text. Další objekty, ty se také nejprve převádějí na text. A potom text samotný. Text je ale v JavaScriptu posloupnost Unicode znaků, o žádném kódování tam nemá smysl mluvit. Z textu se to pomocí nějakého kódování převede na bajty až v okamžiku odesílání.
JavaScript znám spíš z rychlíku, takže jsem o něm nemluvil. Šlo mi spíš o to, že to z principu jinak nemá smysl dělat, i kdyby nakrásně další verze JavaScriptu nějaké kódování uměla apod.


tell me why

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #5 kdy: 21. 08. 2014, 11:52:17 »
No na co se mi pořád nedaří přijít a nenašel jsem odpověď ani na netu (ani na SO nikdo asi neví):
Proč je nutné ty data kódovat do utf-8, wtf? Tomu vůbec nerozumím. Přece ajaxový požadavek je defaultně utf-8, takže
data se z js kódování ucs-2/utf-16 převedou na utf-8 a server je dostane jako utf-8.
Nevím, jak přesně tyhle knihovny komunikují, když WS není k dispozici, ale co se týče WS, tak to není ajax požadavek - prvně se provede handshake, který je ještě relativně korektní HTTP, a potom následuje stream dat, který už není HTTP vůbec. No a u toho streamu norma jasně říká, že to musí být platný UTF8 a pokud není, server MUSÍ spojení zavřít (http://tools.ietf.org/html/rfc6455#section-8.1).

Takže pokud nějaký data knihovně předáš, musela by vždycky kontrolovat, jestli se jedná o korektní UTF8 data a v případě že ne, musela by je nějak zakódovat. Což je zbytečný - lepší je říct, že prostě bere jenom UTF8 a když chceš předat něco jinýho, tak si to do UTF8 zakóduj sám.

Jj, napsal jsem ajax pozadavek, pak mi to hned doslo, kdyz jsem to odeslal,ale uz jsem se nechtel opravovat. Sock.js konkretne zkousi websocket a pak fallbackuje na dalsi protokoly jako xhr(ajax). Na tu specifikaci websocketu jsem taky koukal, jestli to neni kvuli tomu, ale to prekodovani z ucs-2/utf-16 do utf-8 si to resi samo, protoze jak psal filip jirsak, tak v javascriptu jakoby nejde neco prekodovat.
 
Tam jsou utf-16 retezce, kde kazdy znak z BMP je reprezentovan 2 bajty, tzn. je mozno reprezentovat \u0000-\uFFFF. Znaky mimo BMP se pak reprezentuji pomoci dvojici znaku (tzv. surrogate pairy), takze zabiraji 4 bajty.

To co dela to utf8.js jak psal filip jirsak je to, ze vlastne zase vrati utf-16 retezec (jine v js nejsou), kde ale kazdy znak toho retezce reprezentuje hodnotou 0x00-0xFD (takze v tom retezci uz jsou znaky jen z ascii). Kazdy znak tedy reprezentuje byte z utf-8 kodovani.

A tenhle utf-16 retezec, jehoz znaky reprezentuji byty utf-8 retezce :D se pak vezme a posle. A protoze prohlizec by to mel konveretovat pred odeslanim do utf-8 (jak pri poslani pres websockety, tak ajaxem), tak ta prace utf8.js se deje uplne zbytecne, protoze prohlizec by to stejne udelal.

Proste nechapu, proc se to pouziva.

tell me why

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #6 kdy: 21. 08. 2014, 12:03:23 »
Takže pokud nějaký data knihovně předáš, musela by vždycky kontrolovat, jestli se jedná o korektní UTF8 data a v případě že ne, musela by je nějak zakódovat. Což je zbytečný - lepší je říct, že prostě bere jenom UTF8 a když chceš předat něco jinýho, tak si to do UTF8 zakóduj sám.
Ale jaká data můžete mít v JavaScriptu? Čísla, ale ta se nepošlou přímo, nejprve se převedou na text. Další objekty, ty se také nejprve převádějí na text. A potom text samotný. Text je ale v JavaScriptu posloupnost Unicode znaků, o žádném kódování tam nemá smysl mluvit. Z textu se to pomocí nějakého kódování převede na bajty až v okamžiku odesílání.

JS pouziva ucs2 nebo utf-16. Kazdy znak je reprezentovan dvema byty a znaky, co se nevejdou na dva byty jsou reprezentovany pomoci surrogate pairu (2 znaky, tedy 4 bajty). To utf8.js vlastne zajisti, ze vsechny znaky toho utf-16 retezce reprezentuji maximalne hodnoy 0xFD. Pokud bych mel ajaxem s charsetem treba iso-8859-2 prenaset japonsky znaky, tak ty urcite nepujdou z utf-16 prevest do iso-8859-2. Pokud mi ale kazdy znak jakoby repreznetuje max. hodnotu 0xFD, tak to normalne prevedu. Na serveru pak akorat musim vsechno brat jako utf-8.
Tady bych to uziti utf8.js chapal, ale u ajaxu lze myslim vzdycky vynutit charset, takze si vzdycky reknu o utf-8 explicitne.   

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #7 kdy: 21. 08. 2014, 12:15:32 »
JS pouziva ucs2 nebo utf-16.
To je ale jen interní implementace některých interpretů JavaScriptu. Jiný interpret by klidně mohl String interně reprezentovat v UTF-32 nebo libovolném jiném kódování, které dokáže ukládat 16bitové znaky (protože podle standardu není String text v Unicode, ale posloupnost 16bitových čísel). Podstatné je to, že z JavaScriptu se nemáte jak dostat k té interní reprezentaci, takže na ní nezáleží. Podobné je to třeba v Javě. Naopak v C si můžete textový řetězec kdykoli přetypovat na pole bajtů, takže tam záleží na tom, jak je řetězec interně uložen.

tell me why

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #8 kdy: 21. 08. 2014, 12:44:31 »
JS pouziva ucs2 nebo utf-16.
To je ale jen interní implementace některých interpretů JavaScriptu. Jiný interpret by klidně mohl String interně reprezentovat v UTF-32 nebo libovolném jiném kódování, které dokáže ukládat 16bitové znaky (protože podle standardu není String text v Unicode, ale posloupnost 16bitových čísel). Podstatné je to, že z JavaScriptu se nemáte jak dostat k té interní reprezentaci, takže na ní nezáleží. Podobné je to třeba v Javě. Naopak v C si můžete textový řetězec kdykoli přetypovat na pole bajtů, takže tam záleží na tom, jak je řetězec interně uložen.

http://es5.github.io/x2.html#x2

podle toho to musí být utf-16 nebo ucs2

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #9 kdy: 21. 08. 2014, 13:10:21 »
http://es5.github.io/x2.html#x2

podle toho to musí být utf-16 nebo ucs2
Nemusí. Tohle popisuje, jak interpretovat znaky na vstupu, ale neříká, jaká má být vnitřní reprezentace v interpretu. Ono také nedává smysl, aby standard předepisoval vnitřní reprezentaci, která kód v JavaScriptu žádným způsobem nemůže ovlivnit.

tell me why

Re:Tak to zkusím i tu - socket.io/sock.js
« Odpověď #10 kdy: 21. 08. 2014, 17:24:57 »
http://es5.github.io/x2.html#x2

podle toho to musí být utf-16 nebo ucs2
Nemusí. Tohle popisuje, jak interpretovat znaky na vstupu, ale neříká, jaká má být vnitřní reprezentace v interpretu. Ono také nedává smysl, aby standard předepisoval vnitřní reprezentaci, která kód v JavaScriptu žádným způsobem nemůže ovlivnit.

hm, rozumím, to nemá v tom případě vůbec vliv na programování