Monday, November 08, 2010 at 12:05 AM.

system.verbs.builtins.radio.webServer.parseAcceptHeader

on parseAcceptHeader (pta) {
	<<Changes:
		<<7/28/01; 12:52:28 AM by JES
			<<Created: Returns a sorted table of arrays of mime-types, based on the 'q' value and specificity of the type.
				<<The names of the arrays are the q values, highest being the types with the highest priority.
				<<[type]/* is always prioritized just below the lowest priority mime type of the same [type] unless q is specified, in which case it's the lowest priority type for a given q value.
				<<*/* is always lowest priority, when present.
				<<See HTTP 1.1 spec:
					<<http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
	
	local (t); new (tableType, @t);
	local (smallestQTable); new (tableType, @smallestQTable);
	
	local (ct = string.countFields (pta^.requestHeaders.accept, ','));
	for i = ct downto 1 { //parse the individual types
		local (typeSpec = string.nthField (pta^.requestHeaders.accept, ',', i));
		local (theType = string.trimWhiteSpace (string.nthField (typeSpec, ';', 1)));
		
		local (q = "1.00", flQSpecified = false);
		local (majorType = string.nthField (theType, '/', 1));
		local (subType = string.nthField (theType, '/', 2));
		local (paramString = "");
		
		local (ctParams = string.countFields (typeSpec, ';') - 1);
		for j = 1 to ctParams { //parse params
			local (oneParam = string.trimWhiteSpace (string.nthField (typeSpec, ';', j + 1)));
			local (name = string.trimWhiteSpace (string.nthField (oneParam, '=', 1)));
			local (val = string.trimWhiteSpace (string.nthField (oneParam, '=', 2)));
			if string.lower (name) == "q" { //normalize the value of the q parameter
				if not (val contains '.') { //it's a whole integer -- add the decimal part: .00
					val = val + ".00"};
				if val beginsWith '.' { //add the leading zero
					val = "0" + val};
				while sizeOf (val) < 4 { //pad the end of the mantissa to two digits
					val = val + "0"};
				q = val; flQSpecified = true}
			else { //add the params to the paramString, which is appended to theType, when added to the table
				paramString = paramString + ";" + name + "=" + val}};
		if defined (smallestQTable.[majorType]) {
			if smallestQTable.[majorType] > q {
				smallestQTable.[majorType] = q}}
		else { //create it
			smallestQTable.[majorType] = q};
		if subType == "*" { //set q to the lowest known q for this majorType
			if not flQSpecified {
				if theType == "*/*" {
					q = "0.00"};
				if smallestQTable contains majorType {
					q = smallestQTable[majorType]}}};
		
		local (typeAndParams = theType + paramString);
		if not defined (t.[q]) {
			t.[q] = {}};
		if string (t.[q]) contains ("\"" + majorType + "/*\"") { //insert at the begining of the list
			<<Known bug:
				<<There's a long-shot possibility that's ignored here: if a given q's list already has the following:
					<<{"text/html;level=1", "text/*"}
				<<And this type is text/html, then you'll get:
					<<{"text/html", "text/html;level=1", "text/*"}
				<<The order is wrong: the first and second list elements should be reversed.
			t.[q] = typeAndParams + t.[q]}
		else { //params make a type more specific
			if paramString == "" and ( string (t.[q]) contains ("\"" + theType + "\"") ) {
				t.[q] = t.[q] + typeAndParams}
			else { //ithis type is more specific than one that's already defined with this q value
				t.[q] = typeAndParams + t.[q]}}};
	return (t)}
<<bundle //testing
	<<local (t); new (tableType, @t)
	<<new (tableType, @t.requestHeaders)
	<<t.requestHeaders.accept = "audio/*; q=0.2, audio/basic"
	<<t.requestHeaders.accept = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"
	<<t.requestHeaders.accept = "text/*, text/html, text/html;level=1, */*"
	<<t.requestHeaders.accept = "text/*;q=0.3, text/html, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5"
	<<local (pta = @t)
	<<temp.acceptTypes = parseAcceptHeader (pta)
	<<edit (@temp.acceptTypes); op.fullExpand (); window.zoom (window.frontmost ())



This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.