############################################################################### ## ## Copyright 2011-2012 Tavendo GmbH ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## ############################################################################### import re 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*.*") # 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): """ Lookup if browser supports WebSocket (Hixie76, Hybi10+, RFC6455) natively, and if not, whether the web-socket-js Flash bridge works to polyfill that. Returns a tuple of booleans (ws_supported, needs_flash, detected) ws_supported = WebSocket is supported needs_flash = Flash Bridge is needed for support detected = the code has explicitly mapped the support/nosupport Params: ua = user agent string, i.e. flask.request.user_agent.string """ ## 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) UA_DETECT_WS_SUPPORT_DB = {} def lookupWsSupport(ua, debug = True): ws = _lookupWsSupport(ua) if debug: if not UA_DETECT_WS_SUPPORT_DB.has_key(ua): 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", ua, ws[0], ws[1], ws[2], msg return ws