Files
deb-python-autobahn/autobahn/websocket/useragent.py
2015-03-10 00:15:32 +01:00

311 lines
10 KiB
Python

###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Tavendo GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################
import re
__all__ = ("lookupWsSupport",)
UA_FIREFOX = re.compile(".*Firefox/(\d*).*")
UA_CHROME = re.compile(".*Chrome/(\d*).*")
UA_CHROMEFRAME = re.compile(".*chromeframe/(\d*).*")
UA_WEBKIT = re.compile(".*AppleWebKit/([0-9+\.]*)\w*.*")
UA_WEBOS = re.compile(".*webos/([0-9+\.]*)\w*.*")
UA_HPWEBOS = re.compile(".*hpwOS/([0-9+\.]*)\w*.*")
UA_DETECT_WS_SUPPORT_DB = {}
# Chrome =============================================================
# Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11
# Chrome Frame =======================================================
# IE6 on Windows with Chrome Frame
# Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; chromeframe/11.0.660.0)
# Firefox ============================================================
# Windows 7 64 Bit
# Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0a2) Gecko/20120227 Firefox/12.0a2
# Android ============================================================
# Firefox Mobile
# Mozilla/5.0 (Android; Linux armv7l; rv:10.0.2) Gecko/20120215 Firefox/10.0.2 Fennec/10.0.2
# Chrome for Android (on ICS)
# Mozilla/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build/IML74K) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7
# Android builtin browser
# Samsung Galaxy Tab 1
# Mozilla/5.0 (Linux; U; Android 2.2; de-de; GT-P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
# Samsung Galaxy S
# Mozilla/5.0 (Linux; U; Android 2.3.3; de-de; GT-I9000 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
# Samsung Galaxy Note
# Mozilla/5.0 (Linux; U; Android 2.3.6; de-de; GT-N7000 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
# Samsung Galaxy ACE (no Flash since ARM)
# Mozilla/5.0 (Linux; U; Android 2.2.1; de-de; GT-S5830 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
# WebOS ==============================================================
# HP Touchpad
# Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.5; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.83 Safari/534.6 TouchPad/1.0
# => Qt-WebKit, Hixie-76, Flash
# Safari =============================================================
# iPod Touch, iOS 4.2.1
# Mozilla/5.0 (iPod; U; CPU iPhone OS 4_2_1 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5
# => Hixie-76
# MacBook Pro, OSX 10.5.8, Safari 5.0.6
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.50.2 (KHTML, like Gecko) Version/5.0.6 Safari/533.22.3
# => Hixie-76
# RFC6455
# Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.24+ (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10
# Hixie-76
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.53.11 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10
# Hixie-76
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.50.2 (KHTML, like Gecko) Version/5.0.6 Safari/533.22.3
# Opera ==============================================================
# Windows 7 32-Bit
# Opera/9.80 (Windows NT 6.1; U; de) Presto/2.10.229 Version/11.61
# Windows 7 64-Bit
# Opera/9.80 (Windows NT 6.1; WOW64; U; de) Presto/2.10.229 Version/11.62
# Samsung Galaxy S
# Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1202231246; U; de) Presto/2.10.254 Version/12.00
# Samsung Galaxy Tab 1
# Opera/9.80 (Android 2.2; Linux; Opera Tablet/ADR-1203051631; U; de) Presto/2.10.254 Version/12.00
# Samsung Galaxy ACE:
# Opera/9.80 (Android 2.2.1; Linux; Opera Mobi/ADR-1203051631; U; de) Presto/2.10.254 Version/12.00
# Nokia N8, Symbian S60 5th Ed., S60 Bell
# Opera/9.80 (S60; SymbOS; Opera Mobi/SYB-1111151949; U; de) Presto/2.9.201 Version/11.50
def _lookupWsSupport(ua):
# Internet Explorer
##
# FIXME: handle Windows Phone
##
if ua.find("MSIE") >= 0:
# IE10 has native support
if ua.find("MSIE 10") >= 0:
# native Hybi-10+
return True, False, True
# first, check for Google Chrome Frame
# http://www.chromium.org/developers/how-tos/chrome-frame-getting-started/understanding-chrome-frame-user-agent
if ua.find("chromeframe") >= 0:
r = UA_CHROMEFRAME.match(ua)
try:
v = int(r.groups()[0])
if v >= 14:
# native Hybi-10+
return True, False, True
except:
# detection problem
return False, False, False
# Flash fallback
if ua.find("MSIE 8") >= 0 or ua.find("MSIE 9") >= 0:
return True, True, True
# unsupported
return False, False, True
# iOS
##
if ua.find("iPhone") >= 0 or ua.find("iPad") >= 0 or ua.find("iPod") >= 0:
# native Hixie76 (as of March 2012), no Flash, no alternative browsers
return True, False, True
# Android
##
if ua.find("Android") >= 0:
# Firefox Mobile
##
if ua.find("Firefox") >= 0:
# Hybi-10+ for FF Mobile 8+
return True, False, True
# Opera Mobile
##
if ua.find("Opera") >= 0:
# Hixie76 for Opera 11+
return True, False, True
# Chrome for Android
##
if ua.find("CrMo") >= 0:
# http://code.google.com/chrome/mobile/docs/faq.html
return True, False, True
# Android builtin Browser (ooold WebKit)
##
if ua.find("AppleWebKit") >= 0:
# Though we return WS = True, and Flash = True here, when the device has no actual Flash support, that
# will get later detected in JS. This applies to i.e. ARMv6 devices like Samsung Galaxy ACE
# builtin browser, only works via Flash
return True, True, True
# detection problem
return False, False, False
# webOS
##
if ua.find("hpwOS") >= 0 or ua.find("webos") >= 0:
try:
if ua.find("hpwOS") >= 0:
vv = [int(x) for x in UA_HPWEBOS.match(ua).groups()[0].split('.')]
if vv[0] >= 3:
return True, False, True
elif ua.find("webos") >= 0:
vv = [int(x) for x in UA_WEBOS.match(ua).groups()[0].split('.')]
if vv[0] >= 2:
return True, False, True
except:
# detection problem
return False, False, False
else:
# unsupported
return False, False, True
# Opera
##
if ua.find("Opera") >= 0:
# Opera 11+ has Hixie76 (needs to be manually activated though)
return True, False, True
# Firefox
##
if ua.find("Firefox") >= 0:
r = UA_FIREFOX.match(ua)
try:
v = int(r.groups()[0])
if v >= 7:
# native Hybi-10+
return True, False, True
elif v >= 3:
# works with Flash bridge
return True, True, True
else:
# unsupported
return False, False, True
except:
# detection problem
return False, False, False
# Safari
##
if ua.find("Safari") >= 0 and not ua.find("Chrome") >= 0:
# rely on at least Hixie76
return True, False, True
# Chrome
##
if ua.find("Chrome") >= 0:
r = UA_CHROME.match(ua)
try:
v = int(r.groups()[0])
if v >= 14:
# native Hybi-10+
return True, False, True
elif v >= 4:
# works with Flash bridge
return True, True, True
else:
# unsupported
return False, False, True
except:
# detection problem
return False, False, False
# detection problem
return False, False, False
def lookupWsSupport(ua, debug=True):
"""
Lookup if browser supports WebSocket (Hixie76, Hybi10+, RFC6455) natively,
and if not, whether the `web-socket-js <https://github.com/gimite/web-socket-js>`__
Flash bridge works to polyfill that.
Returns a tuple of booleans ``(ws_supported, needs_flash, detected)`` where
* ``ws_supported``: WebSocket is supported
* ``needs_flash``: Flash Bridge is needed for support
* ``detected`` the code has explicitly mapped support
:param ua: The browser user agent string as sent in the HTTP header, e.g. provided as `flask.request.user_agent.string` in Flask.
:type ua: str
:returns: tuple -- A tuple ``(ws_supported, needs_flash, detected)``.
"""
ws = _lookupWsSupport(ua)
if debug:
if ua not in UA_DETECT_WS_SUPPORT_DB:
UA_DETECT_WS_SUPPORT_DB[ua] = ws
if not ws[2]:
msg = "UNDETECTED"
elif ws[0]:
msg = "SUPPORTED"
elif not ws[0]:
msg = "UNSUPPORTED"
else:
msg = "ERROR"
print("DETECT_WS_SUPPORT: %s %s %s %s %s" % (ua, ws[0], ws[1], ws[2], msg))
return ws