abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    včera 22:44 | IT novinky

    Apple představil nový MacBook Pro s čipy M4, M4 Pro a M4 Max.

    Ladislav Hagara | Komentářů: 1
    včera 22:00 | Zajímavý software

    Na GOG.com běží Halloween Sale 2024. Při té příležitosti lze získat zdarma počítačovou hru Return of the Phantom.

    Ladislav Hagara | Komentářů: 0
    včera 20:22 | IT novinky

    Společnost OpenAI spustila internetový vyhledávač ChatGPT search.

    Ladislav Hagara | Komentářů: 0
    včera 14:33 | Pozvánky

    Konference OpenAlt 2024 proběhne již tento víkend 2. a 3. listopadu v prostorách FIT VUT v Brně. Začíná ale už v pátek na warm-up party ve Studentském klubu u Kachničky v 17:00. Pokud jste ještě areál FITu nenavštívili, k dispozici jsou pokyny k orientaci. Na programu je 54 přednášek a workshopů. Témata jsou od silně technických témat jako je třeba GCC nebo PostgreSQL po méně technické témata jako eGovernment, nebo třeba detailní analýzu … více »

    Ladislav Hagara | Komentářů: 2
    včera 13:23 | Nová verze

    Byla vydána nová verze 6.9 živé linuxové distribuce Tails (The Amnesic Incognito Live System), jež klade důraz na ochranu soukromí uživatelů a anonymitu. Přehled změn v příslušném seznamu. Tor Browser byl povýšen na verzi 14.0.1. Tor client na verzi 0.4.8.13. Thunderbird na verzi 115.16.0.

    Ladislav Hagara | Komentářů: 1
    včera 12:33 | Komunita

    Vývojáři free a open source synchronizačního nástroje (a p2p náhrady Dropboxu) Syncthing oznámili, že z důvodu odporu ze strany Google Play ukončují podporu OS Android. Bohužel v rámci toho zmizí i vydání Syncthing na F-Droid, který má slabší uživatelskou základnu. Syncthing je na Androidu implementován formou wrapper aplikace, která spustí Syncthing démon, vyžádá potřebná oprávnění a zpřístupní webové rozhraní démona. Ve srovnání se

    … více »
    Harvie.CZ | Komentářů: 4
    včera 01:11 | Nová verze

    V červnu 2022 bylo oznámeno, že z K-9 Mailu se stane Thunderbird pro Android. Trvalo to poněkud déle, než vývojáři předpokládali, ale včera byl první stabilní Thunderbird pro Android 8.0 vydán.

    Ladislav Hagara | Komentářů: 0
    30.10. 21:33 | Komunita

    Projekt microDMG Racer na Kickstarteru nevyšel, tak se autor rozhodl uvolnit na ESP32 postavené autíčko i ovladač jako open source.

    Ladislav Hagara | Komentářů: 6
    30.10. 13:22 | Nová verze

    Byl vydán TrueNAS SCALE 24.10 „Electric Eel“. Přehled novinek této open source storage platformy postavené na Debianu v poznámkách k vydání.

    Ladislav Hagara | Komentářů: 0
    30.10. 13:11 | Nová verze

    Byla vydána nová verze 24.10.29 svobodného multiplatformního video editoru Shotcut (Wikipedie) postaveného nad multimediálním frameworkem MLT. Nově s podporou AI (whisper.cpp) pro generování titulků. Nejnovější Shotcut je již vedle zdrojových kódů k dispozici také ve formátech AppImage, Flatpak a Snap.

    Ladislav Hagara | Komentářů: 1
    Rozcestník

    Servlety a kódování znaků

    17.5.2006 21:43 | Přečteno: 2368× | Java | poslední úprava: 18.5.2006 10:11

    Zatímco nastavení správného kódování souborů odesílaných webovým serverem do prohlížeče je už celkem zvládnutá věc, příjem textů z formulářů na webovém serveru může záludnostmi souvisejícími s kódováním ještě potrápit. Protože jsem při hledání jedné chyby na Abíčku zabrousil do hlubin zdrojových kódu Servlet API a servlet kontejneru Jetty, a nechci to za půl roku zkoumat znovu, popíšu (si) závěry výzkumu sem.

    Ani s vynálezem Unicode není problémům s různými kódováními znaků konec. Většinou už se s nimi nesetkávají běžní uživatelé, ale programátoři si jich stále ještě užijí dost a dost. Jedním z klasických problémů je komunikace přes HTTP.

    Každý slušný webový server, pokud posílá nějaký text, přidá do HTTP hlaviček informaci o jaký typ dat se jedná (např. HTML, čistý text) a také v jakém jsou kódování:

    HTTP/1.x 200 OK
    Date: Wed, 17 May 2006 18:24:59 GMT
    Server: Jetty/4.2.17
    Content-Type: text/html; charset=UTF-8
    

    Při odesílání dat z webového formuláře na server je ale situace horší. application/x-www-form-urlencoded nebo multipart/form-data , o použitém kódování ani čárka. Nějak mezi prohlížeči není zvykem tam informaci o kódování přidávat. Ona by nejspíš také spoustu serverů zmátla, a zbytek by s ní neuměl pracovat. A servery se tuto informaci zase nepokoušejí číst, protože ji prohlížeče neposílají. Začarovaný kruh.

    Naštěstí je mezi prohlížeči dobrým zvykem odesílat data zpět v kódování, v jakém ho přijala (resp. v kódování, které má na dané stránce uživatel zrovna nastavené, takže změní-li si uživatel z nějakého důvodu kódování stránky, pošlou se data v jiném kódování, než čekáte). Vynechám teď speciální případy, kdy mám v jednom projektu stránky v různých kódováních, nebo kdy bych chtěl odesílat data do formuláře, který nemám pod kontrolou (na cizí web) a musel bych se kódováním své stránky trefit do kódování cílového webu. I v jednoduchém případě, že odesílám formulář na svůj vlatní web, který má konzistení kódování znaků, pořád je tu problém: já jako autor aplikace vím, v jakém kódování mám stránky, a tedy v jakém kódování očekávat odpověď. Ale ta aplikace to neví.

    Konkrétně ve specifikaci Servlet API k tomu, aby se to aplikace dozvěděla, slouží metoda ServletRequest.setCharacterEncoding(String), doplněná do API od verze 2.3. Tím sdělíte Servlet API, v jakém kódování bude odpověď. (Jak jsem popsal výše, Servlet API nemá žádný způsob, jak kódování zjistit z HTTP požadavku. Spoléhá tedy na programátora, že dopředu ví, jaké to kódování bude. Ještě stále dokážou programátoři z pohledu počítačů magické věci – zde třeba věštit budoucnost.) Dobrým zvykem tedy je na začátku servletu (ještě před jakýmkoliv čtením z HTTP požadavku) zavolat tuto metodu se správným kódováním – a o zbytek už se není potřeba starat, Servlet API se postará o správné rozkódování parametrů dotazu a programátor v dalším kódu už jen může vrnět blahem nad tím, jak Java pěkně pracuje s řetězci, že String je prostě řetězec Unicode znaků a o nějaké kódování se nemusím starat, dockud nechci řetězec poslat zase někam ven.

    Pokud tuhle metodu programátor na začátku nezavolá, předpokládá servlet kontejner nějaké defaultní kódování – např. Jetty ve verzi 4.2.x předpokládalo kódování iso-8859-1, verze 5 a výš předpokládají UTF-8. Poměrně častý způsob zacházení s kódováním požadavku (a před přidáním metody ServletRequest.setCharacterEncoding(String) jediný možný) tedy bylo:

    Že tuhle rozcvičku text přežil ve zdraví je dáno shodou okolností: URLkódování kóduje oktety (osmibitové znaky) – kódování původního textu, který prohlížeč posílal, tedy vždy muselo pro svou reprezentaci používat oktety (ona se dnes snad ani jiná kódování nepoužívají, i UTF-16 ukládá do dvojic oktetů). A kódování iso-88592-1 plně pokrývá celý rozsah oktetů – jinými slovy, ať si zvolíte jakýkoli oktet, vždy to v iso-8859-1 znamená nějaký platný znak. U UTF-8 je situace horší, tam by zřejmě bylo možné vyrobit takovou sekvenci oktetů, které v UTF-8 neznamenají nic – tam už by tedy mohlo dojít ke ztrátě některých znaků nebo dokonce k chybě při překódování. Naštěstí u znakových sad iso-8859-2 a Windows-1250 se všechny běžné znaky vyjádřené v oktetech namapují na nějaké znaky UTF-8, takže ke ztrátě informace nedojde (alespoň jsem se s tím zatím nesetkal).

    Až dosud by to byla docela známá věc, a nebylo by potřeba nic zkoumat. Kdyby mi při testování nevracelo Servlet API tvrdošíjně řetězce překódované podle iso-8859-1 nezávisle na tom, jaké kódování jsem nastavil. (V situaci, kdy Jetty je spuštěné pod Windows a tedy kódovou stránkou windows-1250, konzole ve Windows zobrazuje v CP852, HTML stránky a tedy parametry jsou v iso-8859-2 a Servlet API si o tom myslí, že je to iso-8859-1, taky chvíli trvalo, než jsem zjistil, kde se to vlastně špatně překóduje…)

    Kamenem úrazu se zde stalo ono před jakýmkoli čtením požadavku. Debugování naustále ukazovalo, že parametry požadavku už někdo četl… Pochvíli byl jasný i pachatel: Filtr jakarta_compression (nejspíš součást Tomcatu), který komprimuje odpovědi gzipem, aby se po síti přenášelo míň dat. Tento filtřík s 60 řádky copyrightu a 200 řádky kódu se zcela nevinně dotazoval na parametr gzip. Sloužil mu k tomu, aby v případě, že je nastaven na false, data nekomprimoval. Taková drobná fíčurka usnadňující ladění… Tím pádem už někdo četl parametry, tedy četl požadavek, a tedy jakékoli snahy o změnu kódování vyšly naprázdno.

    Jak z toho ven? Napadají mne dvě možnosti: za prvé – pokaždé, když Servlet API získá informaci o změně kódování, zahodit nakešované parametry a načíst je znovu, tentokrát ve správném kódování (fuj). Taky by to zřejmě znamenalo pamatovat si celý požadavek po celou dobu zpracováníní… Druhá možnost: všem filtrům a veškerému zpracování požadavku předřadit ještě jeden filtr, který nastaví předpokládané kódování (dvakrát fuj). Všechny filtry mezi tím prvním nastavovacím a mým servletem budou už pracovat s nějakým kódováním, a nebudou o tom vědět. Navíc nastavení kódování parametrů, které potřebuji v Servletu, musím udělat úplně někde jinde, v nesouvisející části, a ještě nesmím zapomenout to všude přidat. Asi jako kdyby se už u zápisu do 1. třídy ptali, z jakých předmětů chci maturovat…

    Bohužel, nezbyde než použít metodu dvakrát fuj, protože jak mě upozornil Greg Wilkins, autor Jetty, specifikace k metodě ServletRequest.setCharacterEncoding(String) říká:

    Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader(). Otherwise, it has no effect.
    Tedy volně řečeno: dokud požadavek nikdo nečetl, lze měnit kódování libovolně, jakmile se někdo byť jen na písmenko podíval, je se změnami kódování utrum.

    A závěr? Příště už si nebudu myslet, že volání setCharacterEncoding na prvním řádku servletu je dostatečně brzo. Bez Filteru nastavujícího správné kódování už v Servlet webaplikacích ani ránu. Aneb

    public class EncodingFilter implements Filter{
      public void init(FilterConfig filterConfig) {
        this.encoding = filterConfig.getInitParameter("encoding");
      }
    
      public void doFilter ( ServletRequest request, ServletResponse response,
          FilterChain chain ) throws IOException, ServletException {
        request.setCharacterEncoding(this.encoding);
        chain.doFilter(request, response);
      }
    }
    
    do každé rodiny. A příležitostně pošťouchnout Mozillí Bugzillu, jestli by třeba nechtěl Firefox s formulářovými daty posílat i jejich kódování, pozeptat se ve fóru Servlet API, Apache a dalších, jestli by z takových údajů nechtěli informace o kódování získávat, a tak. A nebo doplnit křišťálovou kouli jako standardní výbavu webserverů…

    PS: A mimochodem – ta chyba na Abíčku nakonec byla úplně v něčem jiném. Věřili byste, že je možné přes chránku vložit do textového pole formuláře ve Firefoxu znaky jako Escape (kód 27)? A zřejmě občas někdo považoval za dobrý nápad takovéhle znaky vložit třeba do diskuze… Ale exkurze po zdrojácích Jetty z toho byla rozhodně zajímavá, vyzkoušet si vzdálené ladění Jetty s pomocí eclipse se také hodilo, a zase jsem o něco chytřejší… :-)

           

    Hodnocení: 100 %

            špatnédobré        

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    18.5.2006 07:49 mivrap | blog: Mirkovo
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    Zajímavé... Ovšem odstavec "Že tuhle rozcvičku..." mi přijde nějaký hóódně podezřelý. Napadla mě při tom otázka: Co máš vůbec za sebou v rámci počítačového vzdělávání? Gympl? Samouk?
    18.5.2006 10:00 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    Co je na něm podezřelého? OK, UTF-16 nekóduje do 2 oktetů ale do 16 bitů, což je ale vzájemně triviálně převoditelné…

    Co já vím, jak je to s mým počítačovým vzděálním? Samouk, gympl jako student, učitel i správce sítě, přednášky na VŠ…
    Jiří Poláček avatar 18.5.2006 08:53 Jiří Poláček | skóre: 47 | blog: naopak | Sivice
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    Před pár měsíci jsem se také s kódováním znaků z formulářů trápil. Řešení jsem našel na wiki Tomcatu.
    Sudoku omrzelo? Zkuste bobblemaze! | Statistiky jsou jak bikiny. Napoví hodně, všechno ale neukážou.
    18.5.2006 10:10 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    No jo, jenže to první popsané řešení na té wiki je právě špatně :-( Za prvé, IE ani jiný prohlížeč neposílá data v iso-8859-1, ale v kódování, v jakém je stránka s formulářem. Je na to jednuduchý test – pokusit se odeslat text třeba s č, ř, š apod. – tyhle znaky není jak v iso-8859-1 zakódovat. Ale prohlížeč je zpravidla odešle :-) A za druhé se tam provádí ono dvojí překódování znaků, což nemusí dopadnout vždycky dobře. Navíc se tam předpokládá, že to první překódování bylo podle iso-8859-1, což taky nemusí být vždy pravda. To druhé řešení je správné, je tam dokonce i celý ten filtr i jeho použití, takže copy–&–paste toho filtru doporučuji z wiki Tomcatu :-)
    Jiří Poláček avatar 19.5.2006 09:17 Jiří Poláček | skóre: 47 | blog: naopak | Sivice
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    Kdyby prohlížeče odesílaly data v kódování, v jakém je stránka s formulářem, tak bych s tím neměl žádné problémy a nehledal řešení ... Nevím, jestli v tom nemá prsty Tomcat, ale u mě se data posílají v iso-8859-1 bez ohledu na kódování stránky.
    Sudoku omrzelo? Zkuste bobblemaze! | Statistiky jsou jak bikiny. Napoví hodně, všechno ale neukážou.
    19.5.2006 09:54 Filip Jirsák | skóre: 68 | blog: Fa & Bi
    Rozbalit Rozbalit vše Re: Servlety a kódování znaků
    Důkazem, že prohlížeč neodesílá data v kódování iso-8859-1, je samotný váš komentář :-) V kódování iso-8859-1 nejsou znaky ř, ž, č – vám se je přes prohlížeč přesto podařilo odeslat… Jestli pod Tomcatem máte v servletu znaky rozkódované, jakoby byly iso-8859-1, ale stránka je v jiném kódování, je to přesně to, o čem byl můj spot – a nejjednodušší řešení je použít filtr popsaný na konci spotu nebo na vámi odkazované wiki Tomcatu.

    Mimochodem, pro ladění servletů doporučuji rozšíření do Firefoxu LiveHTTPheaders, tam můžete zjistit, v jakém kódování prohlížeč stránku dostává, jaká data odesílá atd.

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.