abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 14:33 | Nová verze

    Byla vydána nová verze 14.3 svobodného unixového operačního systému FreeBSD. Podrobný přehled novinek v poznámkách k vydání.

    Ladislav Hagara | Komentářů: 0
    dnes 14:00 | Upozornění

    CSIRT.CZ upozorňuje, že na základě rozhodnutí federálního soudu ve Spojených státech budou veškeré konverzace uživatelů s ChatGPT uchovávány. Včetně těch smazaných.

    Ladislav Hagara | Komentářů: 3
    dnes 13:44 | Pozvánky

    Ač semestr ve škole právě končí, bastlíři ze studentského klubu Silicon Hill neodpočívají a opět se jako každý měsíc hlásí s pravidelným bastlířským setkáním Virtuální Bastlírna, kde si můžete s ostatními techniky popovídat jako u piva o novinkách, o elektronice, softwaru, vědě, technice obecně, ale také o bizarních tématech, která se za poslední měsíc na internetu vyskytla.

    Z novinek za zmínku stojí Maker Faire, kde Pájeníčko předvedlo … více »
    bkralik | Komentářů: 0
    dnes 04:44 | Zajímavý software

    Na WWDC25 byl představen balíček Containerization a nástroj container pro spouštění linuxových kontejnerů na macOS. Jedná se o open source software pod licencí Apache 2.0 napsaný v programovacím jazyce Swift.

    Ladislav Hagara | Komentářů: 0
    dnes 02:00 | IT novinky

    Do 16. června do 19:00 běží na Steamu přehlídka nadcházejících her Festival Steam Next | červen 2025 doplněná demoverzemi, přenosy a dalšími aktivitami. Demoverze lze hrát zdarma.

    Ladislav Hagara | Komentářů: 0
    včera 21:44 | IT novinky

    Apple na své vývojářské konferenci WWDC25 (Worldwide Developers Conference, keynote) představil řadu novinek: designový materiál Liquid Glass, iOS 26, iPadOS 26, macOS Tahoe 26, watchOS 26, visionOS 26, tvOS 26, nové funkce Apple Intelligence, …

    Ladislav Hagara | Komentářů: 0
    včera 20:44 | Komunita

    Organizátoři konference LinuxDays 2025, jež proběhne o víkendu 4. a 5. října 2025 v Praze na FIT ČVUT, spustili přihlašování přednášek (do 31. srpna) a sběr námětů na zlepšení.

    Ladislav Hagara | Komentářů: 0
    včera 19:11 | Nová verze

    Po roce byla vydána nová stabilní verze 25.6.0 svobodného multiplatformního multimediálního přehrávače SMPlayer (Wikipedie).

    Ladislav Hagara | Komentářů: 0
    včera 12:55 | IT novinky

    DNS4EU, tj. evropská infrastruktura služeb DNS založená na vysoce federovaném a distribuovaném ochranném ekosystému, byla spuštěna v testovacím režimu [𝕏]. Na výběr je 5 možností filtrování DNS.

    Ladislav Hagara | Komentářů: 17
    8.6. 22:44 | IT novinky

    Skriptovací programovací jazyk PHP (PHP: Hypertext Preprocessor, původně Personal Home Page) dnes slaví 30 let. Přesně před třiceti lety, 8. června 1995, oznámil Rasmus Lerdorf vydání PHP Tools (Personal Home Page Tools) verze 1.0.

    Ladislav Hagara | Komentářů: 19
    Jaký je váš oblíbený skriptovací jazyk?
     (55%)
     (32%)
     (7%)
     (2%)
     (0%)
     (0%)
     (3%)
    Celkem 241 hlasů
     Komentářů: 16, poslední 8.6. 21:05
    Rozcestník

    Servlety a kódování znaků

    17.5.2006 21:43 | Přečteno: 2389× | 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.