Back to index

moin  1.9.0~rc2
useragents.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     werkzeug.useragents
00004     ~~~~~~~~~~~~~~~~~~~
00005 
00006     This module provides a helper to inspect user agent strings.  This module
00007     is far from complete but should work for most of the currently available
00008     browsers.
00009 
00010 
00011     :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
00012     :license: BSD, see LICENSE for more details.
00013 """
00014 import re
00015 
00016 
00017 class UserAgentParser(object):
00018     """A simple user agent parser.  Used by the `UserAgent`."""
00019 
00020     platforms = (
00021         ('iphone', 'iphone'),
00022         (r'darwin|mac|os\s*x', 'macos'),
00023         ('win', 'windows'),
00024         (r'android', 'android'),
00025         (r'x11|lin(\b|ux)?', 'linux'),
00026         ('(sun|i86)os', 'solaris'),
00027         (r'nintendo\s+wii', 'wii'),
00028         ('irix', 'irix'),
00029         ('hp-?ux', 'hpux'),
00030         ('aix', 'aix'),
00031         ('sco|unix_sv', 'sco'),
00032         ('bsd', 'bsd'),
00033         ('amiga', 'amiga')
00034     )
00035     browsers = (
00036         ('googlebot', 'google'),
00037         ('msnbot', 'msn'),
00038         ('yahoo', 'yahoo'),
00039         ('ask jeeves', 'ask'),
00040         (r'aol|america\s+online\s+browser', 'aol'),
00041         ('opera', 'opera'),
00042         ('chrome', 'chrome'),
00043         ('firefox|firebird|phoenix|iceweasel', 'firefox'),
00044         ('galeon', 'galeon'),
00045         ('safari', 'safari'),
00046         ('webkit', 'webkit'),
00047         ('camino', 'camino'),
00048         ('konqueror', 'konqueror'),
00049         ('k-meleon', 'kmeleon'),
00050         ('netscape', 'netscape'),
00051         (r'msie|microsoft\s+internet\s+explorer', 'msie'),
00052         ('lynx', 'lynx'),
00053         ('links', 'links'),
00054         ('seamonkey|mozilla', 'seamonkey')
00055     )
00056 
00057     _browser_version_re = r'(?:%s)[/\sa-z(]*(\d+[.\da-z]+)?(?i)'
00058     _language_re = re.compile(
00059         r'(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|'
00060         r'(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)'
00061     )
00062 
00063     def __init__(self):
00064         self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms]
00065         self.browsers = [(b, re.compile(self._browser_version_re % a))
00066                          for a, b in self.browsers]
00067 
00068     def __call__(self, user_agent):
00069         for platform, regex in self.platforms:
00070             match = regex.search(user_agent)
00071             if match is not None:
00072                 break
00073         else:
00074             platform = None
00075         for browser, regex in self.browsers:
00076             match = regex.search(user_agent)
00077             if match is not None:
00078                 version = match.group(1)
00079                 break
00080         else:
00081             browser = version = None
00082         match = self._language_re.search(user_agent)
00083         if match is not None:
00084             language = match.group(1) or match.group(2)
00085         else:
00086             language = None
00087         return platform, browser, version, language
00088 
00089 
00090 class UserAgent(object):
00091     """Represents a user agent.  Pass it a WSGI environment or a user agent
00092     string and you can inspect some of the details from the user agent
00093     string via the attributes.  The following attributes exist:
00094 
00095     .. attribute:: string
00096 
00097        the raw user agent string
00098 
00099     .. attribute:: platform
00100 
00101        the browser platform.  The following platforms are currently
00102        recognized:
00103 
00104        -   `aix`
00105        -   `amiga`
00106        -   `android`
00107        -   `bsd`
00108        -   `hpux`
00109        -   `iphone`
00110        -   `irix`
00111        -   `linux`
00112        -   `macos`
00113        -   `sco`
00114        -   `solaris`
00115        -   `wii`
00116        -   `windows`
00117 
00118     .. attribute:: browser
00119 
00120         the name of the browser.  The following browsers are currently
00121         recognized:
00122 
00123         -   `aol` *
00124         -   `ask` *
00125         -   `camino`
00126         -   `chrome`
00127         -   `firefox`
00128         -   `galeon`
00129         -   `google` *
00130         -   `kmeleon`
00131         -   `konqueror`
00132         -   `links`
00133         -   `lynx`
00134         -   `msie`
00135         -   `msn`
00136         -   `netscape`
00137         -   `opera`
00138         -   `safari`
00139         -   `seamonkey`
00140         -   `webkit`
00141         -   `yahoo` *
00142 
00143         (Browsers maked with a star (``*``) are crawlers.)
00144 
00145     .. attribute:: version
00146 
00147         the version of the browser
00148 
00149     .. attribute:: language
00150 
00151         the language of the browser
00152     """
00153     _parser = UserAgentParser()
00154 
00155     def __init__(self, environ_or_string):
00156         if isinstance(environ_or_string, dict):
00157             environ_or_string = environ_or_string.get('HTTP_USER_AGENT', '')
00158         self.string = environ_or_string
00159         self.platform, self.browser, self.version, self.language = \
00160             self._parser(environ_or_string)
00161 
00162     def to_header(self):
00163         return self.string
00164 
00165     def __str__(self):
00166         return self.string
00167 
00168     def __nonzero__(self):
00169         return bool(self.browser)
00170 
00171     def __repr__(self):
00172         return '<%s %r/%s>' % (
00173             self.__class__.__name__,
00174             self.browser,
00175             self.version
00176         )
00177 
00178 
00179 # conceptionally this belongs in this module but because we want to lazily
00180 # load the user agent module (which happens in wrappers.py) we have to import
00181 # it afterwards.  The class itself has the module set to this module so
00182 # pickle, inspect and similar modules treat the object as if it was really
00183 # implemented here.
00184 from werkzeug.wrappers import UserAgentMixin