2
0

Using constants, corrected typos and added some shorthand methods

This commit is contained in:
Ruslan Semagin
2023-11-17 16:45:31 +03:00
parent ab1411d0eb
commit ffe1cc3702
4 changed files with 121 additions and 95 deletions
+3
View File
@@ -1,3 +1,6 @@
.idea/
.vscode/
.DS_Store
old.go
old_test.go
file.txt
+15
View File
@@ -30,6 +30,11 @@ func (ua UserAgent) IsChromeOS() bool {
return ua.OS == ChromeOS || ua.OS == "CrOS"
}
// IsBlackberryOS shorthand function to check if OS == BlackBerry
func (ua UserAgent) IsBlackberryOS() bool {
return ua.OS == BlackBerry
}
// IsOpera shorthand function to check if Name == Opera
func (ua UserAgent) IsOpera() bool {
return ua.Name == Opera
@@ -65,6 +70,11 @@ func (ua UserAgent) IsEdge() bool {
return ua.Name == Edge
}
// IsBlackBerry shorthand function to check if Name == BlackBerry
func (ua UserAgent) IsBlackBerry() bool {
return ua.Name == BlackBerry
}
// IsGooglebot shorthand function to check if Name == Googlebot
func (ua UserAgent) IsGooglebot() bool {
return ua.Name == Googlebot
@@ -80,6 +90,11 @@ func (ua UserAgent) IsFacebookbot() bool {
return ua.Name == FacebookExternalHit
}
// IsYandexbot shorthand function to check if Name == YandexBot
func (ua UserAgent) IsYandexbot() bool {
return ua.Name == YandexBot
}
// IsUnknown returns true if the package can't determine the user agent reliably.
// Fields like Name, OS, etc. might still have values.
func (ua UserAgent) IsUnknown() bool {
+102 -95
View File
@@ -25,15 +25,18 @@ type UserAgent struct {
// Constants for browsers and operating systems for easier comparison
const (
Windows = "Windows"
WindowsPhone = "Windows Phone"
Android = "Android"
MacOS = "macOS"
IOS = "iOS"
Linux = "Linux"
FreeBSD = "FreeBSD"
ChromeOS = "ChromeOS"
BlackBerry = "BlackBerry"
Windows = "Windows"
WindowsPhone = "Windows Phone"
WindowsNT = "Windows NT"
WindowsPhoneOS = "Windows Phone OS"
Android = "Android"
MacOS = "macOS"
IOS = "iOS"
Linux = "Linux"
FreeBSD = "FreeBSD"
ChromeOS = "ChromeOS"
BlackBerry = "BlackBerry"
CrOS = "CrOS"
Opera = "Opera"
OperaMini = "Opera Mini"
@@ -45,6 +48,10 @@ const (
Safari = "Safari"
Edge = "Edge"
Vivaldi = "Vivaldi"
MobileSafari = "Mobile Safari"
NetFront = "NetFront"
Mozilla = "Mozilla"
Msie = "MSIE"
GoogleAdsBot = "Google Ads Bot"
Googlebot = "Googlebot"
@@ -52,10 +59,16 @@ const (
FacebookExternalHit = "facebookexternalhit"
Applebot = "Applebot"
Bingbot = "Bingbot"
YandexBot = "YandexBot"
YandexAdNet = "YandexAdNet"
FacebookApp = "Facebook App"
InstagramApp = "Instagram App"
TiktokApp = "TikTok App"
Version = "Version"
Mobile = "Mobile"
Tablet = "Tablet"
)
// Parse user agent string returning UserAgent struct
@@ -75,15 +88,13 @@ func Parse(userAgent string) UserAgent {
}
}
//fmt.Printf("%+v\n", tokens)
// OS lookup
switch {
case tokens.exists("Android"):
case tokens.exists(Android):
ua.OS = Android
var osIndex int
osIndex, ua.OSVersion = tokens.getIndexValue(Android)
ua.Tablet = strings.Contains(strings.ToLower(ua.String), "tablet")
ua.Tablet = strings.Contains(strings.ToLower(ua.String), strings.ToLower(Tablet))
ua.Device = tokens.findAndroidDevice(osIndex)
case tokens.exists("iPhone"):
@@ -98,14 +109,14 @@ func Parse(userAgent string) UserAgent {
ua.Device = "iPad"
ua.Tablet = true
case tokens.exists("Windows NT"):
case tokens.exists(WindowsNT):
ua.OS = Windows
ua.OSVersion = tokens.get("Windows NT")
ua.OSVersion = tokens.get(WindowsNT)
ua.Desktop = true
case tokens.exists("Windows Phone OS"):
case tokens.exists(WindowsPhoneOS):
ua.OS = WindowsPhone
ua.OSVersion = tokens.get("Windows Phone OS")
ua.OSVersion = tokens.get(WindowsPhoneOS)
ua.Mobile = true
case tokens.exists("Macintosh"):
@@ -113,33 +124,33 @@ func Parse(userAgent string) UserAgent {
ua.OSVersion = tokens.findMacOSVersion()
ua.Desktop = true
case tokens.exists("Linux"):
case tokens.exists(Linux):
ua.OS = Linux
ua.OSVersion = tokens.get(Linux)
ua.Desktop = true
case tokens.exists("FreeBSD"):
case tokens.exists(FreeBSD):
ua.OS = FreeBSD
ua.OSVersion = tokens.get(FreeBSD)
ua.Desktop = true
case tokens.exists("CrOS"):
case tokens.exists(CrOS):
ua.OS = ChromeOS
ua.OSVersion = tokens.get("CrOS")
ua.OSVersion = tokens.get(CrOS)
ua.Desktop = true
case tokens.exists("BlackBerry"):
case tokens.exists(BlackBerry):
ua.OS = BlackBerry
ua.OSVersion = tokens.get("BlackBerry")
ua.OSVersion = tokens.get(BlackBerry)
ua.Mobile = true
}
switch {
case tokens.exists("Googlebot"):
case tokens.exists(Googlebot):
ua.Name = Googlebot
ua.Version = tokens.get(Googlebot)
ua.Bot = true
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.existsAny("GoogleProber", "GoogleProducer"):
if name := tokens.findBestMatch(false); name != "" {
@@ -147,14 +158,14 @@ func Parse(userAgent string) UserAgent {
}
ua.Bot = true
case tokens.exists("Applebot"):
case tokens.exists(Applebot):
ua.Name = Applebot
ua.Version = tokens.get(Applebot)
ua.Bot = true
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
ua.OS = ""
case tokens.get("Opera Mini") != "":
case tokens.get(OperaMini) != "":
ua.Name = OperaMini
ua.Version = tokens.get(OperaMini)
ua.Mobile = true
@@ -162,84 +173,91 @@ func Parse(userAgent string) UserAgent {
case tokens.get("OPR") != "":
ua.Name = Opera
ua.Version = tokens.get("OPR")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("OPT") != "":
ua.Name = OperaTouch
ua.Version = tokens.get("OPT")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
// Opera on iOS
case tokens.get("OPiOS") != "":
ua.Name = Opera
ua.Version = tokens.get("OPiOS")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
// Chrome on iOS
case tokens.get("CriOS") != "":
ua.Name = Chrome
ua.Version = tokens.get("CriOS")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
// Firefox on iOS
case tokens.get("FxiOS") != "":
ua.Name = Firefox
ua.Version = tokens.get("FxiOS")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("Firefox") != "":
case tokens.get(Firefox) != "":
ua.Name = Firefox
ua.Version = tokens.get(Firefox)
ua.Mobile = tokens.exists("Mobile")
ua.Tablet = tokens.exists("Tablet")
ua.Mobile = tokens.exists(Mobile)
ua.Tablet = tokens.exists(Tablet)
case tokens.get("Vivaldi") != "":
case tokens.get(Vivaldi) != "":
ua.Name = Vivaldi
ua.Version = tokens.get(Vivaldi)
case tokens.exists("MSIE"):
case tokens.exists(Msie):
ua.Name = InternetExplorer
ua.Version = tokens.get("MSIE")
ua.Version = tokens.get(Msie)
case tokens.get("EdgiOS") != "":
ua.Name = Edge
ua.Version = tokens.get("EdgiOS")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("Edge") != "":
case tokens.get(Edge) != "":
ua.Name = Edge
ua.Version = tokens.get("Edge")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Version = tokens.get(Edge)
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("Edg") != "":
ua.Name = Edge
ua.Version = tokens.get("Edg")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("EdgA") != "":
ua.Name = Edge
ua.Version = tokens.get("EdgA")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("bingbot") != "":
ua.Name = Bingbot
ua.Version = tokens.get("bingbot")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("YandexBot") != "":
ua.Name = "YandexBot"
ua.Version = tokens.get("YandexBot")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens.get(YandexBot) != "":
ua.Name = YandexBot
ua.Version = tokens.get(YandexBot)
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
ua.Bot = true
case tokens.get(YandexAdNet) != "":
ua.Name = YandexAdNet
ua.Version = tokens.get(YandexAdNet)
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
ua.Bot = true
case tokens.get("SamsungBrowser") != "":
ua.Name = "Samsung Browser"
ua.Version = tokens.get("SamsungBrowser")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.get("HeadlessChrome") != "":
ua.Name = HeadlessChrome
ua.Version = tokens.get("HeadlessChrome")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
ua.Bot = true
case tokens.existsAny("AdsBot-Google-Mobile", "Mediapartners-Google", "AdsBot-Google"):
@@ -279,18 +297,18 @@ func Parse(userAgent string) UserAgent {
case tokens.get("HuaweiBrowser") != "":
ua.Name = "Huawei Browser"
ua.Version = tokens.get("HuaweiBrowser")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.exists("BlackBerry"):
ua.Name = "BlackBerry"
ua.Version = tokens.get("Version")
case tokens.exists(BlackBerry):
ua.Name = BlackBerry
ua.Version = tokens.get(Version)
case tokens.exists("NetFront"):
ua.Name = "NetFront"
ua.Version = tokens.get("NetFront")
case tokens.exists(NetFront):
ua.Name = NetFront
ua.Version = tokens.get(NetFront)
ua.Mobile = true
// if chrome and Safari defined, find any other token sent descr
// if Chrome and Safari defined, find any other token sent descr
case tokens.exists(Chrome) && tokens.exists(Safari):
name := tokens.findBestMatch(true)
if name != "" {
@@ -300,30 +318,30 @@ func Parse(userAgent string) UserAgent {
}
fallthrough
case tokens.exists("Chrome"):
case tokens.exists(Chrome):
ua.Name = Chrome
ua.Version = tokens.get("Chrome")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Version = tokens.get(Chrome)
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.exists("Brave Chrome"):
ua.Name = Chrome
ua.Version = tokens.get("Brave Chrome")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
case tokens.exists("Safari"):
case tokens.exists(Safari):
ua.Name = Safari
v := tokens.get("Version")
v := tokens.get(Version)
if v != "" {
ua.Version = v
} else {
ua.Version = tokens.get("Safari")
ua.Version = tokens.get(Safari)
}
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
default:
if ua.OS == "Android" && tokens.get("Version") != "" {
if ua.IsAndroid() && tokens.get(Version) != "" {
ua.Name = "Android browser"
ua.Version = tokens.get("Version")
ua.Version = tokens.get(Version)
ua.Mobile = true
} else {
if name := tokens.findBestMatch(false); name != "" {
@@ -335,7 +353,7 @@ func Parse(userAgent string) UserAgent {
ua.Bot = strings.Contains(strings.ToLower(ua.Name), "bot")
// If mobile flag has already been set, don't override it.
if !ua.Mobile {
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
ua.Mobile = tokens.existsAny(Mobile, MobileSafari)
}
}
}
@@ -349,7 +367,7 @@ func Parse(userAgent string) UserAgent {
ua.Mobile = false
}
// if not already bot, check some popular bots and wether URL is set
// if not already bot, check some popular bots and whether URL is set
if !ua.Bot {
ua.Bot = ua.URL != ""
}
@@ -384,7 +402,7 @@ func parse(userAgent string) properties {
if val.Len() == 0 { // only if value don't exists
var ver string
s, ver = checkVer(s) // determin version string and split
s, ver = checkVer(s) // determine version string and split
clients.add(s, ver)
} else {
clients.add(s, strings.TrimSpace(val.String()))
@@ -403,7 +421,6 @@ func parse(userAgent string) properties {
bua := []byte(userAgent)
for i, c := range bua {
//fmt.Println(string(c), c)
switch {
case c == 41: // )
addToken()
@@ -434,7 +451,7 @@ func parse(userAgent string) properties {
// If the following character is not a space, change to a space.
buff.WriteByte(' ')
}
// Otherwise don't write as its probably a badly formatted key value separator.
// Otherwise don't write as it's probably a badly formatted key value separator.
case slash && c == 32:
addToken()
@@ -469,10 +486,8 @@ func checkVer(s string) (name, v string) {
return s, ""
}
//v = s[i+1:]
switch s[:i] {
case "Linux", "Windows NT", "Windows Phone OS", "MSIE", "Android":
case Linux, WindowsNT, WindowsPhoneOS, Msie, Android:
return s[:i], s[i+1:]
case "CrOS x86_64", "CrOS aarch64", "CrOS armv7l":
j := strings.LastIndex(s[:i], " ")
@@ -480,20 +495,12 @@ func checkVer(s string) (name, v string) {
default:
return s, ""
}
// for _, c := range v {
// if (c >= 48 && c <= 57) || c == 46 {
// } else {
// return s, ""
// }
// }
// return s[:i], s[i+1:]
}
// ignore retursn true if token should be ignored
// ignore returns true if token should be ignored
func ignore(s string) bool {
switch s {
case "KHTML, like Gecko", "U", "compatible", "Mozilla", "WOW64", "en", "en-us", "en-gb", "ru-ru", "Browser":
case "KHTML, like Gecko", "U", "compatible", Mozilla, "WOW64", "en", "en-us", "en-gb", "ru-ru", "Browser":
return true
default:
return false
@@ -607,9 +614,9 @@ func (p properties) findBestMatch(withVerOnly bool) string {
for i := 0; i < n; i++ {
for _, prop := range p.list {
switch prop.Key {
case Chrome, Firefox, Safari, "Version", "Mobile", "Mobile Safari", "Mozilla", "AppleWebKit", "Windows NT", "Windows Phone OS", Android, "Macintosh", Linux, "GSA", "CrOS", "Tablet":
case Chrome, Firefox, Safari, Version, Mobile, MobileSafari, Mozilla, "AppleWebKit", WindowsNT, WindowsPhoneOS, Android, "Macintosh", Linux, "GSA", CrOS, Tablet:
default:
// don' pick if starts with number
// don't pick if starts with number
if len(prop.Key) != 0 && prop.Key[0] >= 48 && prop.Key[0] <= 57 {
break
}
@@ -641,15 +648,15 @@ func (p *properties) findAndroidDevice(startIndex int) string {
if len(p.list) > i+1 {
dev := p.list[i+1].Key
if len(dev) == 2 || (len(dev) == 5 && dev[2] == '-') {
// probably langage tag (en-us etc..), ignore and continue loop
// probably language tag (en-us etc..), ignore and continue loop
continue
}
switch dev {
case Chrome, Firefox, Safari, "Opera Mini", "Presto", "Version", "Mobile", "Mobile Safari", "Mozilla", "AppleWebKit", "Windows NT", "Windows Phone OS", Android, "Macintosh", Linux, "CrOS":
// ignore this tokens, not device names
case Chrome, Firefox, Safari, OperaMini, "Presto", Version, Mobile, MobileSafari, Mozilla, "AppleWebKit", WindowsNT, WindowsPhoneOS, Android, "Macintosh", Linux, CrOS:
// ignore these tokens, not device names
default:
if strings.Contains(strings.ToLower(dev), "tablet") {
p.list[i+1].Key = "Tablet" // leave Tablet tag for later table detection
if strings.Contains(strings.ToLower(dev), strings.ToLower(Tablet)) {
p.list[i+1].Key = Tablet // leave Tablet tag for later table detection
} else {
p.list = append(p.list[:i+1], p.list[i+2:]...)
}
+1
View File
@@ -90,6 +90,7 @@ var testTable = [][]string{
{"Mozilla/5.0 (compatible; Yahoo Ad monitoring; https://help.yahoo.com/kb/yahoo-ad-monitoring-SLN24857.html) cnv.aws-prod---sieve.hlfs-rest_client/1681346790-0", "Yahoo Ad monitoring", "", "bot", ""},
{"GoogleProber", "GoogleProber", "", "bot", ""},
{"GoogleProducer; (+http://goo.gl/7y4SX)", "GoogleProducer", "", "bot", ""},
{"Mozilla/5.0 (compatible; YandexAdNet/1.0; +http://yandex.com/bots) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.268", "YandexAdNet", "1.0", "bot", ""},
// Google ads bots
{"Mozilla/5.0 (Linux; Android 4.0.0; Galaxy Nexus Build/IMM76B) AppleWebKit/537.36 (KHTML, like Gecko; Mediapartners-Google) Chrome/104.0.0.0 Mobile Safari/537.36", ua.GoogleAdsBot, "", "bot", ua.Android},