Login

Improved Accept middleware with webkit workaround

Author:
raven_nevermore
Posted:
November 15, 2010
Language:
Python
Version:
1.2
Score:
0 (after 0 ratings)

An accept middleware, which is based on the code of http://djangosnippets.org/snippets/1042/ but adds a workaround for the buggy accept header, sent from webkit browsers such as safari and chrome.

The workaround affects any accept header, that has xml and (x)html in the best q, but also the xml mediatype at first place in the list.

If this is the case, the header is rearanged, by shifting the xml mediatype to become the last element of the best quality entries in the header.

If the workaround did manipulate the header, and there is a html entry in the list with lower quality as an xhtml entry that is also in the list (with best q), then the html entry is also raised in q to be one entry in front of xml.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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)
        

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 12 months ago

Comments

Please login first before commenting.