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.