Revision 5c812d1b

b/api/emitter.py
3 3
# Copyright © 2010 Greek Research and Technology Network
4 4
#
5 5

  
6
import re
7 6
from xml.dom import minidom
8
from django.conf.urls.defaults import url
9 7
from piston.emitters import Emitter, Mimer
10
from piston.resource import Resource as BaseResource
11

  
12
_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?')
13

  
14
def parse_accept_header(value):
15
    """Parse an HTTP Accept header
16

  
17
    Returns an ordered by quality list of tuples (value, quality)
18
    """
19
    if not value:
20
        return []
21

  
22
    result = []
23
    for match in _accept_re.finditer(value):
24
        quality = match.group(2)
25
        if not quality:
26
            quality = 1
27
        else:
28
            quality = max(min(float(quality), 1), 0)
29
        result.append((match.group(1), quality))
30

  
31
    # sort by quality
32
    result.sort(key=lambda x: x[1])
33

  
34
    return result
35

  
36
class Resource(BaseResource):
37
    def determine_emitter(self, request, *args, **kwargs):
38
        """
39
        Override default emitter policy to account for Accept header
40

  
41
        emitter_format (.json or .xml suffix in URL) always takes precedence.
42

  
43
        After that, the Accept header is checked; if both JSON and XML are
44
        equally preferred, use JSON.
45

  
46
        If none of the two were provided, then use JSON as per the
47
        specification.
48
        """
49

  
50
        em = request.GET.get('format', 'json')
51
        if 'emitter_format' in kwargs and \
52
           kwargs["emitter_format"] is not None:
53
            em = kwargs.pop('emitter_format')
54
        elif 'HTTP_ACCEPT' in request.META:
55
            accepts = parse_accept_header(request.META['HTTP_ACCEPT'])
56
            for content_type, quality in accepts:
57
                if content_type == 'application/json':
58
                    break
59
                elif content_type == 'application/xml':
60
                    em = request.GET.get('format', 'xml')
61
                    break
62

  
63
        return em
64 8

  
65 9
class OSXMLEmitter(Emitter):
66 10
    """
......
118 62

  
119 63
Emitter.register('xml', OSXMLEmitter, 'application/xml')
120 64
Mimer.register(lambda *a: None, ('application/xml',))
121

  
122
def url_with_format(regex, *args, **kwargs):
123
    """
124
    An extended url() that adds an .json/.xml suffix to the end to avoid DRY
125
    """
126
    if regex[-1] == '$' and regex[-2] != '\\':
127
        regex = regex[:-1]
128
    regex = regex + r'(\.(?P<emitter_format>json|xml))?$'
129
    return url(regex, *args, **kwargs)
b/api/resource.py
1
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
2
#
3
# Copyright © 2010 Greek Research and Technology Network
4
#
5

  
6
from piston.resource import Resource as BaseResource
7
from synnefo.helpers import parse_accept_header
8

  
9
class Resource(BaseResource):
10
    def determine_emitter(self, request, *args, **kwargs):
11
        """
12
        Override default emitter policy to account for Accept header
13

  
14
        emitter_format (.json or .xml suffix in URL) always takes precedence.
15

  
16
        After that, the Accept header is checked; if both JSON and XML are
17
        equally preferred, use JSON.
18

  
19
        If none of the two were provided, then use JSON as per the
20
        specification.
21
        """
22

  
23
        em = request.GET.get('format', 'json')
24
        if 'emitter_format' in kwargs and \
25
           kwargs["emitter_format"] is not None:
26
            em = kwargs.pop('emitter_format')
27
        elif 'HTTP_ACCEPT' in request.META:
28
            accepts = parse_accept_header(request.META['HTTP_ACCEPT'])
29
            for content_type, quality in accepts:
30
                if content_type == 'application/json':
31
                    break
32
                elif content_type == 'application/xml':
33
                    em = request.GET.get('format', 'xml')
34
                    break
35

  
36
        return em
37

  
b/api/urls.py
4 4
#
5 5

  
6 6
from django.conf.urls.defaults import *
7
from synnefo.api.emitter import Resource, url_with_format
7
from synnefo.helpers import url_with_format
8
from synnefo.api.resource import Resource
8 9
from synnefo.api.handlers import *
9 10
from synnefo.api.authentication import TokenAuthentication
10 11
from synnefo.api.faults import fault
b/helpers.py
1
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
2
#
3
# Copyright © 2010 Greek Research and Technology Network
4
#
5

  
6
import re
7
from django.conf.urls.defaults import url
8

  
9
_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?')
10

  
11
def parse_accept_header(value):
12
    """Parse an HTTP Accept header
13

  
14
    Returns an ordered by quality list of tuples (value, quality)
15
    """
16
    if not value:
17
        return []
18

  
19
    result = []
20
    for match in _accept_re.finditer(value):
21
        quality = match.group(2)
22
        if not quality:
23
            quality = 1
24
        else:
25
            quality = max(min(float(quality), 1), 0)
26
        result.append((match.group(1), quality))
27

  
28
    # sort by quality
29
    result.sort(key=lambda x: x[1])
30

  
31
    return result
32

  
33
def url_with_format(regex, *args, **kwargs):
34
    """
35
    An extended url() that adds an .json/.xml suffix to the end to avoid DRY
36
    """
37
    if regex[-1] == '$' and regex[-2] != '\\':
38
        regex = regex[:-1]
39
    regex = regex + r'(\.(?P<emitter_format>json|xml))?$'
40
    return url(regex, *args, **kwargs)

Also available in: Unified diff