There is a bug in Firefox (even in the new betas and in minefield releases) which prevents the caching of certain files because of the algorithm for creating a key in their cache hash. Here is a link to the source code of the function.
I want to ensure that all of my site's files can be cached. However, I do not understand why their hashing function fails to create unique keys for distinct urls. I am hoping someone can describe this malfunction in psuedo-code or java.
It would be good to create a utility for developers to ensure unique urls until this bug is fixed.
EDIT: There have been some very helpful answers, however, I need more step-by-step help to create a utility to check for these cache mixups. It would be great to get some java code which can reproduce the keys that firefox is creating. Therefore, the opening of a bounty on this question.
EDIT 2: Here is a partially working java port (written using processing). Note the tests at the bottom; the first three work as expected, but the others do not. I suspect something regarding signed / unsigned ints. Suggestions?
//
// the bad collision function
// http://mxr.mozilla.org/mozilla/source/netwerk/cache/src/nsDiskCacheDevice.cpp#240
//
//248 PLDHashNumber
//249 nsDiskCache::Hash(const char * key)
//250 {
//251 PLDHashNumber h = 0;
//252 for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
//253 h = PR_ROTATE_LEFT32(h, 4) ^ *s;
//254 return (h == 0 ? ULONG_MAX : h);
//255 }
//
// a java port...
//
String getHash( String url )
{
//get the char array for the url string
char[] cs = getCharArray( url );
int h = 0;
//for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
for ( int i=0; i < cs.length; i++ )
{ h = PR_ROTATE_LEFT32(h, 4) ^ cs[i];
}
//looks like the examples above return something in hex.
//if we get matching ints, that is ok by me.
//but for fun, lets try to hex the return vals?
String hexVal = hex( h );
return hexVal;
}
char[] getCharArray( String s )
{
char[] cs = new char[s.length()];
for (int i=0; i<s.length(); i++)
{
char c = s.charAt(i);
cs[i] = c;
}
return cs;
}
//
// how to PR_ROTATE_LEFT32
//
//110 /*
//111 ** Macros for rotate left and right. The argument 'a' must be an unsigned
//112 ** 32-bit integer type such as PRUint32.
//113 **
//114 ** There is no rotate operation in the C Language, so the construct
//115 ** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert
//116 ** this to a rotate instruction, but MSVC doesn't without a little help.
//117 ** To get MSVC to generate a rotate instruction, we have to use the _rotl
//118 ** or _rotr intrinsic and use a pragma to make it inline.
//119 **
//120 ** Note: MSVC in VS2005 will do an inline rotate instruction on the above
//121 ** construct.
//122 */
//...
//128 #define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits)
//return an int (32 bit). what do we do with the 'bits' parameter? ignore?
int PR_ROTATE_LEFT32( int a, int bits )
{ return (a << 4) | (a >> (32-bits));
}
//
// examples of some colliding hashes
// https://bugzilla.mozilla.org/show_bug.cgi?id=290032#c5
//
//$ ./hashit "ABA/xxx.aba"
//8ffac222
//$ ./hashit "XyZ/xxx.xYz"
//8ffac222
//$ ./hashit "CSS/xxx.css"
//8ffac222
//$ ./hashit "JPG/xxx.jpg"
//8ffac222
//$ ./hashit modules_newsfeeds/MenuBar/MenuBar.css
//15c23729
//$ ./hashit modules_newsfeeds/ListBar/ListBar.css
//15c23729
//$ ./hashit modules_newsfeeds/MenuBar/MenuBar.js
//a15c23e5
//$ ./hashit modules_newsfeeds/ListBar/ListBar.js
//a15c23e5
//
// our attempt at porting this algorithm to java...
//
void setup( )
{
String a = "ABA/xxx.aba";
String b = "CSS/xxx.css";
String c = "CSS/xxx.css";
String d = "JPG/xxx.jpg";
println( getHash(a) ); //yes 8ffac222
println( getHash(b) ); //yes 8ffac222
println( getHash(c) ); //yes 8ffac222
println( getHash(d) ); //no [??] FFFFFF98, not 8ffac222
println( "-----" );
String e = "modules_newsfeeds/MenuBar/MenuBar.css";
String f = "modules_newsfeeds/ListBar/ListBar.css";
println( getHash(e) ); //no [??] FFFFFF8C, not 15c23729
println( getHash(f) ); //no [??] FFFFFF8C, not 15c23729
println( "-----" );
String g = "modules_newsfeeds/MenuBar/MenuBar.js";
String h = "modules_newsfeeds/ListBar/ListBar.js";
println( getHash(g) ); //yes [??] FFFFFF8C, not a15c23e5
println( getHash(h) ); //yes [??] FFFFFF8C, not a15c23e5
}