Use slices internally
This commit is contained in:
@@ -64,10 +64,10 @@ func Parse(userAgent string) UserAgent {
|
|||||||
tokens := parse(userAgent)
|
tokens := parse(userAgent)
|
||||||
|
|
||||||
// check is there URL
|
// check is there URL
|
||||||
for k := range tokens {
|
for i, token := range tokens.list {
|
||||||
if strings.HasPrefix(k, "http://") || strings.HasPrefix(k, "https://") {
|
if strings.HasPrefix(token.Key, "http://") || strings.HasPrefix(token.Key, "https://") {
|
||||||
ua.URL = k
|
ua.URL = token.Key
|
||||||
delete(tokens, k)
|
tokens.list = append(tokens.list[:i], tokens.list[i+1:]...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,8 +76,9 @@ func Parse(userAgent string) UserAgent {
|
|||||||
switch {
|
switch {
|
||||||
case tokens.exists("Android"):
|
case tokens.exists("Android"):
|
||||||
ua.OS = Android
|
ua.OS = Android
|
||||||
ua.OSVersion = tokens[Android]
|
ua.OSVersion = tokens.get(Android)
|
||||||
for s := range tokens {
|
for _, token := range tokens.list {
|
||||||
|
s := token.Key
|
||||||
if strings.HasSuffix(s, "Build") {
|
if strings.HasSuffix(s, "Build") {
|
||||||
ua.Device = strings.TrimSpace(s[:len(s)-5])
|
ua.Device = strings.TrimSpace(s[:len(s)-5])
|
||||||
ua.Tablet = strings.Contains(strings.ToLower(ua.Device), "tablet")
|
ua.Tablet = strings.Contains(strings.ToLower(ua.Device), "tablet")
|
||||||
@@ -98,12 +99,12 @@ func Parse(userAgent string) UserAgent {
|
|||||||
|
|
||||||
case tokens.exists("Windows NT"):
|
case tokens.exists("Windows NT"):
|
||||||
ua.OS = Windows
|
ua.OS = Windows
|
||||||
ua.OSVersion = tokens["Windows NT"]
|
ua.OSVersion = tokens.get("Windows NT")
|
||||||
ua.Desktop = true
|
ua.Desktop = true
|
||||||
|
|
||||||
case tokens.exists("Windows Phone OS"):
|
case tokens.exists("Windows Phone OS"):
|
||||||
ua.OS = WindowsPhone
|
ua.OS = WindowsPhone
|
||||||
ua.OSVersion = tokens["Windows Phone OS"]
|
ua.OSVersion = tokens.get("Windows Phone OS")
|
||||||
ua.Mobile = true
|
ua.Mobile = true
|
||||||
|
|
||||||
case tokens.exists("Macintosh"):
|
case tokens.exists("Macintosh"):
|
||||||
@@ -113,12 +114,12 @@ func Parse(userAgent string) UserAgent {
|
|||||||
|
|
||||||
case tokens.exists("Linux"):
|
case tokens.exists("Linux"):
|
||||||
ua.OS = Linux
|
ua.OS = Linux
|
||||||
ua.OSVersion = tokens[Linux]
|
ua.OSVersion = tokens.get(Linux)
|
||||||
ua.Desktop = true
|
ua.Desktop = true
|
||||||
|
|
||||||
case tokens.exists("CrOS"):
|
case tokens.exists("CrOS"):
|
||||||
ua.OS = ChromeOS
|
ua.OS = ChromeOS
|
||||||
ua.OSVersion = tokens[ChromeOS]
|
ua.OSVersion = tokens.get(ChromeOS)
|
||||||
ua.Desktop = true
|
ua.Desktop = true
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -131,92 +132,97 @@ func Parse(userAgent string) UserAgent {
|
|||||||
|
|
||||||
case tokens.exists("Googlebot"):
|
case tokens.exists("Googlebot"):
|
||||||
ua.Name = Googlebot
|
ua.Name = Googlebot
|
||||||
ua.Version = tokens[Googlebot]
|
ua.Version = tokens.get(Googlebot)
|
||||||
ua.Bot = true
|
ua.Bot = true
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens.exists("Applebot"):
|
case tokens.exists("Applebot"):
|
||||||
ua.Name = Applebot
|
ua.Name = Applebot
|
||||||
ua.Version = tokens[Applebot]
|
ua.Version = tokens.get(Applebot)
|
||||||
ua.Bot = true
|
ua.Bot = true
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
ua.OS = ""
|
ua.OS = ""
|
||||||
|
|
||||||
case tokens["Opera Mini"] != "":
|
case tokens.get("Opera Mini") != "":
|
||||||
ua.Name = OperaMini
|
ua.Name = OperaMini
|
||||||
ua.Version = tokens[OperaMini]
|
ua.Version = tokens.get(OperaMini)
|
||||||
ua.Mobile = true
|
ua.Mobile = true
|
||||||
|
|
||||||
case tokens["OPR"] != "":
|
case tokens.get("OPR") != "":
|
||||||
ua.Name = Opera
|
ua.Name = Opera
|
||||||
ua.Version = tokens["OPR"]
|
ua.Version = tokens.get("OPR")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["OPT"] != "":
|
case tokens.get("OPT") != "":
|
||||||
ua.Name = OperaTouch
|
ua.Name = OperaTouch
|
||||||
ua.Version = tokens["OPT"]
|
ua.Version = tokens.get("OPT")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
// Opera on iOS
|
// Opera on iOS
|
||||||
case tokens["OPiOS"] != "":
|
case tokens.get("OPiOS") != "":
|
||||||
ua.Name = Opera
|
ua.Name = Opera
|
||||||
ua.Version = tokens["OPiOS"]
|
ua.Version = tokens.get("OPiOS")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
// Chrome on iOS
|
// Chrome on iOS
|
||||||
case tokens["CriOS"] != "":
|
case tokens.get("CriOS") != "":
|
||||||
ua.Name = Chrome
|
ua.Name = Chrome
|
||||||
ua.Version = tokens["CriOS"]
|
ua.Version = tokens.get("CriOS")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
// Firefox on iOS
|
// Firefox on iOS
|
||||||
case tokens["FxiOS"] != "":
|
case tokens.get("FxiOS") != "":
|
||||||
ua.Name = Firefox
|
ua.Name = Firefox
|
||||||
ua.Version = tokens["FxiOS"]
|
ua.Version = tokens.get("FxiOS")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["Firefox"] != "":
|
case tokens.get("Firefox") != "":
|
||||||
ua.Name = Firefox
|
ua.Name = Firefox
|
||||||
ua.Version = tokens[Firefox]
|
ua.Version = tokens.get(Firefox)
|
||||||
_, ua.Mobile = tokens["Mobile"]
|
ua.Mobile = tokens.exists("Mobile")
|
||||||
_, ua.Tablet = tokens["Tablet"]
|
ua.Tablet = tokens.exists("Tablet")
|
||||||
|
|
||||||
case tokens["Vivaldi"] != "":
|
case tokens.get("Vivaldi") != "":
|
||||||
ua.Name = Vivaldi
|
ua.Name = Vivaldi
|
||||||
ua.Version = tokens[Vivaldi]
|
ua.Version = tokens.get(Vivaldi)
|
||||||
|
|
||||||
case tokens.exists("MSIE"):
|
case tokens.exists("MSIE"):
|
||||||
ua.Name = InternetExplorer
|
ua.Name = InternetExplorer
|
||||||
ua.Version = tokens["MSIE"]
|
ua.Version = tokens.get("MSIE")
|
||||||
|
|
||||||
case tokens["EdgiOS"] != "":
|
case tokens.get("EdgiOS") != "":
|
||||||
ua.Name = Edge
|
ua.Name = Edge
|
||||||
ua.Version = tokens["EdgiOS"]
|
ua.Version = tokens.get("EdgiOS")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["Edge"] != "":
|
case tokens.get("Edge") != "":
|
||||||
ua.Name = Edge
|
ua.Name = Edge
|
||||||
ua.Version = tokens["Edge"]
|
ua.Version = tokens.get("Edge")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["Edg"] != "":
|
case tokens.get("Edg") != "":
|
||||||
ua.Name = Edge
|
ua.Name = Edge
|
||||||
ua.Version = tokens["Edg"]
|
ua.Version = tokens.get("Edg")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["EdgA"] != "":
|
case tokens.get("EdgA") != "":
|
||||||
ua.Name = Edge
|
ua.Name = Edge
|
||||||
ua.Version = tokens["EdgA"]
|
ua.Version = tokens.get("EdgA")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["bingbot"] != "":
|
case tokens.get("bingbot") != "":
|
||||||
ua.Name = "Bingbot"
|
ua.Name = "Bingbot"
|
||||||
ua.Version = tokens["bingbot"]
|
ua.Version = tokens.get("bingbot")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens["SamsungBrowser"] != "":
|
case tokens.get("YandexBot") != "":
|
||||||
|
ua.Name = "YandexBot"
|
||||||
|
ua.Version = tokens.get("YandexBot")
|
||||||
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
|
case tokens.get("SamsungBrowser") != "":
|
||||||
ua.Name = "Samsung Browser"
|
ua.Name = "Samsung Browser"
|
||||||
ua.Version = tokens["SamsungBrowser"]
|
ua.Version = tokens.get("SamsungBrowser")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
// if chrome and Safari defined, find any other token sent descr
|
// if chrome and Safari defined, find any other token sent descr
|
||||||
@@ -224,39 +230,40 @@ func Parse(userAgent string) UserAgent {
|
|||||||
name := tokens.findBestMatch(true)
|
name := tokens.findBestMatch(true)
|
||||||
if name != "" {
|
if name != "" {
|
||||||
ua.Name = name
|
ua.Name = name
|
||||||
ua.Version = tokens[name]
|
ua.Version = tokens.get(name)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
case tokens.exists("Chrome"):
|
case tokens.exists("Chrome"):
|
||||||
ua.Name = Chrome
|
ua.Name = Chrome
|
||||||
ua.Version = tokens["Chrome"]
|
ua.Version = tokens.get("Chrome")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens.exists("Brave Chrome"):
|
case tokens.exists("Brave Chrome"):
|
||||||
ua.Name = Chrome
|
ua.Name = Chrome
|
||||||
ua.Version = tokens["Brave Chrome"]
|
ua.Version = tokens.get("Brave Chrome")
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
case tokens.exists("Safari"):
|
case tokens.exists("Safari"):
|
||||||
ua.Name = Safari
|
ua.Name = Safari
|
||||||
if v, ok := tokens["Version"]; ok {
|
v := tokens.get("Version")
|
||||||
|
if v != "" {
|
||||||
ua.Version = v
|
ua.Version = v
|
||||||
} else {
|
} else {
|
||||||
ua.Version = tokens["Safari"]
|
ua.Version = tokens.get("Safari")
|
||||||
}
|
}
|
||||||
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ua.OS == "Android" && tokens["Version"] != "" {
|
if ua.OS == "Android" && tokens.get("Version") != "" {
|
||||||
ua.Name = "Android browser"
|
ua.Name = "Android browser"
|
||||||
ua.Version = tokens["Version"]
|
ua.Version = tokens.get("Version")
|
||||||
ua.Mobile = true
|
ua.Mobile = true
|
||||||
} else {
|
} else {
|
||||||
if name := tokens.findBestMatch(false); name != "" {
|
if name := tokens.findBestMatch(false); name != "" {
|
||||||
ua.Name = name
|
ua.Name = name
|
||||||
ua.Version = tokens[name]
|
ua.Version = tokens.get(name)
|
||||||
} else {
|
} else {
|
||||||
ua.Name = ua.String
|
ua.Name = ua.String
|
||||||
}
|
}
|
||||||
@@ -285,8 +292,10 @@ func Parse(userAgent string) UserAgent {
|
|||||||
return ua
|
return ua
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse(userAgent string) (clients properties) {
|
func parse(userAgent string) properties {
|
||||||
clients = make(map[string]string)
|
clients := properties{
|
||||||
|
list: make([]property, 0, 8),
|
||||||
|
}
|
||||||
slash := false
|
slash := false
|
||||||
isURL := false
|
isURL := false
|
||||||
var buff, val bytes.Buffer
|
var buff, val bytes.Buffer
|
||||||
@@ -301,9 +310,9 @@ func parse(userAgent string) (clients properties) {
|
|||||||
if val.Len() == 0 { // only if value don't exists
|
if val.Len() == 0 { // only if value don't exists
|
||||||
var ver string
|
var ver string
|
||||||
s, ver = checkVer(s) // determin version string and split
|
s, ver = checkVer(s) // determin version string and split
|
||||||
clients[s] = ver
|
clients.add(s, ver)
|
||||||
} else {
|
} else {
|
||||||
clients[s] = strings.TrimSpace(val.String())
|
clients.add(s, strings.TrimSpace(val.String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,36 +387,60 @@ func checkVer(s string) (name, v string) {
|
|||||||
// return s, ""
|
// return s, ""
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// return s[:i], s[i+1:]
|
// return s[:i], s[i+1:]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type properties map[string]string
|
type property struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
type properties struct {
|
||||||
|
list []property
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *properties) add(key, value string) {
|
||||||
|
p.list = append(p.list, property{Key: key, Value: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p properties) get(key string) string {
|
||||||
|
for _, prop := range p.list {
|
||||||
|
if prop.Key == key {
|
||||||
|
return prop.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (p properties) exists(key string) bool {
|
func (p properties) exists(key string) bool {
|
||||||
_, ok := p[key]
|
for _, prop := range p.list {
|
||||||
return ok
|
if prop.Key == key {
|
||||||
}
|
|
||||||
|
|
||||||
func (p properties) existsAny(keys ...string) bool {
|
|
||||||
for _, k := range keys {
|
|
||||||
if _, ok := p[k]; ok {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p properties) existsAny(keys ...string) bool {
|
||||||
|
for _, k := range keys {
|
||||||
|
for _, prop := range p.list {
|
||||||
|
if prop.Key == k {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p properties) findMacOSVersion() string {
|
func (p properties) findMacOSVersion() string {
|
||||||
for k, v := range p {
|
for _, token := range p.list {
|
||||||
if strings.Contains(k, "OS") {
|
if strings.Contains(token.Key, "OS") {
|
||||||
if ver := findVersion(v); ver != "" {
|
if ver := findVersion(token.Value); ver != "" {
|
||||||
return ver
|
return ver
|
||||||
} else if ver = findVersion(k); ver != "" {
|
} else if ver = findVersion(token.Key); ver != "" {
|
||||||
return ver
|
return ver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -421,16 +454,16 @@ func (p properties) findBestMatch(withVerOnly bool) string {
|
|||||||
n = 1
|
n = 1
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
for k, v := range p {
|
for _, prop := range p.list {
|
||||||
switch k {
|
switch prop.Key {
|
||||||
case Chrome, Firefox, Safari, "Version", "Mobile", "Mobile Safari", "Mozilla", "AppleWebKit", "Windows NT", "Windows Phone OS", Android, "Macintosh", Linux, "GSA", ChromeOS:
|
case Chrome, Firefox, Safari, "Version", "Mobile", "Mobile Safari", "Mozilla", "AppleWebKit", "Windows NT", "Windows Phone OS", Android, "Macintosh", Linux, "GSA", ChromeOS:
|
||||||
default:
|
default:
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if v != "" { // in first check, only return keys with value
|
if prop.Value != "" { // in first check, only return keys with value
|
||||||
return k
|
return prop.Key
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return k
|
return prop.Key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user