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.