HTTP header madness: diverse problemen met Yahoo YUI, Safari en Firefox

Wednesday 08 July 2009, 22:56:00 | web dev

Afgelopen week een aantal vreemde problemen tegen het lijf gelopen rondom HTTP headers:

  1. Apple's Safari normaliseert de HTTP headers die hij van de server krijgt.
  2. Het Connection object uit Yahoo's YUI library voldoet niet aan de standaard bij het opvragen van HTTP headers.
  3. Mozilla's Firefox doet raar met caching van HTTP headers.

Achtereenvolgens is dat dan 1) raar; 2) API bug; 3) bug. Hieronder zal ik uitleggen wat deze problemen precies inhouden.

Als eerste het relatief eenvoudige probleem: Safari normaliseert de HTTP headers die hij van de server krijgt.

Dat wil zeggen, hij maakt de header volledig lowercase en de eerste letters van de woorden weer uppercase. Dus x-CUSTOM-header wordt in Safari doorgegeven als X-Custom-Header. Dat is eigenlijk geen probleem, omdat de HTTP specificatie vermeld dat Field names are case-insensitive. Dus dan moet het niet uitmaken of je in je software de header opvraagt als "X-CUSTOM-HEADER" of "x-custom-header", het is één pot nat.

En dat klopt bijvoorbeeld ook, als je een klein stukje javascript maakt dat via een XMLHttpRequest een 'ajax' call doet, en vervolgens d.m.v. de getResponseHeader methode headers gaat uitvragen. Deze geeft netjes de betreffende header terug ook als de case niet exact klopt (zie de W3C specificatie).

Dus waar maak ik me eigenlijk druk om? Nou, het blijkt dat niet alle software zich houdt aan de W3C spec... Dat brengt ons op het volgende punt:

Het Connection object uit Yahoo's YUI library voldoet niet aan de standaard bij het opvragen van HTTP headers.

Het gaat om YAHOO.util.Connect, wat een wrapper is om XMLHttpRequest om 'ajax' calls te kunnen doen. Om één of andere bizarre reden heeft men bij Yahoo besloten dat de methods van het XMLHttpRequest object om de headers uit te vragen, nu gewone properties van het response object moesten worden. Als je de source er bij pakt kun je zien dat de http response headers in een associative array gezet worden en dat je ze op moet halen met array subscription: getResponseHeader["header-naam"]. De grote fout die daardoor begaan wordt is dat de headers niet langer case-insensitive gezocht kunnen worden omdat een associative array in Javascript case-sensitive is!

Zolang je exact de juiste header string opgeeft is er niks aan de hand, maar herinner nu het issue van hierboven (Safari die je HTTP headers normaliseert). Dan voel je het al aankomen: in Safari werkt je javascript code mogelijk opeens niet meer als je gebruik maakt van YUI en HTTP headers moet uitlezen bij 'ajax' requests! Terwijl je code eerst prima werkte zolang je direct gebruik maakt van het native XMLHttpRequest object... Even een korte schets van wat er fout kan gaan:

Is het dan niet de fout van Safari, kun je je afvragen. Te meer omdat er niks aan de hand is in de andere browsers die ik heb getest (Firefox 3, IE 7, Opera 9): zij laten de headers ongemoeid die van de server terugkomen. Mijn mening is dat dit niet uitmaakt en dat het echt een bug is in YUI; de spec zegt tenslotte dat HTTP header fields case-insensitive zijn en dan moet het dus niet uitmaken welke header string je exact gebruikt in je code. Ik kwam de bug alleen op het spoor toen ik met Safari ging testen, en opeens mijn javascript ermee ophield. Maar ik vind dat je net zo goed in je code mag zetten: "X-CUSTOM-HEADER", en deze moet dan overal die header teruggeven. Maar als je dit doet zul je ervaren dat de code het opeens in geen enkele browser meer goed doet...

Het ironische is trouwens: de YUI library zou juist een browser onafhankelijk platform moeten bieden voor web programming, maar in dit geval introduceert het juist een browser afhankelijkheid!

Op dit moment heb ik het opgelost door op de server ervoor te zorgen dat alle custom headers alvast 'genormaliseerd' worden doorgestuurd, maar echt duurzaam is dat niet. Misschien is een wrapper functie om http headers op te halen - en die rekening houdt met de YUI bug van het array - wel het beste...

Tenslotte dan nog het probleem in Firefox waarbij de browser verkeerde HTTP headers rapporteert als je van server wisselt in je URL.

Deze is lastig uit te leggen, ik ga hier binnenkort nog een keer een test case voor neerzetten om het hopelijk beter uit te zoeken, maar vooralsnog heb ik het volgende waargenomen:

Gebruikte tools: Firefox 3 + Firebug, Fiddler debugging proxy.

Het is een heel vaag probleem waar ik nog niet mijn vinger achter heb kunnen krijgen. Zoals gezegd hoop ik binnenkort nauwkeuriger te kunnen testen en mogelijk de oorzaak te vinden of zelfs een oplossing.

People have replied:

Irmen de Jong

2009-07-12 16:43:00

Goed ik heb een test pagina gemaakt voor probleem #3: Firefox die http headers cached.

Het heeft trouwens niets te maken met verschillende servers: het gaat ook al mis als het requests zijn naar dezelfde server. Ik had het echter als eerste waargenomen in een situatie met verschillende servers.

Waar het op neer lijkt te komen is dat het XMLHttpRequest object in Firefox, HTTP headers lijkt te cachen waarbij de string waaronder deze als eerste aangetroffen wordt, wordt vastgehouden gedurende de hele tijd dat de pagina in de cache zit. Als een nieuw 'ajax' request dezelfde HTTP header teruggeeft maar met als verschil dat deze een andere case heeft (b.v. X-CUSTOM-HDR t.o.v. X-Custom-Hdr) dan blijft Firefox de header string van de vorige keer hanteren.

Op zich is dat niet zo heel erg, ware het niet dat door de bug in de YUI library er dus problemen kunnen ontstaan die heel erg veel lijken op het probleem dat Safari heeft omdat die ook met case van http headers loopt te knoeien... :-( Misschien toch maar een officiele bug report indienen? Hier alvast de report op het Firefox support forum.