Commits

Ben Bangert committed 7c5b8ca Merge

Merging mimehelper

Comments (0)

Files changed (3)

tests/test_mimetypes.py

+from webhelpers.mimehelper import MIMETypes
+from util import test_environ
+
+def setup():
+    MIMETypes.init()
+
+def test_register_alias():
+    MIMETypes.add_alias('html', 'text/html')
+    assert MIMETypes.aliases['html'] == 'text/html'
+    
+def test_usage():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test.html'
+    m = MIMETypes(environ)
+    assert m.mimetype('html') == 'text/html'
+
+def test_root_path():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/'
+    environ['HTTP_ACCEPT'] = 'text/html, application/xml'
+    m = MIMETypes(environ)
+    assert m.mimetype('text/html') == 'text/html'
+
+def test_with_extention():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test.xml'
+    environ['HTTP_ACCEPT'] = 'text/html, application/xml'
+    m = MIMETypes(environ)
+    assert m.mimetype('text/html') == False
+    assert m.mimetype('application/xml') == 'application/xml'
+
+def test_with_unregistered_extention():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test.iscool'
+    environ['HTTP_ACCEPT'] = 'application/xml'
+    m = MIMETypes(environ)
+    assert m.mimetype('text/html') == False
+    assert m.mimetype('application/xml') == 'application/xml'
+
+def test_with_no_extention():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test'
+    environ['HTTP_ACCEPT'] = 'application/xml'
+    m = MIMETypes(environ)
+    assert m.mimetype('text/html') == False
+    assert m.mimetype('application/xml') == 'application/xml'
+    
+def test_with_no_extention_and_no_accept():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test'
+    m = MIMETypes(environ)
+    assert m.mimetype('html') == 'text/html'
+
+def test_with_text_star_accept():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test.iscool'
+    environ['HTTP_ACCEPT'] = 'text/*'
+    m = MIMETypes(environ)
+    assert m.mimetype('text/html') == 'text/html'
+
+def test_with_star_star_accept():
+    environ = test_environ()
+    environ['PATH_INFO'] = '/test.iscool'
+    environ['HTTP_ACCEPT'] = '*/*'
+    m = MIMETypes(environ)
+    assert m.mimetype('application/xml') == 'application/xml'
 
 import routes
 
+def test_environ():
+    return {
+        'HTTP_HOST': 'bob.local:5000',
+        'PATH_INFO': '/test',
+        'QUERY_STRING': 'test=webhelpers&framework=pylons',
+        'REQUEST_METHOD': 'GET',
+        'SERVER_NAME': '0.0.0.0',
+        'SCRIPT_NAME': '',
+        'pylons.environ_config': dict(session='test.session'),
+        'test.session': {},
+        'wsgi.multiprocess': False,
+        'wsgi.multithread': True,
+        'wsgi.run_once': False,
+        'wsgi.url_scheme': 'http'
+        }
+
+
 class WebHelpersTestCase(TestCase):
     """Establishes a faux-environment for tests"""
     def test_environ(self):

webhelpers/mimehelper.py

+"""MIMEType helpers"""
+import mimetypes
+import webob
+
+class MIMETypes(object):
+    """MIMETypes registration mapping
+    
+    The MIMETypes object class provides a single point to hold onto all
+    the registered mimetypes, and their association extensions. It's
+    used by the mimetypes function to determine the appropriate content
+    type to return to a client.
+    
+    """
+    aliases = {}
+    
+    def init(cls):
+        """Loads a default mapping of extensions and mimetypes
+        
+        These are suitable for most web applications by default. 
+        Additional types can be added with the using the mimetypes
+        module.
+        
+        """
+        mimetypes.init()
+    init = classmethod(init)
+    
+    def add_alias(cls, alias, mimetype):
+        """Creates a MIMEType alias to a full mimetype
+        
+        These aliases may not include /'s. Examples include 
+        html->text/html, xml->application/xml."""
+        if '/' in alias:
+            raise ValueError("MIMEType aliases may not contain '/'")
+        cls.aliases[alias] = mimetype
+    add_alias = classmethod(add_alias)
+    
+    def __init__(self, environ):
+        self.env = environ
+    
+    def _set_responce_conetent_type(self, mimetype):
+        if 'pylons.pylons' in self.env:
+            self.env['pylons.pylons'].response.content_type = mimetype
+        return mimetype
+        
+    def mimetype(self, content_type):
+        """Check the PATH_INFO of the current request and clients HTTP Accept 
+        to attempt to use the appropriate mime-type
+    
+        If a content-type is matched, the appropriate response content
+        type is set as well.
+                
+        This works best with URLs that end in extensions that differentiate
+        content-type. Examples: http://example.com/example, 
+        http://example.com/example.xml, http://example.com/example.csv
+                
+        Since browsers generally allow for any content-type, but should be
+        sent HTML when possible, the html mimetype check should always come
+        first, as shown in the example below.
+        
+        Example::
+            # some code likely in environment.py
+            
+            MIMETypes.init()
+            MIMETypes.alias('html', 'text/html')
+            MIMETypes.alias('xml', 'application/xml')
+            MIMETypes.alias('csv', 'text/csv')
+            
+            def somaction(self):
+                # prepare a bunch of data
+                # ......
+                
+                # prepare MIMETypes object
+                m = MIMETypes(request.environ)
+                
+                if m.mimetype('html'):
+                    return render('/some/template.html')
+                elif m.mimetype('atom'):
+                    return render('/some/xml_template.xml')
+                elif m.mimetype('csv'):
+                    # write the data to a csv file
+                    return csvfile
+                else:
+                    abort(404)
+        
+        """
+
+        if content_type in MIMETypes.aliases:
+            content_type = MIMETypes.aliases[content_type]
+        path = self.env['PATH_INFO']
+        guess_from_url = mimetypes.guess_type(path)[0]
+        possible_from_accept_header = None
+        has_extension = False
+        if len(path.split('/')) > 1:
+            last_part = path.split('/')[-1]
+            if '.' in last_part:
+                has_extension = True
+        if 'HTTP_ACCEPT' in self.env:
+            possible_from_accept_header = webob.acceptparse.MIMEAccept('ACCEPT', 
+                self.env['HTTP_ACCEPT'])
+        if has_extension == False:
+            if possible_from_accept_header is None:
+                return self._set_responce_conetent_type(content_type)
+            elif mimetype in possible_from_accept_header:
+                return self._set_responce_conetent_type(content_type)
+            else:
+                return False
+        if content_type == guess_from_url:
+            # Guessed same mimetype
+            return self._set_responce_conetent_type(content_type)
+        elif guess_from_url is None and content_type in possible_from_accept_header:
+            return self._set_responce_conetent_type(content_type)
+        else:
+            return False