123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- # -*- coding: utf-8 -*-
- """
- werkzeug.useragents
- ~~~~~~~~~~~~~~~~~~~
- This module provides a helper to inspect user agent strings. This module
- is far from complete but should work for most of the currently available
- browsers.
- :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
- :license: BSD, see LICENSE for more details.
- """
- import re
- class UserAgentParser(object):
- """A simple user agent parser. Used by the `UserAgent`."""
- platforms = (
- ('cros', 'chromeos'),
- ('iphone|ios', 'iphone'),
- ('ipad', 'ipad'),
- (r'darwin|mac|os\s*x', 'macos'),
- ('win', 'windows'),
- (r'android', 'android'),
- ('netbsd', 'netbsd'),
- ('openbsd', 'openbsd'),
- ('freebsd', 'freebsd'),
- ('dragonfly', 'dragonflybsd'),
- ('(sun|i86)os', 'solaris'),
- (r'x11|lin(\b|ux)?', 'linux'),
- (r'nintendo\s+wii', 'wii'),
- ('irix', 'irix'),
- ('hp-?ux', 'hpux'),
- ('aix', 'aix'),
- ('sco|unix_sv', 'sco'),
- ('bsd', 'bsd'),
- ('amiga', 'amiga'),
- ('blackberry|playbook', 'blackberry'),
- ('symbian', 'symbian')
- )
- browsers = (
- ('googlebot', 'google'),
- ('msnbot', 'msn'),
- ('yahoo', 'yahoo'),
- ('ask jeeves', 'ask'),
- (r'aol|america\s+online\s+browser', 'aol'),
- ('opera', 'opera'),
- ('edge', 'edge'),
- ('chrome', 'chrome'),
- ('seamonkey', 'seamonkey'),
- ('firefox|firebird|phoenix|iceweasel', 'firefox'),
- ('galeon', 'galeon'),
- ('safari|version', 'safari'),
- ('webkit', 'webkit'),
- ('camino', 'camino'),
- ('konqueror', 'konqueror'),
- ('k-meleon', 'kmeleon'),
- ('netscape', 'netscape'),
- (r'msie|microsoft\s+internet\s+explorer|trident/.+? rv:', 'msie'),
- ('lynx', 'lynx'),
- ('links', 'links'),
- ('Baiduspider', 'baidu'),
- ('bingbot', 'bing'),
- ('mozilla', 'mozilla')
- )
- _browser_version_re = r'(?:%s)[/\sa-z(]*(\d+[.\da-z]+)?'
- _language_re = re.compile(
- r'(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|'
- r'(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)'
- )
- def __init__(self):
- self.platforms = [(b, re.compile(a, re.I)) for a, b in self.platforms]
- self.browsers = [(b, re.compile(self._browser_version_re % a, re.I))
- for a, b in self.browsers]
- def __call__(self, user_agent):
- for platform, regex in self.platforms:
- match = regex.search(user_agent)
- if match is not None:
- break
- else:
- platform = None
- for browser, regex in self.browsers:
- match = regex.search(user_agent)
- if match is not None:
- version = match.group(1)
- break
- else:
- browser = version = None
- match = self._language_re.search(user_agent)
- if match is not None:
- language = match.group(1) or match.group(2)
- else:
- language = None
- return platform, browser, version, language
- class UserAgent(object):
- """Represents a user agent. Pass it a WSGI environment or a user agent
- string and you can inspect some of the details from the user agent
- string via the attributes. The following attributes exist:
- .. attribute:: string
- the raw user agent string
- .. attribute:: platform
- the browser platform. The following platforms are currently
- recognized:
- - `aix`
- - `amiga`
- - `android`
- - `blackberry`
- - `bsd`
- - `chromeos`
- - `dragonflybsd`
- - `freebsd`
- - `hpux`
- - `ipad`
- - `iphone`
- - `irix`
- - `linux`
- - `macos`
- - `netbsd`
- - `openbsd`
- - `sco`
- - `solaris`
- - `symbian`
- - `wii`
- - `windows`
- .. attribute:: browser
- the name of the browser. The following browsers are currently
- recognized:
- - `aol` *
- - `ask` *
- - `baidu` *
- - `bing` *
- - `camino`
- - `chrome`
- - `firefox`
- - `galeon`
- - `google` *
- - `kmeleon`
- - `konqueror`
- - `links`
- - `lynx`
- - `mozilla`
- - `msie`
- - `msn`
- - `netscape`
- - `opera`
- - `safari`
- - `seamonkey`
- - `webkit`
- - `yahoo` *
- (Browsers marked with a star (``*``) are crawlers.)
- .. attribute:: version
- the version of the browser
- .. attribute:: language
- the language of the browser
- """
- _parser = UserAgentParser()
- def __init__(self, environ_or_string):
- if isinstance(environ_or_string, dict):
- environ_or_string = environ_or_string.get('HTTP_USER_AGENT', '')
- self.string = environ_or_string
- self.platform, self.browser, self.version, self.language = \
- self._parser(environ_or_string)
- def to_header(self):
- return self.string
- def __str__(self):
- return self.string
- def __nonzero__(self):
- return bool(self.browser)
- __bool__ = __nonzero__
- def __repr__(self):
- return '<%s %r/%s>' % (
- self.__class__.__name__,
- self.browser,
- self.version
- )
- # conceptionally this belongs in this module but because we want to lazily
- # load the user agent module (which happens in wrappers.py) we have to import
- # it afterwards. The class itself has the module set to this module so
- # pickle, inspect and similar modules treat the object as if it was really
- # implemented here.
- from werkzeug.wrappers import UserAgentMixin # noqa
|