from string import lower def webkit_workaround(bestq, result): """The next part is a workaround, to avoid the problem, webkit browsers generate, by putting application/xml as the first item in theire accept headers The algorithm changes the order of the best quality fields, if xml appears to be the first entry of best quality and eigther an xhtml or html emtry is, found with also best quality, to xml beeing the last entry of best quality. If only an xhtml entry is found in bestq, but the request contains an html entry with lower rating, it rearranges the html entry to be directly in front of xml. """ if result[0][0] == "application/xml": bestresult = [] length = 0 hashtml = False hasxhtml = False idxhtml = None i = 0 for mediatype in result: if mediatype[2] == bestq: bestresult.append(mediatype) length = length + 1 if not hasxhtml and lower(mediatype[0]) == "application/xhtml+xml": hasxhtml = True if not hashtml and lower(mediatype[0]) == "text/html": hashtml = True if lower(mediatype[0]) == "text/html": idxhtml = i i = i+1 if (hashtml or hasxhtml) and length > 1: newresult = [] newresult.extend(bestresult[1:]) if not hashtml and idxhtml: htmltype = result.pop(idxhtml) htmltype = (htmltype[0], htmltype[1], bestq) newresult.append(htmltype) newresult.append(bestresult[0]) newresult.extend(result[length:]) result = newresult return result def parse_accept_header(accept): """Parse the Accept header *accept*, returning a list with pairs of (media_type, q_value), ordered by q values. """ bestq = 0.0 result = [] for media_range in accept.split(","): parts = media_range.split(";") media_type = parts.pop(0) media_params = [] q = 1.0 for part in parts: (key, value) = part.lstrip().split("=", 1) if key == "q": q = float(value) else: media_params.append((key, value)) if q > bestq: bestq = q result.append((media_type, tuple(media_params), q)) result.sort(lambda x, y: -cmp(x[2], y[2])) result = webkit_workaround(bestq, result) return result class AcceptMiddleware(object): def process_request(self, request): accept = parse_accept_header(request.META.get("HTTP_ACCEPT", "")) request.accept = accept request.accepted_types = map(lambda (t, p, q): t, accept)