<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>grack.com</title>
	
	<link>http://grack.com/blog</link>
	<description>Matt Mastracci's random musings on code, people and other important things</description>
	<lastBuildDate>Thu, 17 Sep 2009 22:13:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/grack" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Javascript primitive conversion quick-reference</title>
		<link>http://grack.com/blog/2009/09/16/javascript-primitive-conversion-quick-reference/</link>
		<comments>http://grack.com/blog/2009/09/16/javascript-primitive-conversion-quick-reference/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 16:02:00 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=327</guid>
		<description><![CDATA[Javascript has three primitive types: number, string and boolean.  You can quickly coerce values between the primitive types using some simple expressions.
There are a few different coersion expressions, depending on how you want to handle some of the corner cases.  I&#8217;ve automatically generated a list below:



Conversion:
To Number
To Number
To Number
To String
To Boolean
To Boolean


Expression:
+x
(+x)&#124;&#124;0
+(x&#124;&#124;0)
&#8220;&#8221;+x
!!x
!!+x




null
0
0
0
&#8220;null&#8221;
false
false


(void 0)
NaN
0
0
&#8220;undefined&#8221;
false
false


NaN
NaN
0
0
&#8220;NaN&#8221;
false
false


Infinity
Infinity
Infinity
Infinity
&#8220;Infinity&#8221;
true
true


-Infinity
-Infinity
-Infinity
-Infinity
&#8220;-Infinity&#8221;
true
true


0
0
0
0
&#8220;0&#8243;
false
false


&#8220;0&#8243;
0
0
0
&#8220;0&#8243;
true
false


1
1
1
1
&#8220;1&#8243;
true
true


&#8220;1&#8243;
1
1
1
&#8220;1&#8243;
true
true


2
2
2
2
&#8220;2&#8243;
true
true


&#8220;2&#8243;
2
2
2
&#8220;2&#8243;
true
true


[]
0
0
0
&#8220;&#8221;
true
false


({})
NaN
0
NaN
&#8220;[object Object]&#8220;
true
false


true
1
1
1
&#8220;true&#8221;
true
true


&#8220;true&#8221;
NaN
0
NaN
&#8220;true&#8221;
true
false


false
0
0
0
&#8220;false&#8221;
false
false


&#8220;false&#8221;
NaN
0
NaN
&#8220;false&#8221;
true
false


&#8220;&#8221;
0
0
0
&#8220;&#8221;
false
false


&#8220;null&#8221;
NaN
0
NaN
&#8220;null&#8221;
true
false



The [...]]]></description>
			<content:encoded><![CDATA[<p>Javascript has three primitive types: number, string and boolean.  You can quickly coerce values between the primitive types using some simple expressions.</p>
<p>There are a few different coersion expressions, depending on how you want to handle some of the corner cases.  I&#8217;ve automatically generated a list below:</p>
<table id="results" style="border: 1px solid black; border-collapse: collapse;" border="0">
<tbody>
<tr>
<th>Conversion:</th>
<th style="border: 1px solid black; padding: 0.2em;">To Number</th>
<th style="border: 1px solid black; padding: 0.2em;">To Number</th>
<th style="border: 1px solid black; padding: 0.2em;">To Number</th>
<th style="border: 1px solid black; padding: 0.2em;">To String</th>
<th style="border: 1px solid black; padding: 0.2em;">To Boolean</th>
<th style="border: 1px solid black; padding: 0.2em;">To Boolean</th>
</tr>
<tr>
<th>Expression:</th>
<th style="border: 1px solid black; padding: 0.2em;">+x</th>
<th style="border: 1px solid black; padding: 0.2em;">(+x)||0</th>
<th style="border: 1px solid black; padding: 0.2em;">+(x||0)</th>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;&#8221;+x</th>
<th style="border: 1px solid black; padding: 0.2em;">!!x</th>
<th style="border: 1px solid black; padding: 0.2em;">!!+x</th>
</tr>
</tbody>
<tbody>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">null</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;null&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">(void 0)</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;undefined&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">NaN</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;NaN&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">Infinity</th>
<td style="border: 1px solid black; padding: 0.2em;">Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;Infinity&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">-Infinity</th>
<td style="border: 1px solid black; padding: 0.2em;">-Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">-Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">-Infinity</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;-Infinity&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">0</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;0&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;0&#8243;</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;0&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">1</th>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;1&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;1&#8243;</th>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;1&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">2</th>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;2&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;2&#8243;</th>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">2</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;2&#8243;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">[]</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">({})</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;[object Object]&#8220;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">true</th>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">1</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;true&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;true&#8221;</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;true&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">false</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;false&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;false&#8221;</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;false&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;&#8221;</th>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
<tr>
<th style="border: 1px solid black; padding: 0.2em;">&#8220;null&#8221;</th>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">0</td>
<td style="border: 1px solid black; padding: 0.2em;">NaN</td>
<td style="border: 1px solid black; padding: 0.2em;">&#8220;null&#8221;</td>
<td style="border: 1px solid black; padding: 0.2em;">true</td>
<td style="border: 1px solid black; padding: 0.2em;">false</td>
</tr>
</tbody>
</table>
<p>The above table was generated with this code (note: uses some Firefox-specific code).</p>
<pre>&lt;table id="results" style="border-collapse: collapse; border: 1px solid black;"&gt;
 &lt;tr id="header"&gt;
 &lt;th&gt;Conversion:&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr id="header2"&gt;
 &lt;th&gt;Expression:&lt;/th&gt;
 &lt;/tr&gt;
&lt;/table&gt;

&lt;script&gt;
function styleCell(cell) {
 cell.style.border = '1px solid black';
 cell.style.padding = '0.2em';
 return cell;
}

values = [
null, undefined, NaN, +Infinity, -Infinity, 0, "0", 1, "1", 2, "2",
   [], {}, true, "true", false, "false", "", "null"
]

coersions = [
["To Number", "+x"],
 ["To Number", "(+x)||0"],
 ["To Number", "+(x||0)"],
 ["To String", "\"\"+x"],
 ["To Boolean", "!!x"],
 ["To Boolean", "!!+x"]
]

var results = document.getElementById('results');
var trHeader = document.getElementById('header');
var trHeader2 = document.getElementById('header2');

for (var i = 0; i &lt; coersions.length; i++) {
 var th = trHeader.appendChild(styleCell(document.createElement('th')));
 th.textContent = coersions[i][0]
 th = trHeader2.appendChild(styleCell(document.createElement('th')));
 th.textContent = coersions[i][1]
}

for (var i = 0; i &lt; values.length; i++) {
 var tr = results.appendChild(document.createElement('tr'));
 var rowHeader = tr.appendChild(styleCell(document.createElement('th')));
 rowHeader.textContent = uneval(values[i]);

 for (var j = 0; j &lt; coersions.length; j++) {
 var td = tr.appendChild(styleCell(document.createElement('td')));
 td.textContent = uneval(eval("(function(x) { return "+coersions[j][1]+"})")(values[i]));
 }
}

&lt;/script&gt;</pre>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=noVe25lEK_k:1rsffgEIn18:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=noVe25lEK_k:1rsffgEIn18:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=noVe25lEK_k:1rsffgEIn18:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=noVe25lEK_k:1rsffgEIn18:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=noVe25lEK_k:1rsffgEIn18:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=noVe25lEK_k:1rsffgEIn18:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=noVe25lEK_k:1rsffgEIn18:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=noVe25lEK_k:1rsffgEIn18:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/noVe25lEK_k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/16/javascript-primitive-conversion-quick-reference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Time for Atom to Put RSS Out to Pasture?</title>
		<link>http://grack.com/blog/2009/09/15/time-for-atom-to-put-rss-out-to-pasture/</link>
		<comments>http://grack.com/blog/2009/09/15/time-for-atom-to-put-rss-out-to-pasture/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 02:42:43 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=409</guid>
		<description><![CDATA[Is it time to the world to move on from RSS and to its successor, Atom?  Some considerations:
Atom has an IETF standard for syndication. Atom has an IETF standard for publication. Atom was designed for modularity. Atom supports rich, well-defined activities within feeds.
RSS is effectively frozen at 2.0:
RSS is by no means a perfect [...]]]></description>
			<content:encoded><![CDATA[<p>Is it time to the world to move on from RSS and to its successor, Atom?  Some considerations:</p>
<p><a href="http://tools.ietf.org/html/rfc4287">Atom has an IETF standard for syndication.</a> <a href="http://tools.ietf.org/html/rfc5023">Atom has an IETF standard for publication.</a> <a href="http://en.wikipedia.org/wiki/Atom_%28standard%29#Modularity">Atom was designed for modularity.</a> <a href="http://activitystrea.ms/">Atom supports rich, well-defined activities within feeds.</a></p>
<p>RSS is effectively frozen at 2.0:</p>
<blockquote><p>RSS is by no means a perfect format, but it is very popular and widely supported. Having a settled spec is something RSS has needed for a long time. The purpose of this work is to help it become a unchanging thing, to foster growth in the market that is developing around it, and to clear the path for innovation in new syndication formats. Therefore, the RSS spec is, for all practical purposes, frozen at version 2.0.1. We anticipate possible 2.0.2 or 2.0.3 versions, etc. only for the purpose of clarifying the specification, not for adding new features to the format. Subsequent work should happen in modules, using namespaces, and in completely new syndication formats, with new names.</p></blockquote>
<p>It is full of <a href="http://www.rssboard.org/rss-specification#lttextinputgtSubelementOfLtchannelgt">legacy</a> <a href="http://www.rssboard.org/rsscloud-interface">tags</a> and <a href="http://www.rssboard.org/rss-specification#optionalChannelElements">archaic design decisions</a>:</p>
<blockquote><p>The purpose of the &lt;textInput&gt; element is something of a mystery. You can use it to specify a search engine box. Or to allow a reader to provide feedback. Most aggregators ignore it.</p></blockquote>
<p>We are spending all this time duplicating effort.  Every feed reader needs to deal with Atom <em>and</em> RSS.  Every blog provides an Atom feed and an RSS feed.  Users trying to subscribe to blog feeds are presented with an unnecessary choice.</p>
<p>RSS solved a need at the time, even though it was crufty and difficult to use and difficult to parse (remember when RSS XML didn&#8217;t have to be well-formed XML?).  It served as an inspiration for millions of sites to open up their content to new methods of reading.  It inspired a great successor, Atom, which has surpassed it many times over.</p>
<p>We dropped gopher when its time ran out.  It&#8217;s time to make Atom the primary format for blogs.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=VAYxtyrHqjM:D9XK95OD3YU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=VAYxtyrHqjM:D9XK95OD3YU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=VAYxtyrHqjM:D9XK95OD3YU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=VAYxtyrHqjM:D9XK95OD3YU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=VAYxtyrHqjM:D9XK95OD3YU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=VAYxtyrHqjM:D9XK95OD3YU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=VAYxtyrHqjM:D9XK95OD3YU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=VAYxtyrHqjM:D9XK95OD3YU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/VAYxtyrHqjM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/15/time-for-atom-to-put-rss-out-to-pasture/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Real-time Search and Frnégtttrdre</title>
		<link>http://grack.com/blog/2009/09/14/real-time-search-and-frnegtttrdre/</link>
		<comments>http://grack.com/blog/2009/09/14/real-time-search-and-frnegtttrdre/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 05:30:44 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=400</guid>
		<description><![CDATA[Robert Scoble&#8217;s accidental tweet (&#8221;Frnégtttrdre&#8221;) earlier tonite caused a minor ripple: people wondering if he was announcing a secret project, under the influence of alcohol or wandering around with an unlocked iPhone in his back pocket.
It also makes for an interesting test for real-time search.
An hour after his tweet:

Google lists 7 results (of which a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://scobleizer.com">Robert Scoble&#8217;s</a> <a href="http://friendfeed.com/scobleizer/79055172/frnegtttrdre">accidental tweet</a> (&#8221;Frnégtttrdre&#8221;) earlier tonite caused a minor ripple: people wondering if he was announcing a secret project, under the influence of alcohol or wandering around with an unlocked iPhone in his back pocket.</p>
<p>It also makes for an interesting test for real-time search.</p>
<p>An hour after his tweet:</p>
<ul>
<li><a href="http://www.google.com/search?q=Frnégtttrdre">Google lists 7 results</a> (of which a few now point to this blog)</li>
<li><a href="http://www.bing.com/search?q=Frn%C3%A9gtttrdre&amp;go=&amp;form=QBLH&amp;filt=all&amp;qs=n">Bing lists 0 results</a></li>
<li><a href="http://ca.search.yahoo.com/search?p=Frn%C3%A9gtttrdre&amp;fr=yfp-t-501&amp;type=&amp;toggle=1&amp;cop=&amp;ei=UTF-8">Yahoo lists 0 results</a></li>
<li><a href="http://search.twitter.com/search?q=Frn%C3%A9gtttrdre">Twitter search lists 12 results</a></li>
<li><a href="http://friendfeed.com/search?q=Frn%C3%A9gtttrdre">FriendFeed lists 20+ results</a></li>
<li><a href="http://www.oneriot.com/search?q=Frn%C3%A9gtttrdre&amp;st=web&amp;ot=">OneRiot doesn&#8217;t support Unicode in URLs and falls over</a></li>
<li><a href="http://tweetmeme.com/search?q=Frn%C3%A9gtttrdre">Tweetmeme lists 0 results</a></li>
</ul>
<p>Anyone else I&#8217;ve missed?</p>
<p>Conclusions: If you tweet a random word, there&#8217;s no guarantee that you&#8217;ll get indexed right away.  Additionally, not every service tests unicode querystring parameters.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=_mMtAWHQyvo:Fvgs9GiHJLI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=_mMtAWHQyvo:Fvgs9GiHJLI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=_mMtAWHQyvo:Fvgs9GiHJLI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=_mMtAWHQyvo:Fvgs9GiHJLI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=_mMtAWHQyvo:Fvgs9GiHJLI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=_mMtAWHQyvo:Fvgs9GiHJLI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=_mMtAWHQyvo:Fvgs9GiHJLI:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=_mMtAWHQyvo:Fvgs9GiHJLI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/_mMtAWHQyvo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/14/real-time-search-and-frnegtttrdre/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Serious rssCloud Protocol DDoS Vulnerability</title>
		<link>http://grack.com/blog/2009/09/10/serious-rsscloud-ddos-vulnerability/</link>
		<comments>http://grack.com/blog/2009/09/10/serious-rsscloud-ddos-vulnerability/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 02:00:09 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=375</guid>
		<description><![CDATA[UPDATE: There&#8217;s a new domain parameter in rssCloud that makes this DDoS far, far worse.  Since there&#8217;s no verification (yet) on rssCloud endpoints, you can now subscribe any server to any rssCloud hub&#8217;s notifications.
While researching some of the issues of rssCloud running in a shared hosting environment, I came across a serious vulnerability in the [...]]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATE: </strong>There&#8217;s <a href="http://rsscloud.org/walkthrough/proposedChange.html">a new domain parameter in rssCloud</a> that makes this DDoS far, far worse.  Since there&#8217;s no verification (yet) on rssCloud endpoints, <em>you can now subscribe any server to any rssCloud hub&#8217;s notifications</em>.</p>
<p>While researching some of the issues of rssCloud running in a shared hosting environment, I came across a serious vulnerability in the protocol.  The vulnerability allows someone to cripple a shared web host.  Because of the sensitive nature of this vulnerability, I&#8217;m not going to share example code or which shared host(s) are vulnerable.  <strong>The fix is easy: follow these <a href="http://grack.com/blog/2009/09/10/rsscloud-security-notifications/">security recommendations</a> to close the hole</strong>.</p>
<p>The inspiration for this vulnerability was discovered by <a href="http://friendfeed.com/nlothian/b7fcee08/rsscloud-is-even-more-broken-that-i-realized-it">Nick Lothian&#8217;s post on FriendFeed</a>.  It turns out that many shared hosting providers route incoming and outgoing HTTP requests through different IP addresses.  The process of routing the HTTP requests is usually done transparently by a networking gear outside of the web servers themselves.</p>
<p>rssCloud&#8217;s specification infers the endpoint from the REMOTE_ADDR CGI variable at the time of the subscription.  It would be very difficult to get an rssCloud subscriber working in a shared hosting environment because every subscription request you make goes out on IP address A, but all of your incoming requests come in via port 80 on IP address B.  For some shared web providers, the machines that make outgoing requests are also web servers, serving banner messages or redirects to sales sites.  Because they are web servers, they are considered valid rssCloud REST endpoints (returning 200 OK for POST requests on some URLs).</p>
<p>When you put these pieces together, it becomes readily apparent that you can now subscribe your shared host&#8217;s outgoing HTTP request IP address to any number of feeds. Considering that Wordpress has 7.5 million blogs that speak rssCloud, there&#8217;s a significant number of blogs that could end up pinging the machine.</p>
<p>There are probably a number of other interesting vulnerabilities in this area, such as traffic that travels through a proxy, or an anonymizing service such as <a href="http://tor.eff.org">TOR</a>. It may be possible to knock one of these offline by subscribing it to a large number of feeds.</p>
<p>The problem with rssCloud is that its subscription request only proves that you <em>can make</em> requests via the given IP address, not that the given IP address <strong>is willing to receive</strong> them. By adding the challenge parameter I suggested in the previous post, you can now guarantee that the endpoint is willing to receive these requests, making it much harder to subscribe an unwilling participant in the protocol.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=ciXvhr6xhLM:-DQynkFz2l0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=ciXvhr6xhLM:-DQynkFz2l0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=ciXvhr6xhLM:-DQynkFz2l0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=ciXvhr6xhLM:-DQynkFz2l0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=ciXvhr6xhLM:-DQynkFz2l0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=ciXvhr6xhLM:-DQynkFz2l0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=ciXvhr6xhLM:-DQynkFz2l0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=ciXvhr6xhLM:-DQynkFz2l0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/ciXvhr6xhLM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/10/serious-rsscloud-ddos-vulnerability/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>rssCloud Security Recommendations</title>
		<link>http://grack.com/blog/2009/09/10/rsscloud-security-notifications/</link>
		<comments>http://grack.com/blog/2009/09/10/rsscloud-security-notifications/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 21:41:29 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=368</guid>
		<description><![CDATA[Copy of an email I sent to http://tech.groups.yahoo.com/group/rss-cloud/messages:
I&#8217;ve been looking into the security of rssCloud over the last few days and a number of serious issues have come up.  The ones of immediate importance have been reported and fixed, but I&#8217;d like to suggest some protocol changes to prevent rssCloud servers from DoS&#8217;ing sites [...]]]></description>
			<content:encoded><![CDATA[<p>Copy of an email I sent to <a href="http://tech.groups.yahoo.com/group/rss-cloud/messages">http://tech.groups.yahoo.com/group/rss-cloud/messages</a>:</p>
<p>I&#8217;ve been looking into the security of rssCloud over the last few days and a number of serious issues have come up.  The ones of immediate importance have been reported and fixed, but I&#8217;d like to suggest some protocol changes to prevent rssCloud servers from DoS&#8217;ing sites or ending up DoS&#8217;ing each other.</p>
<p>Here are my implementor guidelines, based on the research over the last few days.  These guidelines should mitigate all of the problems I&#8217;ve found so far without requiring rssCloud subscribers to make major changes to their code:</p>
<ol>
<li>An rssCloud implementation MUST validate that the Content-Type of the POST is &#8220;application/x-www-form-urlencoded&#8221;.</li>
<li>All rssCloud parameters MUST be read from the body of the HTTP POST (ie: $_POST in PHP or equivalent in other languages).  Parameters in the querystring must be ignored.</li>
<li>The path parameter for the callback path MUST begin with a /.</li>
<li>The port parameter, if specified, must be converted to an integer value before constructing the callback URL with it.  Any trailing non-digit characters must cause the hub to return a 5xx error.</li>
<li>The subscription callback and all subscription pings MUST include a &#8220;challenge&#8221; parameter (inspired by PubSubHubbub).  The subscriber MUST respond with a response that contains the contents of that challenge parameter as the body of the response.  No additional information may appear in the body.</li>
</ol>
<p>I haven&#8217;t taken a look at the SOAP/XML-RPC parts of the protocol yet, but the extra framing should help make them more secure.  Someone more familiar with those technologies should run those through their paces.</p>
<p>Feel free to contact me with any rssCloud hub implementation you might have and I&#8217;ll run my battery of tests against it.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=cIZ9PCjPUmo:XeTF3Ptv_PQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=cIZ9PCjPUmo:XeTF3Ptv_PQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cIZ9PCjPUmo:XeTF3Ptv_PQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cIZ9PCjPUmo:XeTF3Ptv_PQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=cIZ9PCjPUmo:XeTF3Ptv_PQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cIZ9PCjPUmo:XeTF3Ptv_PQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=cIZ9PCjPUmo:XeTF3Ptv_PQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cIZ9PCjPUmo:XeTF3Ptv_PQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/cIZ9PCjPUmo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/10/rsscloud-security-notifications/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Parsing the PubSubHubbub Notifications</title>
		<link>http://grack.com/blog/2009/09/09/parsing-the-pubsubhubbub-notifications/</link>
		<comments>http://grack.com/blog/2009/09/09/parsing-the-pubsubhubbub-notifications/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 05:58:22 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=366</guid>
		<description><![CDATA[I&#8217;ve updated my prototype to use the excellent Rome feed parser library.  Instead of dumping 20kB of &#8216;useful&#8217; raw feed on you, it now formats the entries nicely.
I&#8217;ve hooked it up to deliver me real-time headlines from my Google Reader feed and from TechCrunch, both of which work flawlessly.
With all the building blocks I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve updated my prototype to use the excellent <a href="http://rome.dev.java.net/">Rome</a> feed parser library.  Instead of dumping 20kB of &#8216;useful&#8217; raw feed on you, it now formats the entries nicely.</p>
<p>I&#8217;ve hooked it up to deliver me real-time headlines from my <a href="http://www.google.com/reader/public/atom/user/06220228422595838760/state/com.google/broadcast">Google Reader feed</a> and from <a href="http://feeds.feedburner.com/Techcrunch">TechCrunch</a>, both of which work flawlessly.</p>
<p>With all the building blocks I&#8217;ve strung together, this really wasn&#8217;t any work at all.  All of the complexity lies in the cloud: Google&#8217;s AppEngine and XMPP implementation and the PubSubHubbub hub. The rest is done with a feed-parsing library. </p>
<p>Here&#8217;s the new code:</p>
<pre>
package com.grack.pubsubhubbub.xmpp;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.xmpp.JID;
import com.google.appengine.api.xmpp.MessageBuilder;
import com.google.appengine.api.xmpp.XMPPService;
import com.google.appengine.api.xmpp.XMPPServiceFactory;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;

@SuppressWarnings("serial")
public class Subscribe extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setStatus(204);
		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));

		SyndFeedInput input = new SyndFeedInput();
		SyndFeed feed;
		try {
			feed = input.build(new XmlReader(req.getInputStream()));
		} catch (IllegalArgumentException e) {
			throw new ServletException(e);
		} catch (FeedException e) {
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Feed exception: " + e.toString()).withRecipientJids(jid)
					.build());
			throw new ServletException(e);
		}

		@SuppressWarnings("unchecked")
		List<SyndEntry> entries = feed.getEntries();

		StringBuilder message = new StringBuilder("Got update: \n");
		for (SyndEntry entry : entries) {
			message.append(entry.getTitle()).append(": ").append(
					entry.getLink()).append('\n');
		}
		xmpp.sendMessage(new MessageBuilder().withBody(message.toString())
				.withRecipientJids(jid).build());
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setStatus(200);
		resp.setContentType("text/plain");

		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));

		if (req.getParameter("hub.mode").equals("subscribe"))
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Subscribing to " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());
		else
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Unsubscribing from " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());

		resp.getOutputStream().print(req.getParameter("hub.challenge"));
		resp.getOutputStream().flush();
	}
}
</pre>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=U3h0siRcp1o:Hsumesk4r8I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=U3h0siRcp1o:Hsumesk4r8I:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=U3h0siRcp1o:Hsumesk4r8I:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=U3h0siRcp1o:Hsumesk4r8I:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=U3h0siRcp1o:Hsumesk4r8I:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=U3h0siRcp1o:Hsumesk4r8I:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=U3h0siRcp1o:Hsumesk4r8I:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=U3h0siRcp1o:Hsumesk4r8I:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/U3h0siRcp1o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/09/parsing-the-pubsubhubbub-notifications/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>rssCloud Meeting Wrap-up</title>
		<link>http://grack.com/blog/2009/09/09/rsscloud-meeting-wrap-up/</link>
		<comments>http://grack.com/blog/2009/09/09/rsscloud-meeting-wrap-up/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 04:04:48 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=364</guid>
		<description><![CDATA[I caught the audio of the rssCloud get-together in Berkeley tonight and it was very enlightening.  
One of the first points brought up was the problematic subscription API.  The subscription API requires that the endpoint live at the the same IP address as the system making the subscription request.  Dave Winer&#8217;s response [...]]]></description>
			<content:encoded><![CDATA[<p>I caught the audio of the rssCloud get-together in Berkeley tonight and it was very enlightening.  </p>
<p>One of the first points brought up was the problematic subscription API.  The subscription API requires that the endpoint live at the the same IP address as the system making the subscription request.  Dave Winer&#8217;s response was basically &#8220;we can&#8217;t and won&#8217;t change the protocol because it&#8217;s too widely deployed&#8221;.  He asked that anyone who wanted to change this fork the protocol.  Unfortunately, the lack of flexibility in assigning endpoint URLs makes this a very difficult sell for larger organizations where outgoing and incoming HTTP requests are routed differently.  I think this was a big mistake on Dave&#8217;s part here.  There&#8217;s a great opportunity to fix the glaring holes in the protocol (those 7.5 million blogs on Wordpress run the same WP rssCloud plugin that I do).</p>
<p>Some other interesting points were brought up, such as the lack of a block button (useless in a distributed web) and ideas for distributed identity.  Tunneling was quickly brought up, but the discussion moved on just as quickly.</p>
<p>At one point, someone asked about rssCloud support in Atom.  Dave Winer suggested using a namespace for the element and some discussion took place on it.  I&#8217;m not sure who brought it up, but it will likely be blogged and Dave will point to it to make it official.  Noone brought up the already-specified &lt;link rel= tag as an alternative, unfortunately.</p>
<p>Another interesting item brought up was that Wordpress <b>will</b> be supporting Pubsubhubbub as well at some point in the future.  It was more convenient to support rssCloud first, so they went with it.  Dave Winer and Matt Mullenwag joked that when they do, &#8220;just don&#8217;t say rsscloud is dead&#8221;.</p>
<p>More notes are available from <a href="http://twitter.com/susiewee">@susiewee</a>&#8217;s live twittering.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=mQhbEbPFdnA:fKYkdA0iOM0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=mQhbEbPFdnA:fKYkdA0iOM0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=mQhbEbPFdnA:fKYkdA0iOM0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=mQhbEbPFdnA:fKYkdA0iOM0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=mQhbEbPFdnA:fKYkdA0iOM0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=mQhbEbPFdnA:fKYkdA0iOM0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=mQhbEbPFdnA:fKYkdA0iOM0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=mQhbEbPFdnA:fKYkdA0iOM0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/mQhbEbPFdnA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/09/rsscloud-meeting-wrap-up/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A PubSubHubbub to XMPP Gateway</title>
		<link>http://grack.com/blog/2009/09/09/pubsubhubbub-to-xmpp-gateway/</link>
		<comments>http://grack.com/blog/2009/09/09/pubsubhubbub-to-xmpp-gateway/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 07:00:08 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=345</guid>
		<description><![CDATA[At first glance, both rssCloud and PubSubHubbub have an interesting shortcoming that makes them difficult to use for desktop feed readers.  Since both of them require HTTP callbacks to a publicly accessibly endpoint, a user is required to open up a port on their firewall.
It turns out that a subtle difference in the specifications [...]]]></description>
			<content:encoded><![CDATA[<p>At first glance, both rssCloud and PubSubHubbub have an interesting shortcoming that makes them difficult to use for desktop feed readers.  Since both of them require HTTP callbacks to a publicly accessibly endpoint, a user is required to open up a port on their firewall.</p>
<p>It turns out that a subtle difference in the specifications gives PubSubHubbub a big edge in this case.  While rssCloud requires your callback endpoint to live at the IP address you make your request from, PubSubHubbub <a href="http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.2.html#anchor5">allows you to subscribe any endpoint you wish</a> by specifying a <code>hub.callback</code> url.  </p>
<p>So how do we turn this into a real-time feed for desktop clients? Simple: we implement a PubSubHubbub subscriber on a publicly-available, always-on server that receives PubSubHubbub update events and wraps them in XMPP.  The XMPP events are transmitted to the desktop client, where it can then process them as if it received the callbacks directly.  </p>
<p>The server application doesn&#8217;t need to be smart.  Only the &#8220;subscribe&#8221; and &#8220;publish&#8221; modes of PubSubHubbub&#8217;s protocol are required.  All it needs to do is correctly route the update subscriptions to the correct XMPP account.  In fact, <a href="http://code.google.com/appengine/docs/java/xmpp/overview.html">with Google AppEngine&#8217;s new XMPP support</a>, you can this in a few dozen lines of code, as I&#8217;ve done here:</p>
<p><b><a href="http://pubsubhubbub-xmpp.appspot.com/">A PubSubHubbub to XMPP gateway, hosted on Google AppEngine</a></b></p>
<p>Try out the gateway by entering your XMPP ID on the main page.  This will give you a callback URL that you can use on <a href="http://pubsubhubbub.appspot.com/subscribe">Google&#8217;s main PubSubHubbub hub</a>.  Enter the URL for any PubSubHubbub-enabled field as the topic.  </p>
<p>The code is simple, though not very robust:</p>
<pre>
@SuppressWarnings("serial")
public class Subscribe extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setStatus(204);
		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));

		byte[] buffer = new byte[10 * 1024];
		req.getInputStream().read(buffer);
		xmpp.sendMessage(new MessageBuilder().withBody(
				"Got update: " + new String(buffer))
				.withRecipientJids(jid).build());
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setStatus(200);
		resp.setContentType("text/plain");

		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));

		if (req.getParameter("hub.mode").equals("subscribe"))
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Subscribing to " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());
		else
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Unsubscribing from " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());

		resp.getOutputStream().print(req.getParameter("hub.challenge"));
		resp.getOutputStream().flush();
	}
}
</pre>
<p><b>Postscript</b>: I really hope that PubSubHubbub gets a new name.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=qlw4q84ndPs:BLar3ODmbYw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=qlw4q84ndPs:BLar3ODmbYw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=qlw4q84ndPs:BLar3ODmbYw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=qlw4q84ndPs:BLar3ODmbYw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=qlw4q84ndPs:BLar3ODmbYw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=qlw4q84ndPs:BLar3ODmbYw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=qlw4q84ndPs:BLar3ODmbYw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=qlw4q84ndPs:BLar3ODmbYw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/qlw4q84ndPs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/09/pubsubhubbub-to-xmpp-gateway/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>PubSubHubbub vs. rssCloud</title>
		<link>http://grack.com/blog/2009/09/07/pubsubhubbub-vs-rsscloud/</link>
		<comments>http://grack.com/blog/2009/09/07/pubsubhubbub-vs-rsscloud/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 16:20:47 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=328</guid>
		<description><![CDATA[UPDATE: I&#8217;ve written a PubSubHubbub-to-XMPP gateway that solves some of the issues of running a real-time feed reader behind a firewall.
UPDATE 2 rssCloud has a serious vulnerability that needs to be addressed in the protocol. I&#8217;ve linked some security recommendations here that rssCloud hubs should implement as soon as possible.
These last few months have brought [...]]]></description>
			<content:encoded><![CDATA[<p><b>UPDATE:</b> I&#8217;ve <a href="http://grack.com/blog/2009/09/09/pubsubhubbub-to-xmpp-gateway/">written a PubSubHubbub-to-XMPP gateway</a> that solves some of the issues of running a real-time feed reader behind a firewall.</p>
<p><b>UPDATE 2</b> <b>rssCloud has a <a href="http://grack.com/blog/2009/09/10/serious-rsscloud-ddos-vulnerability/">serious vulnerability</a> that needs to be addressed in the protocol.</b> I&#8217;ve linked some <a href="http://grack.com/blog/2009/09/10/rsscloud-security-notifications/">security recommendations here</a> that rssCloud hubs should implement as soon as possible.</p>
<p>These last few months have brought us not one, but two RSS-to-real-time protocols: PubSubHubbub and rssCloud. While rssCloud has been &#8220;around&#8221; for a while, it never saw much adoption or interest until recently.</p>
<p>As a developer, the important question is: which of these two protocols should I focus on?</p>
<p>When you compare the two protocols technically, you find that there are some similarities (<b>UPDATE:</b> see <a href="http://jy.typepad.com/jy/2009/07/pubsubhubbub-rsscloud.html">here</a> for a more in-depth comparison of the APIs):</p>
<ul>
<li>Both PubSubHubbub and rssCloud allow the hub to live on a different server than the server that is providing RSS. This lets the complexity of both of these protocols to live in a black box somewhere else, managed by someone who cares more about getting the details right.</li>
<li>Both offer a fairly simple publisher &#8220;ping&#8221; notification for publishers. An rssCloud client can make a simple POST request to the specified cloud server, which is then verified by the server to ensure that the update was real (alternatively, rssCloud can use XML-RPC or SOAP, neither of which are in fashion right now).  PubSubHubbub has <a href="http://code.google.com/p/pubsubhubbub/source/browse/trunk/publisher_clients/php/library/publisher.php"> a very similar POST operation</a> with very similar semantics.</li>
<li>Both offer simple APIs on the hub for subscribing to feeds.  PubSubHubbub offers an unsubscribe option, while rssCloud times out subscriptions after 25 hours (the client is expected to re-subscribe after 24).</li>
</ul>
<p>There are some significant differences between the two protocols, however:</p>
<ul>
<li>PubSubHubbub supports RSS and Atom out of the box. rssCloud does not support Atom right now, as noone has defined how it would look inside of an Atom feed.</li>
<li>PubSubHubbub provides &#8220;fat pings&#8221; to clients, while rssCloud only provides basic notification updates. A PubSubHubbub subscriber can keep tabs on a feed entirely through the ping notifications, allowing it to skip polling of any feed that supports the update protocol. rssCloud requires the subscriber to re-poll the feed after receiving a ping. The &#8220;fat ping&#8221; has the advantage of saving the feed publisher bandwidth, since clients aren&#8217;t downloading the same repeated feed entries time after time, and potentially CPU cycles, since the feed publisher only has to generate a single feed output for the hub rather than for all of its clients (this can be mitigated by caching the generated feed). The fat ping requires more work on the part of the hub, however, as it needs to detect which parts of the feed have changed and push those parts into the subscriber notification dispatch queue.</li>
<li>PubSubHubbub lets you subscribe any endpoint you like (with some intelligence to prevent you spamming pings to arbitrary hosts).  rssCloud infers your endpoint hostname from the IP address of the request, requiring your subscription logic to live on the same servers as your ping endpoints. </li>
</ul>
<p>Back to the question: which of these protocols should I focus on?  The answer probably depends on what you are doing.</p>
<ul>
<li>If you are a publisher that publishers both RSS and Atom feeds, it&#8217;s trivial for you to support pinging rssCloud and PubSubHubbub hubs. There&#8217;s nothing stopping you from doing it now &#8211; just figure out which hubs to use.  If you use FeedBurner and PingShot, <a href="http://code.google.com/p/pubsubhubbub/wiki/HubbubAtGoogle">Google has already cloud-enabled your blog for you</a>.  If you want to control your own hub, you&#8217;ll probably want to pick an off-the-shelf one. PubSubHubbub is likely the best choice here as it both saves you bandwidth and gets you <a href="http://friendfeed.com/pubsubhubbub">real-time support in FriendFeed</a>.</li>
<li>If you are planning on writing a hub, you&#8217;ll probably want to start with rssCloud. Its implementation will be simpler than PubSubHubbub as all it does is redistribute ping notifications.</li>
<li>If you are a feed reader or a content spider, you&#8217;ll probably have to implement both. I believe that PubSubHubbub gives you the biggest bang for the buck now, as it&#8217;s supported by nearly all of the <a href="http://code.google.com/p/pubsubhubbub/wiki/HubbubAtGoogle">Google feed properties</a>: FeedBurner (the Atom/RSS intermediary choice for a significant number of self-hosted blogs), Blogger (millions of blogs) and Google Reader feeds. It&#8217;s also supported by LiveJournal (which lists 20+ million blogs on its homepage).  rssCloud is fairly new, but <a href="http://en.blog.wordpress.com/2009/09/07/rss-in-the-clouds/">it managed to score a big integration with wordpress.com</a> (7.5 million blogs, according to their own blog). Unfortunately, as not all of the big sites have implemented both, you&#8217;ll have to deal with two technologies for the time being.</li>
</ul>
<p>After researching both of the technologies in-depth, I&#8217;d say that PubSubHubbub is the better technology overall.  While more complex to implement for hubs, it offers far more to feed readers and publishers in terms of bandwidth savings and real-time updates.  For companies doing content analysis, PubSubHubbub is a huge win: it brings the power of the Twitter firehose to RSS. No matter which technology you choose, however, you&#8217;ll be getting your RSS feed updates far more often.  It might even allow the next real-time technology to be built on an open XML feed rather than a proprietary company&#8217;s servers.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=sNvk3S6fjig:k4Yyrcgx6uo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=sNvk3S6fjig:k4Yyrcgx6uo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=sNvk3S6fjig:k4Yyrcgx6uo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=sNvk3S6fjig:k4Yyrcgx6uo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=sNvk3S6fjig:k4Yyrcgx6uo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=sNvk3S6fjig:k4Yyrcgx6uo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=sNvk3S6fjig:k4Yyrcgx6uo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=sNvk3S6fjig:k4Yyrcgx6uo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/sNvk3S6fjig" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/09/07/pubsubhubbub-vs-rsscloud/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>A quieter window.name transport for IE</title>
		<link>http://grack.com/blog/2009/07/28/a-quieter-window-name-transport-for-ie/</link>
		<comments>http://grack.com/blog/2009/07/28/a-quieter-window-name-transport-for-ie/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 02:29:14 +0000</pubDate>
		<dc:creator>Matt Mastracci</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[clicks]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[navigation]]></category>

		<guid isPermaLink="false">http://grack.com/blog/?p=318</guid>
		<description><![CDATA[Using window.name as a transport for cooperative cross-domain communication is a reasonably well-known and well-researched technique. I came across it via two blog posts by members of the GWT community that were using it to submit GWT FormPanels to endpoints on other domains.
For our product, I&#8217;ve been looking at various ways we can offer RPC [...]]]></description>
			<content:encoded><![CDATA[<p>Using window.name as a transport for cooperative cross-domain communication is a reasonably well-known and well-researched technique. I came across it via two <a href="http://timepedia.blogspot.com/2008/07/cross-domain-formpanel-submissions-in.html">blog</a> <a href="http://development.lombardi.com/?p=611">posts </a>by members of the GWT community that were using it to submit GWT FormPanels to endpoints on other domains.</p>
<p>For our product, I&#8217;ve been looking at various ways we can offer RPC for our script when it is embedded in pages that don&#8217;t run on servers under our control.  Modern browsers, like Firefox 3.5 and Safari 4.0 support <a href="http://www.w3.org/TR/XMLHttpRequest2/">XMLHttpRequest Level 2</a>.  This standard allows you to make cross-domain calls, as long as the server responds with the appropriate <a href="http://dev.w3.org/2006/waf/access-control/#cross-origin-request">Access-Control header</a>.  Internet Explorer 8 supports a proprietary <a href="http://msdn.microsoft.com/en-us/library/cc288060%28VS.85%29.aspx">XDomainRequest</a> that offers similar support.</p>
<p>When we&#8217;re looking at &#8220;downlevel&#8221; browsers, like Firefox 2/3, Safari 2/3 and IE 6/7, the picture isn&#8217;t as clear. The window.name transport works well in every downlevel browser but IE6 and 7. In those IE versions, each RPC request made across the iframe is accompanied by an annoying click sound. As you can imagine, a page that has a few RPC requests that it requires to load will end up sounding like a machine gun. The reason for this is IE&#8217;s navigation sound which plays on every location change for any window, including iframes. The window.name transport requires a POST and a redirect back to complete the communication, triggering this audio UI.</p>
<p>I spent a few hours hammering away on the problem, trying to find a solution. It turns out that IE6 can be fooled with a &lt;bgsound&gt; element that masks the clicking sound. This doesn&#8217;t work in IE7, however. My research then lead to an interesting discovery: the GTalk team was using an ActiveX object named &#8220;htmlfile&#8221; to work around a similar problem: navigation sounds that would play during their COMET requests. The htmlfile object is basically a UI-disconnected HTML document that works, for the most part, the same way as a browser document. The question was now how to use this for a cross-domain request.</p>
<p>The interesting thing about the htmlfile ActiveX object is that not all HTML works as you&#8217;d expect it to. My first attempt was to use the htmlfile object, creating an iframe element with it, attaching it to the body (along with an accompanying form inside the htmlfile document) and POSTing the data. Unfortunately, I couldn&#8217;t get any of the events to register. The POST was happening, but none of the iframe&#8217;s onload events were firing:</p>
<pre>if ("ActiveXObject" in window) {
    var doc = new ActiveXObject("htmlfile");
    doc.open();
    doc.write("&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;");
    doc.close();
} else {
    var doc = document;
}

var iframe = doc.createElement('iframe');
doc.body.appendChild(iframe);
iframe.onload = ...
iframe.onreadystatechange = ...</pre>
<p>The second attempt was more fruitful. I tried writing the iframe out as part of the document, getting the iframe from the htmlfile and adding event handlers to this object. Success!  I managed to capture the onload event, read back the window.name value and, best of all, the browser did this silently:</p>
<pre>if ("ActiveXObject" in window) {
    var doc = new ActiveXObject("htmlfile");
    doc.open();
    doc.write("&lt;html&gt;&lt;body&gt;&lt;iframe id='iframe'&gt;&lt;/iframe&gt;&lt;/body&gt;&lt;/html&gt;");
    doc.close();
    var iframe = doc.getElementById('iframe');
} else {
    var doc = document;
    var iframe = doc.createElement('iframe');
    doc.body.appendChild(iframe);
}

iframe.onload = ...
iframe.onreadystatechange = ...</pre>
<p>I&#8217;m currently working on cleaning up the ugly proof-of-concept code to integrate as a transport in the Thrift-GWT RPC library I&#8217;m working on. This will allow us to transparently switch to the cross-domain transport when running offsite, without any visible side-effects to the user.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/grack?a=cQFvInMa3YU:ltZfrRODc7U:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/grack?i=cQFvInMa3YU:ltZfrRODc7U:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cQFvInMa3YU:ltZfrRODc7U:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/grack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cQFvInMa3YU:ltZfrRODc7U:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/grack?i=cQFvInMa3YU:ltZfrRODc7U:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cQFvInMa3YU:ltZfrRODc7U:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/grack?i=cQFvInMa3YU:ltZfrRODc7U:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/grack?a=cQFvInMa3YU:ltZfrRODc7U:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/grack?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/grack/~4/cQFvInMa3YU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grack.com/blog/2009/07/28/a-quieter-window-name-transport-for-ie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 3.735 seconds -->
