<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>futtta&#039;s blog &#187; howto</title>
	<atom:link href="http://blog.futtta.be/category/rss-able/technology/howto/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.futtta.be</link>
	<description>Frank Goossens&#039; Twitterless twaddle</description>
	<lastBuildDate>Wed, 08 Feb 2012 17:05:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Remove Facebook like buttons with NoScript</title>
		<link>http://blog.futtta.be/2011/10/05/remove-facebook-like-buttons-with-noscript/</link>
		<comments>http://blog.futtta.be/2011/10/05/remove-facebook-like-buttons-with-noscript/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 06:44:17 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[ghostery]]></category>
		<category><![CDATA[like button]]></category>
		<category><![CDATA[noscript]]></category>
		<category><![CDATA[privacy]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=6517</guid>
		<description><![CDATA[If you don&#8217;t like Facebook&#8217;s omnipresent Like widgets (there were already plenty of reasons why not to like them and last week&#8217;s cookie-debacle only added to that conclusion) and if you already use NoScript so you don&#8217;t want to install another plugin (like Ghostery, which reports any tracking activity and allows you to block it), [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.futtta.be/2011/10/05/remove-facebook-like-buttons-with-noscript/noscript_abe/" rel="attachment wp-att-6521"><img class="alignright size-medium wp-image-6521" title="noscript abe screenshot" src="http://blog.futtta.be/wp-content/uploads/2011/10/noscript_abe-300x270.png" alt="" width="240" height="216" /></a>If you don&#8217;t like Facebook&#8217;s omnipresent Like widgets (there were already <a title="previously on this blog: i dislike facebook's like widget" href="http://blog.futtta.be/2010/07/26/why-i-dislike-facebooks-like-widgets/">plenty of reasons why not to like them</a> and <a title="bbc reports on &quot;cookiegate&quot; ;-)" href="http://www.bbc.co.uk/news/technology-15091674">last week&#8217;s cookie-debacle</a> only added to that conclusion) and if you already use <a title="noscript on this blog" href="http://blog.futtta.be/tag/noscript">NoScript</a> so you don&#8217;t want to install another plugin (like <a title="ghostery.com, for firefox, chrome, safari, opera and (with limited functionality) even for msie" href="http://www.ghostery.com/">Ghostery</a>, which reports any tracking activity and allows you to block it), you can put this in <a title="noscript's Application Bounderies Enforcer. Great stuff!" href="http://noscript.net/abe/index.html">NoScript&#8217;s ABE</a> user ruleset (NoScript Options -&gt; advanced -&gt; ABE);</p>
<p><code># Allow Facebook scripts and objects to be included only<br />
# from Facebook pages<br />
Site .facebook.com .fbcdn.net .facebook.net<br />
Accept from .facebook.com .fbcdn.net .facebook.net<br />
Deny INCLUSION(SCRIPT, OBJ, SUBDOC)</code></p>
<p>This tells NoScript to allow Facebook scripts (you know, to visit facebook.com), but to stop them from being included in other sites. I guess with <a title="surrogate scripts reference" href="http://hackademix.net/2011/09/29/script-surrogates-quick-reference/">NoScript&#8217;s surrogate scripts</a> one might even be able to replace Facebook&#8217;s Like-widget with one that just shows the old-fashioned (and harmless)  share-button. Now wouldn&#8217;t that be fun?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/10/05/remove-facebook-like-buttons-with-noscript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to fix SSL errors in Mac OS X browsers</title>
		<link>http://blog.futtta.be/2011/09/20/how-to-fix-ssl-errors-in-mac-os-x-browsers/</link>
		<comments>http://blog.futtta.be/2011/09/20/how-to-fix-ssl-errors-in-mac-os-x-browsers/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 06:51:27 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[browsers]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[certificate not trusted]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[intermediate certificate]]></category>
		<category><![CDATA[keychain]]></category>
		<category><![CDATA[mac os x]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=6430</guid>
		<description><![CDATA[So you know about SSL (or rather TLS) and you prefer things secure, so you request and pay for an officially signed certificate and configure your Apache to use it. The next days you&#8217;re feeling very Kevin Mitnicky, until some nitwit on Twitter trashes you for the ugly error-message he sees when trying to visit [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.futtta.be/2011/09/20/how-to-fix-ssl-errors-in-mac-os-x-browsers/chrome_mac_ssl_fail-2/" rel="attachment wp-att-6432"><img class="alignright size-medium wp-image-6432" title="chrome on mac: cert signed by trusted cert. authority not trusted?" src="http://blog.futtta.be/wp-content/uploads/2011/09/chrome_mac_ssl_fail1-300x58.png" alt="" width="300" height="58" /></a>So you know about SSL (or rather TLS) and you prefer things secure, so you request and pay for an officially signed certificate and configure your Apache to use it. The next days you&#8217;re feeling very <a title="cracker turned security expert (cfr. wikipedia)" href="http://en.wikipedia.org/wiki/Kevin_Mitnick">Kevin Mitnicky</a>, until some nitwit on Twitter trashes you for the ugly error-message he sees when trying to visit your supposedly &#8220;secure&#8221; site that is. What&#8217;s up with that?</p>
<p>Well, chances are that your disgruntled visitor was using a browser you didn&#8217;t test on, like Chrome on Mac for example? Because there is a small issue you have to take into account when &#8220;doing https&#8221;; both Chrome and Safari (but not Firefox) on Mac <a title="mac os x keychain; used by safari &amp; chrome, not by firefox" href="http://en.wikipedia.org/wiki/Keychain_(Mac_OS)">use OS X&#8217;s keychain</a>, which does not have some of the intermediate certificates needed to establish the trust relationship between your signed certificate and the certificate authority&#8217;s root certificate.</p>
<p>As you can&#8217;t expect Apple to add intermediate certificates to their keychain by default (which Firefox does a pretty good job though) and you can&#8217;t ask all your OS X users to add the intermediate certificate by hand either,  you&#8217;ll have to solve this yourself. A good thing Apache can help you in that department with it&#8217;s <a title="sslcertificatechainfile in apache" href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcertificatechainfile">SSLCertificateChainFile</a> directive, which</p>
<blockquote><p>sets the optional <em>all-in-one</em> file where you can assemble the certificates of Certification Authorities (CA) which form the certificate chain of the server certificate. This starts with the issuing CA certificate of the server certificate and can range up to the root CA certificate.</p></blockquote>
<p>If there&#8217;s only one intermediate certificate missing between your&#8217;s and the CA&#8217;s, you can export it in good old Firefox (as a pem-file), place it in the same directory as the actual certificate and use SSLCertificateChainFile to tell Apache where to find it and that should solve the nasty errors those Twittering Mac-heads get.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/09/20/how-to-fix-ssl-errors-in-mac-os-x-browsers/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Google App Engine project template for PHP (with Quercus)</title>
		<link>http://blog.futtta.be/2011/06/09/google-app-engine-project-template-for-php-with-quercus/</link>
		<comments>http://blog.futtta.be/2011/06/09/google-app-engine-project-template-for-php-with-quercus/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 19:01:19 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[google app engine]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[quercus]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=6116</guid>
		<description><![CDATA[So you&#8217;re a wanna-be developer who&#8217;d love to deploy in the cloud, but you only  &#8220;know&#8221; PHP? Well, as you might already have read elsewhere Caucho, the company behind Resin, has a 100% Java GPL&#8217;ed implementation of PHP5 called Quercus that can be used to run PHP on GAE. It took me some time to [...]]]></description>
			<content:encoded><![CDATA[<p>So you&#8217;re a wanna-be developer <a title="Do you know Amazon EC2 &amp; simpledb?" href="http://blog.futtta.be/2011/05/13/do-you-know-amazon-ec2-simpledb/">who&#8217;d love to deploy in the cloud</a>, but you only  &#8220;know&#8221; PHP? Well, as you might already have read elsewhere Caucho, the company behind Resin, has <a title="quercus home" href="http://quercus.caucho.com/">a 100% Java GPL&#8217;ed implementation of PHP5 called Quercus</a> that can be used to run PHP on GAE. It took me some time to put the pieces of the puzzle together, but in the end it&#8217;s pretty straightforward.</p>
<p>From scratch to a deployed webapp in 7 steps:</p>
<ol>
<li>Download &amp; install the <a title="download GAE SDK" href="http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Java">Google App Engine SDK</a></li>
<li>Download <a title="phptemplate.zip on my dropbox" href="http://dl.dropbox.com/u/9207036/phptemplate.zip">this GAE project template for PHP</a> and unzip it in the root of the SDK directory as  projects/phptemplate/</li>
<li>Put your PHP-files in projects/phptemplate/war/ (you probably want to overwrite index.php and remove phpinfo.php)</li>
<li>Test you application locally with dev_appserver <a title="&quot;running the dev web server&quot; appengine docs" href="http://code.google.com/appengine/docs/java/tools/devserver.html#Running_the_Development_Web_Server">as described here</a><em></em></li>
<li>Login on <a title="appengine dashboard home" href="https://appengine.google.com/">https://appengine.google.com/</a> and register a new application</li>
<li>Put the app id from (5) in projects/phptemplate/war/WEB-INF/appengine-web.xml, between the &lt;application&gt;-tage</li>
<li>Upload your application <a title="appcfg update to upload" href="http://code.google.com/appengine/docs/java/gettingstarted/uploading.html">as described here</a>: appcfg &#8211;enable_jar_splitting update &lt;path-to-war&gt; (&#8211;enable_jar_splitting is needed as the WEB-INF/lib/resin.jar is rather big)</li>
</ol>
<p>And there you have it, <a title="phptemplate running on GAE" href="http://phptemplate.appspot.com/">your very own PHP-app on GAE</a>! Check out the Quercus info on  on how you can <a title="java+php integration on caucho.com" href="http://quercus.caucho.com/quercus-3.1/doc/quercus.xtp#JavaPHPintegration">access Java components from within you PHP-code</a>, it might come in very handy to use GAE&#8217;s Java API&#8217;s for the datastore, queues and all those other goodies!</p>
<p>(<em><strong>Disclaimer</strong>: while this here template seems to work, I can&#8217;t make any promises or provide any kind of warranty.  As soon as you download it, you assume all responsibilities for any problems you might cause to the Internet, GAE or the Ozone-layer.</em>)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/06/09/google-app-engine-project-template-for-php-with-quercus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Secure your smartphone</title>
		<link>http://blog.futtta.be/2011/03/23/secure-your-smartphone/</link>
		<comments>http://blog.futtta.be/2011/03/23/secure-your-smartphone/#comments</comments>
		<pubDate>Wed, 23 Mar 2011 16:43:19 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[htc sense]]></category>
		<category><![CDATA[lookout]]></category>
		<category><![CDATA[lost phone]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4709</guid>
		<description><![CDATA[Your smartphone probably contains a wealth of information of personal and professional nature, which you would not want others to have access to. This is why (after losing my HTC Hero a couple of months ago) I now try to follow 2 out of these 3 simple rules: don&#8217;t lose your smartphone. if you lose [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-4710" title="setting up a lockscreen pattern in android" src="http://blog.futtta.be/wp-content/uploads/2011/03/screenlock_pattern_android.jpeg" alt="" width="114" height="171" />Your smartphone probably contains a wealth of information of personal and professional nature, which you would not want others to have access to. This is why (after <a title="On the rebound with an Acer beTouch e110" href="http://blog.futtta.be/2011/02/07/on-the-rebound-with-an-acer-betouch-e110/">losing my HTC Hero</a> a couple of months ago) I now try to follow 2 out of these 3 simple rules:</p>
<ol>
<li>don&#8217;t lose your smartphone.</li>
<li>if you lose your smartphone, make sure you have something in place to locate it</li>
<li>if you lose your smartphone and you can&#8217;t locate it, make sure you can wipe it remotely</li>
</ol>
<p>There are multiple solutions to locate &amp; wipe smartphones (including <a title="engadget about HTC Sense.com online services" href="http://www.engadget.com/2010/09/15/htcsense-com-will-backup-and-remotely-locate-wipe-htc-devices/">HTC&#8217;s Sense online offering</a>), but for my <a title="How to buy, upgrade, brick, rescue and generally enjoy a HTC Magic in just 14 days" href="http://blog.futtta.be/2011/03/15/how-to-buy-upgrade-brick-rescue-and-generally-enjoy-a-htc-magic-in-just-14-days/">Sense-less HTC Magic</a> I installed &#8220;<a title="Lookout on the Android Market" href="http://market.android.com/details?id=com.lookout">Lookout</a>&#8220;. Lookout is a free application that provides <strong>device location</strong>, contacts backup &amp; restore and apparently also malware protection. If you&#8217;re willing to pay $3/month, you also get <strong>remote wipe</strong>, <strong>remote lock</strong> and backup/ restore of pictures and call log. If you lose your Android-phone, you just log in to the Lookout-website to locate and optionally lock or wipe your handset.</p>
<p>I&#8217;m <strong>happy using the free version</strong> for now; I activated <strong>Android&#8217;s pattern lock-screen</strong> to avoid anyone from accessing my handset and deactivating Lookout. Remote wipe is great, but I guess I can activate my Lookout Premium account if ever I need that feature?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/03/23/secure-your-smartphone/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>How to buy, upgrade, brick, rescue and generally enjoy a HTC Magic in just 14 days</title>
		<link>http://blog.futtta.be/2011/03/15/how-to-buy-upgrade-brick-rescue-and-generally-enjoy-a-htc-magic-in-just-14-days/</link>
		<comments>http://blog.futtta.be/2011/03/15/how-to-buy-upgrade-brick-rescue-and-generally-enjoy-a-htc-magic-in-just-14-days/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 16:17:12 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[cyanogen]]></category>
		<category><![CDATA[cyanogenmod]]></category>
		<category><![CDATA[froyo]]></category>
		<category><![CDATA[goldcard]]></category>
		<category><![CDATA[htc]]></category>
		<category><![CDATA[magic]]></category>
		<category><![CDATA[recovery]]></category>
		<category><![CDATA[spl]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4667</guid>
		<description><![CDATA[Step 1: Buy So you&#8217;re not happy with your cheapo rebound phone, pining for your lost HTC Hero and you start checking out bargain-sites for a good 2nd hand Android smartphone. After a week or so you spot an HTC Magic, on sale for €100 and 2 days later go buy that beauty for even [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.futtta.be/wp-content/uploads/2011/03/magic_hboot.jpeg" alt="" title="htc magic in hboot-mode" width="121" height="161" class="alignright size-full wp-image-4681" /><em><strong>Step 1: Buy</strong></em><br />
So you&#8217;re not happy with <a title="On the rebound with an Acer beTouch e110" href="http://blog.futtta.be/2011/02/07/on-the-rebound-with-an-acer-betouch-e110/">your cheapo rebound phone</a>, pining for your lost HTC Hero and you start checking out bargain-sites for a good 2nd hand Android smartphone. After a week or so you spot an HTC Magic, on sale for €100 and 2 days later go buy that beauty for even €10 less because hey, there&#8217;s no SD-card.</p>
<p><em><strong>Step 2: Upgrade</strong></em><br />
Your brand new Magic turns out to be that very <a href="http://www.bemobile.be/2009/05/07/android-en-belgique-proximus-lance-le-htc-magic/">first Android-phone Proximus started sellinng in May 2009</a>, with Android 1.5, but without HTC Sense and tethering. Not really the smartphone you&#8217;d settle for, so you start looking around xda-developers for an upgrade path. You install flashrec, flash a new recovery image and in recovery flash <a title="myhero thread on xda-developers" href="http://forum.xda-developers.com/showthread.php?t=552274">MyHero 2.0.5</a> and after 1 month without it, you can finally boot into <a title="Switching back from Froyo to HTC’s Eclair" href="http://blog.futtta.be/2010/08/20/switching-back-from-froyo-to-htcs-eclair/">that beautiful HTC Sense UI</a> again.</p>
<p><em><strong>Step 3: Brick</strong></em><br />
HTC Sense, great, but still Android 1.5 and no tethering, seriously? No can do Sir, so you head back to xda-developers to figure out your next step. Late at night, after browsing millions of forum posts about perfected SPL&#8217;s, goldcards and recovery images, you find a thread with links to <a title="official RUU's, do not use these unless you are sure they match your phone's CID" href="http://forum.xda-developers.com/showthread.php?t=659403">official HTC RUU&#8217;s</a>. Easy-peasy and you download one of those boot your Windows PC and start flashing. HBOOT updates, radio updates, &#8230; all goes well and you doze off for a minute. But when you open your eyes, the upgrade process halted and you have a white screen with &#8220;<a title="invalid customer id. or was it vendor id?" href="http://forum.xda-developers.com/wiki/index.php?title=RUU_Errors#ERROR_.5B294.5D_:_INVALID_VENDOR_ID">invalid Customer ID</a>&#8221; in red and no Android. You reboot, no go. You try to enter recovery mode, no go. Congratulations, you now have a shiny (semi-)bricked HTC Magic and you go to sleep feeling an utter moron for trying to flash an official RUU.</p>
<p><em><strong>Step 4: Rescue</strong></em><br />
The next day you start looking for <a title="how to create a goldcard on theunlockr.com" href="http://theunlockr.com/2010/03/10/how-to-create-a-goldcard/">information on the secret craft of goldcard creation</a>. You spend a couple of days trying to get your SD-card&#8217;s CID on your PC, but eventually ask a colleague to adb-shell into his device with your SD-card in it to get the job done (thanks Thomas!). You don&#8217;t bother downloading crypto-software to reverse the string for all the wrong reason, instead immediately heading over to <a title="revskills.de goldcard image creation" href="http://psas.revskills.de/?q=goldcard">the goldcard-manufacturing-webstie</a>, write the disk-image to SD and you try to flash the RUU with the goldcard you just created. Damn, no go! You reverse the string manually, no go. You buy a new SD card (4Gb Sandisk), adb-shelling into your own cheapo Acer this time to get the CID and create a new goldcard, no go.  Over a week goes by and you decide to have another stab at it and opnly then you see that the string should be hex-reversed, not reversed. You click the link to <a title="hexrev on soaa.me" href="http://hexrev.soaa.me/">an online hexreverser</a>, create a goldcard with that string and bingo, the RUU flashes!</p>
<p><a href="http://cyanogenmod.com/"><img src="http://blog.futtta.be/wp-content/uploads/2011/03/cyanogenmod.gif" alt="cyanogenmod" title="cyanogenmod" width="128" height="128" class="alignright size-full wp-image-4679" /></a><em><strong>Step 5: Enjoy</strong></em><br />
It looks like you&#8217;re back where you were at step 2; Android 1.5 with HTC Sense UI and no tethering, so you decide to install <a href="http://www.cyanogenmod.com/">Cyanogenmod</a> by first <a href="http://wiki.cyanogenmod.com/index.php?title=HTC_Magic_%2832A%29:_Rooting_%286.35.x_radio%29">downgrading your radio &amp; hboot</a> and then -finally- <a href="http://wiki.cyanogenmod.com/index.php?title=Upgrading_from_CyanogenMod_4.2_to_CyanogenMod_5/6">flashing Cyanogen&#8217;s Android mod</a>. </p>
<p>And there you have it, after only 2 weeks you successfully turned that old HTC Magic into a modern, fast and reliable Android smartphone. Android 2.2.1 that is, with ADWlauncher, tethering and Exchange-integration. Time well spent, except &#8230; Vodaphone has <a href="http://mobile.engadget.com/2010/12/14/htc-magic-gets-froyo-on-vodafone-uk/">an official Froyo update for the Magic</a> out as well and <a href="http://forum.xda-developers.com/showthread.php?t=886671" title="damn, 32b, guess you'll have to flash a 32a kernel as well">there&#8217;s already a tweaked ROM for it on xda-developers</a>. You really should try that one out as soon as possible, now shouldn&#8217;t you?!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/03/15/how-to-buy-upgrade-brick-rescue-and-generally-enjoy-a-htc-magic-in-just-14-days/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Splitting up a vcard-file</title>
		<link>http://blog.futtta.be/2011/03/07/splitting-up-a-vcard-file/</link>
		<comments>http://blog.futtta.be/2011/03/07/splitting-up-a-vcard-file/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 06:37:43 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[split]]></category>
		<category><![CDATA[vcard]]></category>
		<category><![CDATA[vcf]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4646</guid>
		<description><![CDATA[As my Acer e110 doesn&#8217;t sync with Google, all of my precious contacts in the cloud did not automagically appear on my handset. That left me little but no choice to go the old-fashioned way; the export/import-dance. Exporting from Google is easy, but it generates one vcard-file with all you contacts in it, which the [...]]]></description>
			<content:encoded><![CDATA[<p>As <a title="On the rebound with an Acer beTouch e110" href="http://blog.futtta.be/2011/02/07/on-the-rebound-with-an-acer-betouch-e110/">my Acer e110</a> doesn&#8217;t sync with Google, all of my precious contacts in the cloud did not automagically appear on my handset. That left me little but no choice to go the old-fashioned way; the export/import-dance.</p>
<p>Exporting from Google is easy, but it generates one vcard-file with all you contacts in it, which the contacts app in Android 1.5 can only import the first entry from. To split up the contacts-file, Scroogle pointed me <a href="http://schattenschreiber.org/vcf-split/">vCard list-file splitter</a>, vcf-split for short, a Perl script from back in the days when Windows linebreaks apparently were sufficient evidence of the end of a vcard. But times and technology have changed and linebreaks have lost their former glory, meaning I had to slightly alter the script to watch out for a cryptic &#8220;END:VCARD&#8221; line to indicate the end of a vcard.</p>
<p>And the script goes a little something like this:</p>
<pre class="brush: perl; title: ; notranslate">
#!/usr/bin/perl
#
# vcf-split - split a .list.vcf file into many small .vcf files.
# Copyright (C) 2004  Raphael J. Schmid.
# Tweaked by Frank Goossens (&quot;futtta&quot;) in 2011
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# -- raphael.schmid@gmx.de
# -- futtta@gmail.com

use File::Basename;

if ($ARGV[0] eq &quot;&quot;) {
  print &quot;Usage: vcard-split &lt;file to split&gt;\n\n&quot;;
  exit;
}

$input=$ARGV[0];
$counter=0;

print $input;

open INPUT, $input or die $!;

while (&lt;INPUT&gt;) {
  open OUTPUT, &quot;&gt;&gt; &quot;.$counter.&quot;-&quot;.basename($input) or die $!;

  if ($_ =~ /END:VCARD/ ) {
    print OUTPUT $_;
    $counter+=1;
    close OUTPUT;
  } else {
    print OUTPUT $_;
  }
}

close OUTPUT;
close INPUT;
</pre>
<p>Who knows one day Google will send someone this way who has some vcf-splitting to do?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/03/07/splitting-up-a-vcard-file/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>3 Apache mod_cache gotchas</title>
		<link>http://blog.futtta.be/2011/02/23/3-apache-mod_cache-gotchas/</link>
		<comments>http://blog.futtta.be/2011/02/23/3-apache-mod_cache-gotchas/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 06:11:50 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mod_cache]]></category>
		<category><![CDATA[mod_proxy]]></category>
		<category><![CDATA[rfc2616]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4612</guid>
		<description><![CDATA[If you want to avoid the learning curve of Squid and Varnish or the cost of a dedicated caching &#38; proxying appliance, using Apache with mod_cache may seem like a good, simple and cheap solution. Rest assured, it can be -to some extent- but here are 3 gotchas I learned the hard way: mod_cache ignores [...]]]></description>
			<content:encoded><![CDATA[<p>If you want to avoid the learning curve of Squid and Varnish or the cost of a dedicated caching &amp; proxying appliance, using Apache with mod_cache may seem like a good, simple and cheap solution. Rest assured, it can be -to some extent- but here are 3 gotchas I learned the hard way:</p>
<ol>
<li>mod_cache <strong>ignores Cache-control if Expires is in the past</strong> (which it shouldn&#8217;t according to RFC2616), so <a title="as already described here a few months ago" href="http://blog.futtta.be/2010/10/12/drupal-mod_cache-rfc2616-caching/">you might have to unset the Expires-header</a>.</li>
<li>mod_cache <strong>by default caches cookies</strong>! Let me repeat; cookies are cached! That might be a huge security-disaster waiting to happen; sessionid&#8217;s (that provide access for logged-on users) are generally stored in cookies. If a logged on user that request an uncached page, then that user&#8217;s cookie will get cached and sent to other users that request the same page. Do disable this by adding &#8220;<a title="apache.org cacheignoreheaders doc" href="http://httpd.apache.org/docs/2.2/mod/mod_cache.html#cacheignoreheaders"><strong>CacheIgnoreHeader Set-Cookie</strong></a>&#8221; to your config</li>
<li>mod_cache by default <strong>treats all browsers like the one that triggered the caching</strong> of the object. In the field that approach <strong>can cause problems with e.g. CSS-files that are stored gzipped</strong> (because the first browser requested with header &#8220;Accept-Encoding: gzip, deflate&#8221;). If a browser that does not support gzipped content requests the same file, the CSS will be unreadable and thus not applied. The solution; make sure the &#8220;backend webserver&#8221; sends the &#8220;<strong>Vary: Accept-Encoding</strong>&#8221; header in the response (esp. for CSS-files). This will <a title="apache caching guide overview, scroll down to &quot;variable/ negotiated content&quot;" href="http://httpd.apache.org/docs/2.2/caching.html#overview">tell mod_cache to take different Accept-Encodings into account, storing and sending different versions of the same CSS-file</a>.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/02/23/3-apache-mod_cache-gotchas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to do jQuery templates with jQote2</title>
		<link>http://blog.futtta.be/2011/01/18/how-to-do-jquery-templates-with-jqote2/</link>
		<comments>http://blog.futtta.be/2011/01/18/how-to-do-jquery-templates-with-jqote2/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 10:51:04 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[irail api]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jqote2]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4477</guid>
		<description><![CDATA[For a proof of concept I was preparing at work I needed a jQuery templating solution. Although there is beta templating support (contributed by Microsoft) in jQuery, I decided to implement jQote2 instead. This alternative jQuery plugin is small (3,2Kb minimized, 1,7Kb compressed), versatile and most importantly very, very fast! So what do you need [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://futtta.be/jqote2"><img src="http://blog.futtta.be/wp-content/uploads/2011/01/jqote_example.png" alt="" title="jqote2 example screenshot" width="300" height="137" class="alignright size-full wp-image-4493" /></a>For a proof of concept I was preparing at work I needed a jQuery templating solution. Although there is <a title="Scott Guthrie about MS contributed jquery template" href="http://weblogs.asp.net/scottgu/archive/2010/05/07/jquery-templates-and-data-linking-and-microsoft-contributing-to-jquery.aspx">beta templating support (contributed by Microsoft) in jQuery</a>, I decided to implement <a title="jqote2 on jqery.com" href="http://plugins.jquery.com/project/jqote2">jQote2</a> instead. This alternative jQuery plugin is small (<a title="jqote2.min.js on github" href="https://github.com/aefxx/jQote2/blob/master/jquery.jqote2.min.js">3,2Kb minimized</a>, 1,7Kb compressed), versatile and <a title="comparison of jquery templates and jqote2" href="http://rileydutton.com/post/1303173205/jquery-templates-vs-jqote-2-a-followup-a-k-a-the">most importantly very, very fast</a>!</p>
<p>So what do you need to know about jQote2 to get it working? Well, there&#8217;s 3 ingredients; data, template and javascript-code to put the data in the template.</p>
<p>The data can be fetched from an external source, e.g. <a href="http://api.irail.be/liveboard/?format=json&#038;station=Brussel+Noord&#038;lang=EN&#038;arrdep=DEP">this call to the iRail-api for departures from Brussels North</a>.</p>
<p>The template is basically just HTML with some placeholders for your data:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;script type=&quot;text/x-jqote-template&quot; id=&quot;liveboard_tmpl&quot;&gt;
 &lt;tr&gt;
  &lt;td class=&quot;left&quot;&gt;
   &lt;%= this.station %&gt;
  &lt;/td&gt;
  &lt;td class=&quot;right&quot;&gt;
   &lt;%= this.time %&gt;
  &lt;/td&gt;
  &lt;td class=&quot;right&quot;&gt;
   &lt;%= this.platform %&gt;
  &lt;/td&gt;
 &lt;/tr&gt;
&lt;/script&gt;
</pre>
<p>The javascript fetches the data using jQuery&#8217;s getJson, parses all departures in the template and adds the resulting HTML to an element in your DOM (in this case #liveboard&#8217;):</p>
<pre class="brush: jscript; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(
	function() {
		$.getJSON(
			'http://api.irail.be/liveboard/?format=json&amp;station=Brussel%20Noord&amp;lang=EN&amp;arrdep=DEP&amp;callback=?',
			function(data) {
					$('#liveboard').jqoteapp('#liveboard_tmpl', data.departures.departure);
			}
		)
	}
);
&lt;/script&gt;
</pre>
<p>Off course the UNIX-timestamp in this.time isn&#8217;t really usable, but we can easily add some javascript to the template, just before outputting the time, to fix that;</p>
<pre class="brush: jscript; title: ; notranslate">
&lt;% this.time=((new Date((Number(this.time))*1000)).toLocaleTimeString()).substr(0,5); %&gt;
</pre>
<p>That&#8217;s right, use &#8220;&lt;%&#8221; instead of &#8220;&lt;%=&#8221; and you can mingle javascript in the template. To only show trains that have not left and to show departures including delay, the template looks like this:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;script type=&quot;text/x-jqote-template&quot; id=&quot;liveboard_tmpl&quot;&gt;
&lt;% if (this.left!=&quot;1&quot;) { %&gt;
 &lt;tr&gt;
  &lt;td class=&quot;left&quot;&gt;
   &lt;%= this.station %&gt;
  &lt;/td&gt;
  &lt;td class=&quot;right&quot;&gt;
   &lt;% if (this.delay!=&quot;0&quot;) {
    this.time=&quot;&lt;span class=\&quot;delayed\&quot;&gt;&quot;+((new Date((Number(this.time)+Number(this.delay))*1000)).toLocaleTimeString()).substr(0,5)+&quot;&lt;/span&gt;&quot;;
   } else {
    this.time=((new Date((Number(this.time))*1000)).toLocaleTimeString()).substr(0,5);
   } %&gt;
   &lt;%= this.time %&gt;
  &lt;/td&gt;
  &lt;td class=&quot;right&quot;&gt;
   &lt;%= this.platform %&gt;
  &lt;/td&gt;
 &lt;/tr&gt;
&lt;% }; %&gt;
&lt;/script&gt;
</pre>
<p>Add some CSS and you&#8217;ll quickly have something like <a href="http://futtta.be/jqote2/">the demo you can find here</a>. Just look at the code, it&#8217;s pretty straightforward and check out <a href="http://aefxx.com/api/jqote2-reference/">the jQote2 reference for even more info</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2011/01/18/how-to-do-jquery-templates-with-jqote2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Venus doesn&#8217;t love noscript</title>
		<link>http://blog.futtta.be/2010/12/01/venus-doesnt-love-noscript/</link>
		<comments>http://blog.futtta.be/2010/12/01/venus-doesnt-love-noscript/#comments</comments>
		<pubDate>Wed, 01 Dec 2010 16:44:40 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[html5lib]]></category>
		<category><![CDATA[noscript]]></category>
		<category><![CDATA[planet]]></category>
		<category><![CDATA[planet grep]]></category>
		<category><![CDATA[venus]]></category>
		<category><![CDATA[wp-youtube-lyte]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=4266</guid>
		<description><![CDATA[Damn, Venus doesn&#8217;t love noscript! You&#8217;ve got no clue what I&#8217;m rambling about, do you? Well, allow me to explain; &#60;noscript&#62; is the html tag that identifies alternative content for user agents (browsers, mainly) that don&#8217;t or won&#8217;t do javascript Venus is a planet-like web application that aggregates rss- and atom feeds from a community [...]]]></description>
			<content:encoded><![CDATA[<p>Damn, Venus doesn&#8217;t love noscript!</p>
<p>You&#8217;ve got no clue what I&#8217;m rambling about, do you? Well, allow me to explain;</p>
<ul>
<li><a title="noscript on developer.mozilla.org" href="https://developer.mozilla.org/en/HTML/Element/noscript">&lt;noscript&gt; is the html tag</a> that identifies alternative content for user agents (browsers, mainly) that don&#8217;t or won&#8217;t do javascript</li>
<li><a title="venus does not seem to have a real homepage, this is the main documentation instead" href="http://www.intertwingly.net/code/venus/docs/">Venus</a> is a planet-like web application that aggregates rss- and atom feeds from a community or about a specific subject (see e.g. <a href="http://planet.mozilla.org/">planet mozilla</a>, <a href="http://planet.debian.net/">planet debian</a> and the much-loved <a title="planet grep is where i'm at" href="http://planet.grep.be/">planet grep</a>)</li>
</ul>
<p>So now you know the context, let me reiterate; Venus doesn&#8217;t treat noscript the way it should! It not only strips out javascript as it should (are you listening <a title="tt-rss: javascript &quot;cleanup&quot; is optional" href="http://blog.futtta.be/2010/05/14/web-api-security-basics/">tt-rss</a>?) but it <strong>replaces noscript-tags and all HTML inside with escaped HTML (</strong>with HTML-entities actually). And that, my beloved ones, means that the <strong>HTML that <a title="my very own wordpress plugin" href="http://blog.futtta.be/tag/wp-youtube-lyte/">WP YouTube Lyte</a> generates, doesn&#8217;t work properly on Venus-based planets</strong>.</p>
<p>So I started looking at <a href="http://www.intertwingly.net/code/venus/">the Venus source</a> and mailed with Planet Grep&#8217;s <a title="wouter's home" href="http://grep.be/">Wouter Verhelst</a> to solve this issue. At first sight the <strong>solution seemed pretty straightforward</strong>; Venus shouldn&#8217;t &#8216;escape&#8217; noscript but should instead just strip the opening and closing noscript-tag. Wouter installed <a title="noscript is not evil, or so says my sed-script" href="http://dl.dropbox.com/u/9207036/noscript_is_not_evil.sed">a <strong>small sed-filter</strong> I wrote </a>and added noscript to <a title="acceptable_elements holds the whitelist" href="http://www.intertwingly.net/code/venus/planet/vendor/html5lib/sanitizer.py">the <strong>whitelist</strong> of Venus&#8217;s sanitizer</a> (which is based on <a href="http://feedparser.org/docs/html-sanitization.html">Universal Feed Parser</a>) and &#8230; it did not work.</p>
<p>The problem apperantly is with <strong>another sanitizing component in Venus; html5lib</strong>. Sam Ruby, the developer of Venus, <a href="http://lists.planetplanet.org/archives/devel/2010-November/002178.html">wrote on the mailinglist</a>;</p>
<blockquote><p>There are multiple sanitization passes involved here. [...] The html5parser seems to think that noscript is to be parsed as text only, which would result in the behavior that you describe.  Looking at the current HTML5 spec, it appears that this does not match the expected behavior &#8212; so perhaps that changed too.</p></blockquote>
<p>So I started looking at html5lib and &#8230; well, I&#8217;m stuck, html5lib is a pretty complex beast for a smalltime non-developer to dive into. So earlier today <a href="http://groups.google.com/group/html5lib-discuss/browse_thread/thread/5f534c342434bd42#">I turned to the html5lib discussion list to ask</a> how sanitization can be configured not to escape noscript, let&#8217;s hope someone will enlighten me. Because until then those poor Planet Greppers won&#8217;t be able to see (a thumbnail of) Al Jarreau&#8217;s great version of Take Five way back in 1976:</p>
<div class="lyte" id="WYL_hhq7fSrXn0c" style="width:640px;height:360px;"><noscript><a href="http://youtu.be/hhq7fSrXn0c"><img src="http://img.youtube.com/vi/hhq7fSrXn0c/0.jpg" alt="" width="640" height="340" /></a> Embedded with WP YouTube Lyte.</noscript><script type="text/javascript"><!-- 
 (function(){var d=document;var w=window;if(w.addEventListener){w.addEventListener('load', insert, false)}else{w.onload=insert};setTimeout(insert, 1000);function insert(){if(!d.getElementById('lytescr')){lytescr=d.createElement('script');lytescr.async=true;lytescr.id='lytescr';lytescr.src='http://blog.futtta.be/wp-content/plugins/wp-youtube-lyte/lyte/lyte-min.js?wylver=1.0.0';h=d.getElementsByTagName('script')[0];h.parentNode.insertBefore(lytescr, h)}};}()) 
 --></script></div>
<div class="lL">Watch this video <a href="http://youtu.be/hhq7fSrXn0c">on YouTube</a> or on <a href="http://icant.co.uk/easy-youtube/?http://www.youtube.com/watch?v=hhq7fSrXn0c">Easy Youtube</a>.</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2010/12/01/venus-doesnt-love-noscript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Drupal, mod_cache &amp; RFC2616 caching</title>
		<link>http://blog.futtta.be/2010/10/12/drupal-mod_cache-rfc2616-caching/</link>
		<comments>http://blog.futtta.be/2010/10/12/drupal-mod_cache-rfc2616-caching/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 06:51:35 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[lang:en]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[mod_cache]]></category>
		<category><![CDATA[mod_proxy]]></category>
		<category><![CDATA[pressflow]]></category>
		<category><![CDATA[rfc2616]]></category>

		<guid isPermaLink="false">http://blog.futtta.be/?p=3860</guid>
		<description><![CDATA[Suppose you&#8217;re setting up a Drupal-based site for which you have to implement a caching reverse proxy and for reasons beyond your comprehension Varnish (or even Squid) are not an option. Oh no, you&#8217;re stuck with Apache&#8217;s mod_proxy and mod_cache! What should you do? First of all, Drupal 6 doesn&#8217;t like reverse proxies. If you [...]]]></description>
			<content:encoded><![CDATA[<p>Suppose you&#8217;re setting up a Drupal-based site for which you have to implement a caching reverse proxy and for reasons beyond your comprehension Varnish (or even Squid) are not an option. Oh no, you&#8217;re stuck with Apache&#8217;s <a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy.html">mod_proxy</a> and <a href="http://httpd.apache.org/docs/2.2/mod/mod_cache.html">mod_cache</a>! What should you do?</p>
<p>First of all, Drupal 6 doesn&#8217;t like reverse proxies. If you don&#8217;t want to wait for version 7, which should do better in this respect, you might want to look at <a title="pressflow is to drupal what ubuntu is to debian. that's what the pressflow-guys say." href="http://pressflow.org/">Pressflow</a>. This Drupal 6 &#8220;distro&#8221; has everything on board to work with reverse proxies. So install Pressflow (or <a title="diff from the pressflow-guys" href="http://drupal.org/files/issues/my_unidiff.patch">try to apply this out of date diff to stock Drupal</a>) and in the Performance-screen set &#8220;Caching Mode&#8221; to &#8220;External&#8221; and &#8220;Page Cache Maximum Age&#8221; to the number of minutes you consider a cached page valid. Voila, you&#8217;re done in Drupal (edit: almost, as you might also want to change the $base_url in sites/default/settings.php to reverse proxy URL after you configured Apache).</p>
<p>Next up: Apache! A simple configuration like this one should do the trick:</p>
<pre class="brush: bash; title: ; notranslate">
ProxyRequests Off
ProxyPass /rp_drupal http://localhost/pressflow
ProxyPassReverse /rp_drupal http://localhost/pressflow
CacheEnable disk /rp_drupal/
CacheRoot c:/TEMP/apacache
CacheDefaultExpire 3600
</pre>
<p>OK, this must surely work, no? Well it should, but it doesn&#8217;t! When setting your Apache-loglevel to debug you&#8217;ll see &#8220;not cached&#8221; entries in your error-log, with the following reason:</p>
<blockquote><p>Expires header already expired, not cacheable</p></blockquote>
<p>Expires in the past, what does <a href="http://bazaar.launchpad.net/~pressflow/pressflow/6/annotate/94/includes/bootstrap.inc#L969">Pressflow think it&#8217;s doing deep down in includes/bootstrap.inc</a>?</p>
<pre class="brush: php; title: ; notranslate">// HTTP/1.0 proxies do not support the Vary header, so prevent any caching
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
// Expires header if a Cache-Control: max-age= directive is specified (see RFC
// 2616, section 14.9.3).
drupal_set_header('Expires', 'Sun, 11 Mar 1984 12:00:00 GMT');
// [...]
$max_age = variable_get('cache', CACHE_DISABLED) == CACHE_AGGRESSIVE &amp;&amp; (!isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary'])) ? variable_get('page_cache_max_age', 0) : 0;
$default_headers['Cache-Control'] = 'public, max-age=' . $max_age;</pre>
<p>Darn, those Pressflow-guys seem to have read up on their RFC&#8217;s! And indeed, <a title="RFC 2616 says Pressflow is right, Apache wrong??" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3">2616 confirms</a> that cache-control&#8217;s max-age overrules expires;</p>
<blockquote><p>If a response includes both an Expires header and a max-age directive, the max-age directive overrides the Expires header, even if the Expires header is more restrictive. This rule allows an origin server to provide, for a given response, a longer expiration time to an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache.</p></blockquote>
<p><a title="mod_cache's code on svn.apache.org" href="http://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x/modules/cache/mod_cache.c">Mod_cache&#8217;s code</a> seems to take a much simpler approach; at line 503 it decides not to cache based on an Expires-header in the past, totally dismissing the potential presence of cache-control&#8217;s max-age.</p>
<pre class="brush: cpp; title: ; notranslate">else if (exp != APR_DATE_BAD &amp;&amp; exp &lt; r-&gt;request_time)
    {
        /* if a Expires header is in the past, don't cache it */
        reason = &quot;Expires header already expired, not cacheable&quot;;
    }
</pre>
<p>But you&#8217;re not interested in code which does or does not adhere to whatever RFC some spec-buffs came up with, you just want to cache your frigging&#8217; Drupal-site! Well, fear not little hacker-boy, here&#8217;s some Apache-magic to cure your ailments, to be copy/pasted in the config before ProxyPass and ProxyPassReverse:</p>
<pre class="brush: bash; title: ; notranslate">
&lt;Location /rp_drupal&gt;
     SetEnvIf Request_Protocol &quot;HTTP/1.1&quot; expires_overrule
     # homework: add a SetEnvIf to see if cache-control max-age is present
     Header unset Expires env=expires_overrule
&lt;/Location&gt;
</pre>
<p>So there you have it, a rudimentary caching setup for Drupal (in the guise of Pressflow) using nothing but Apache&#8217;s mod_proxy and mod_cache. Now go do your homework and test and do some finetuning and test some more. Happy caching!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.futtta.be/2010/10/12/drupal-mod_cache-rfc2616-caching/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

