2
0

First commit

This commit is contained in:
mileusna
2017-08-16 18:01:24 +02:00
commit e1aff7cb1e
5 changed files with 741 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Miloš Mileusnić
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.
+74
View File
@@ -0,0 +1,74 @@
# Go/Golang package for parsing user agent strings [![GoDoc](https://godoc.org/github.com/mileusna/useragent?status.svg)](https://godoc.org/github.com/mileusna/useragent)
Parse browser's and bot's user agents strings and determin user agent name, version, operating system name etc.
## Status
Still need some work on detecting Andorid device name.
## Installation <a id="installation"></a>
```
go get github.com/mileusna/useragent
```
## Example<a id="example"></a>
```go
package main
import (
"fmt"
"strings"
"github.com/mileusna/useragent"
)
func main() {
userAgents := []string{
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) FxiOS/8.1.1b4948 Mobile/14F89 Safari/603.2.4",
"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36",
"Mozilla/5.0 (Android 4.3; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0",
"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.9.2246.119956",
"Opera/9.80 (Android; Opera Mini/28.0.2254/66.318; U; en) Presto/2.12.423 Version/12.16",
}
for _, s := range userAgents {
ua := ua.Parse(s)
fmt.Println()
fmt.Println(ua.String)
fmt.Println(strings.Repeat("=", len(ua.String)))
fmt.Println("Name:", ua.Name, "v", ua.Version)
fmt.Println("OS:", ua.OS, "v", ua.OSVersion)
fmt.Println("Device:", ua.Device)
if ua.Mobile {
fmt.Println("(Mobile)")
}
if ua.Tablet {
fmt.Println("(Tablet)")
}
if ua.Desktop {
fmt.Println("(Desktop)")
}
if ua.Bot {
fmt.Println("(Bot)")
}
if ua.URL != "" {
fmt.Println(ua.URL)
}
}
}
```
## Notice
+ Opera and Opera Mini are two browsers, since they operate on very differenta way.
+ If Googlebot (or any other bot) is detected and it is using its mobile crawler, both `bot` and `mobile` flags will be set to `true`.
+76
View File
@@ -0,0 +1,76 @@
package ua
// IsWindows shorthand function to check if OS == Windows
func (ua UserAgent) IsWindows() bool {
return ua.OS == Windows
}
// IsAndroid shorthand function to check if OS == Android
func (ua UserAgent) IsAndroid() bool {
return ua.OS == Android
}
// IsMacOS shorthand function to check if OS == MacOS
func (ua UserAgent) IsMacOS() bool {
return ua.OS == MacOS
}
// IsIOS shorthand function to check if OS == IOS
func (ua UserAgent) IsIOS() bool {
return ua.OS == IOS
}
// IsLinux shorthand function to check if OS == Linux
func (ua UserAgent) IsLinux() bool {
return ua.OS == Linux
}
// IsOpera shorthand function to check if Name == Opera
func (ua UserAgent) IsOpera() bool {
return ua.Name == Opera
}
// IsOperaMini shorthand function to check if Name == Opera Mini
func (ua UserAgent) IsOperaMini() bool {
return ua.Name == OperaMini
}
// IsChrome shorthand function to check if Name == Chrome
func (ua UserAgent) IsChrome() bool {
return ua.Name == Chrome
}
// IsFirefox shorthand function to check if Name == Firefox
func (ua UserAgent) IsFirefox() bool {
return ua.Name == Firefox
}
// IsInternetExplorer shorthand function to check if Name == Internet Explorer
func (ua UserAgent) IsInternetExplorer() bool {
return ua.Name == InternetExplorer
}
// IsSafari shorthand function to check if Name == Safari
func (ua UserAgent) IsSafari() bool {
return ua.Name == Safari
}
// IsEdge shorthand function to check if Name == Edge
func (ua UserAgent) IsEdge() bool {
return ua.Name == Edge
}
// IsGooglebot shorthand function to check if Name == Googlebot
func (ua UserAgent) IsGooglebot() bool {
return ua.Name == Googlebot
}
// IsTwitterbot shorthand function to check if Name == Twitterbot
func (ua UserAgent) IsTwitterbot() bool {
return ua.Name == Twitterbot
}
// IsFacebookbot shorthand function to check if Name == FacebookExternalHit
func (ua UserAgent) IsFacebookbot() bool {
return ua.Name == FacebookExternalHit
}
+407
View File
@@ -0,0 +1,407 @@
package ua
import (
"bytes"
"regexp"
"strings"
)
// UserAgent struct containg all determined datra from parsed user-agent string
type UserAgent struct {
Name string
Version string
OS string
OSVersion string
Device string
Mobile bool
Tablet bool
Desktop bool
Bot bool
URL string
String string
}
var ignore = map[string]struct{}{
"KHTML, like Gecko": struct{}{},
"U": struct{}{},
"compatible": struct{}{},
"Mozilla": struct{}{},
"WOW64": struct{}{},
}
// Constants for browsers and operating systems for easier comparation
const (
Windows = "Windows"
WindowsPhone = "Windows Phone"
Android = "Android"
MacOS = "macOS"
IOS = "iOS"
Linux = "Linux"
Opera = "Opera"
OperaMini = "Opera Mini"
Chrome = "Chrome"
Firefox = "Firefox"
InternetExplorer = "Internet Explorer"
Safari = "Safari"
Edge = "Edge"
Vivaldi = "Vivaldi"
Googlebot = "Googlebot"
Twitterbot = "Twitterbot"
FacebookExternalHit = "facebookexternalhit"
)
// Parse user agent string returning UserAgent struct
func Parse(userAgent string) UserAgent {
ua := UserAgent{
String: userAgent,
}
tokens := parse(userAgent)
// check is there URL
for k := range tokens {
if strings.HasPrefix(k, "http://") || strings.HasPrefix(k, "https://") {
ua.URL = k
delete(tokens, k)
break
}
}
// OS lookup
switch {
case tokens.exists("Android"):
ua.OS = Android
ua.OSVersion = tokens[Android]
for s := range tokens {
if strings.HasSuffix(s, "Build") {
ua.Device = strings.TrimSpace(s[:len(s)-5])
ua.Tablet = strings.Contains(strings.ToLower(ua.Device), "tablet")
}
}
case tokens.exists("iPhone"):
ua.OS = IOS
ua.OSVersion = tokens.findMacOSVersion()
ua.Device = "iPhone"
ua.Mobile = true
case tokens.exists("iPad"):
ua.OS = IOS
ua.OSVersion = tokens.findMacOSVersion()
ua.Device = "iPad"
ua.Tablet = true
case tokens.exists("Windows NT"):
ua.OS = Windows
ua.OSVersion = tokens["Windows NT"]
ua.Desktop = true
case tokens.exists("Windows Phone OS"):
ua.OS = WindowsPhone
ua.OSVersion = tokens["Windows Phone OS"]
ua.Mobile = true
case tokens.exists("Macintosh"):
ua.OS = MacOS
ua.OSVersion = tokens.findMacOSVersion()
ua.Desktop = true
case tokens.exists("Linux"):
ua.OS = Linux
ua.OSVersion = tokens[Linux]
ua.Desktop = true
}
// for s, val := range sys {
// fmt.Println(s, "--", val)
// }
switch {
case tokens.exists("Googlebot"):
ua.Name = Googlebot
ua.Version = tokens[Googlebot]
ua.Bot = true
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens["Opera Mini"] != "":
ua.Name = OperaMini
ua.Version = tokens[OperaMini]
ua.Mobile = true
case tokens["OPR"] != "":
ua.Name = Opera
ua.Version = tokens["OPR"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
// Opera on iOS
case tokens["OPiOS"] != "":
ua.Name = Opera
ua.Version = tokens["OPiOS"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
// Chrome on iOS
case tokens["CriOS"] != "":
ua.Name = Chrome
ua.Version = tokens["CriOS"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
// Firefox on iOS
case tokens["FxiOS"] != "":
ua.Name = Firefox
ua.Version = tokens["FxiOS"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens["Firefox"] != "":
ua.Name = Firefox
ua.Version = tokens[Firefox]
_, ua.Mobile = tokens["Mobile"]
_, ua.Tablet = tokens["Tablet"]
case tokens["Vivaldi"] != "":
ua.Name = Vivaldi
ua.Version = tokens[Vivaldi]
case tokens.exists("MSIE"):
ua.Name = InternetExplorer
ua.Version = tokens["MSIE"]
case tokens["Edge"] != "":
ua.Name = Edge
ua.Version = tokens["Edge"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens["bingbot"] != "":
ua.Name = "Bingbot"
ua.Version = tokens["bingbot"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens["SamsungBrowser"] != "":
ua.Name = "Samsung Browser"
ua.Version = tokens["SamsungBrowser"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
// if chrome and Safari defined, find any other tokensent descr
case tokens.exists(Chrome) && tokens.exists(Safari):
name := tokens.findBestMatch(true)
if name != "" {
ua.Name = name
ua.Version = tokens[name]
break
}
fallthrough
case tokens.exists("Chrome"):
ua.Name = Chrome
ua.Version = tokens["Chrome"]
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
case tokens.exists("Safari"):
ua.Name = Safari
if v, ok := tokens["Version"]; ok {
ua.Version = v
} else {
ua.Version = tokens["Safari"]
}
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
default:
if ua.OS == "Android" && tokens["Version"] != "" {
ua.Name = "Android browser"
ua.Version = tokens["Version"]
ua.Mobile = true
} else {
if name := tokens.findBestMatch(false); name != "" {
ua.Name = name
ua.Version = tokens[name]
} else {
ua.Name = ua.String
}
ua.Bot = strings.Contains(strings.ToLower(ua.Name), "bot")
ua.Mobile = tokens.existsAny("Mobile", "Mobile Safari")
}
}
// if tabler, switch mobile to off
if ua.Tablet {
ua.Mobile = false
}
// if not already bot, check some popular bots and weather URL is set
if !ua.Bot {
ua.Bot = ua.URL != ""
}
if !ua.Bot {
switch ua.Name {
case Twitterbot, FacebookExternalHit:
ua.Bot = true
}
}
return ua
}
func parse(userAgent string) (clients properties) {
clients = make(map[string]string, 0)
slash := false
isURL := false
var buff, val bytes.Buffer
addToken := func() {
if buff.Len() != 0 {
s := strings.TrimSpace(buff.String())
if _, ign := ignore[s]; !ign {
if isURL {
s = strings.TrimPrefix(s, "+")
}
if val.Len() == 0 { // only if value don't exists
var ver string
s, ver = checkVer(s) // determin version string and split
clients[s] = ver
} else {
clients[s] = strings.TrimSpace(val.String())
}
}
}
buff.Reset()
val.Reset()
slash = false
isURL = false
}
parOpen := false
bua := []byte(userAgent)
for i, c := range bua {
//fmt.Println(string(c), c)
switch {
case c == 41: // )
addToken()
parOpen = false
case parOpen && c == 59: // ;
addToken()
case c == 40: // (
addToken()
parOpen = true
case slash && c == 32:
addToken()
case slash:
val.WriteByte(c)
case c == 47 && !isURL: // /
if i != len(bua)-1 && bua[i+1] == 47 && (bytes.HasSuffix(buff.Bytes(), []byte("http:")) || bytes.HasSuffix(buff.Bytes(), []byte("https:"))) {
buff.WriteByte(c)
isURL = true
} else {
slash = true
}
default:
buff.WriteByte(c)
}
}
addToken()
return clients
}
func checkVer(s string) (name, v string) {
i := strings.LastIndex(s, " ")
if i == -1 {
return s, ""
}
//v = s[i+1:]
switch s[:i] {
case "Linux", "Windows NT", "Windows Phone OS", "MSIE", "Android":
return s[:i], s[i+1:]
default:
return s, ""
}
// for _, c := range v {
// if (c >= 48 && c <= 57) || c == 46 {
// } else {
// return s, ""
// }
// }
// return s[:i], s[i+1:]
}
type properties map[string]string
func (p properties) exists(key string) bool {
_, ok := p[key]
return ok
}
func (p properties) existsAny(keys ...string) bool {
for _, k := range keys {
if _, ok := p[k]; ok {
return true
}
}
return false
}
func (p properties) findMacOSVersion() string {
for k, v := range p {
if strings.Contains(k, "OS") {
if ver := findVersion(v); ver != "" {
return ver
} else if ver = findVersion(k); ver != "" {
return ver
}
}
}
return ""
}
// findBestMatch from the rest of the bunch
// in first cycle only return key vith version value
// if withVerValue is false, do another cycle and return any token
func (p properties) findBestMatch(withVerOnly bool) string {
n := 2
if withVerOnly {
n = 1
}
for i := 0; i < n; i++ {
for k, v := range p {
switch k {
case Chrome, Firefox, Safari, "Version", "Mobile", "Mobile Safari", "Mozilla", "AppleWebKit", "Windows NT", "Windows Phone OS", Android, "Macintosh", Linux:
default:
if i == 0 {
if v != "" { // in first check, only return keys with value
return k
}
} else {
return k
}
}
}
}
return ""
}
var rxMacOSVer = regexp.MustCompile("[_\\d\\.]+")
func findVersion(s string) string {
if ver := rxMacOSVer.FindString(s); ver != "" {
return strings.Replace(ver, "_", ".", -1)
}
return ""
}
+163
View File
@@ -0,0 +1,163 @@
package ua_test
import (
"fmt"
"strings"
"testing"
"github.com/mileusna/useragent"
)
func TestParse(t *testing.T) {
var testTable = [][]string{
// Mac
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8", ua.Safari, "10.1.2", "desktop", "macOS"},
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", ua.Chrome, "60.0.3112.90", "desktop", "macOS"},
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0", ua.Firefox, "54.0", "desktop", "macOS"},
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", ua.Opera, "46.0.2597.57", "desktop", "macOS"},
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.91 Safari/537.36 Vivaldi/1.92.917.39", "Vivaldi", "1.92.917.39", "desktop", "macOS"},
// Windows
{"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", ua.Chrome, "59.0.3071.115", "desktop", "Windows"},
{"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2; GWX:RED)", ua.InternetExplorer, "8.0", "desktop", "Windows"},
{"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) NS8/0.9.6", ua.InternetExplorer, "6.0", "desktop", "Windows"},
// iPhone
{"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1", ua.Safari, "10.0", "mobile", "iOS"},
{"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) CriOS/60.0.3112.89 Mobile/14F89 Safari/602.1", ua.Chrome, "60.0.3112.89", "mobile", "iOS"},
{"Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) OPiOS/14.0.0.104835 Mobile/13E233 Safari/9537.53", ua.Opera, "14.0.0.104835", "mobile", "iOS"},
{"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) FxiOS/8.1.1b4948 Mobile/14F89 Safari/603.2.4", ua.Firefox, "8.1.1b4948", "mobile", "iOS"},
// iPad
{"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1", ua.Safari, "10.0", "tablet", "iOS"},
{"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/58.0.3029.113 Mobile/14F89 Safari/602.1", ua.Chrome, "58.0.3029.113", "tablet", "iOS"},
{"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) FxiOS/8.1.1b4948 Mobile/14F89 Safari/603.2.4", ua.Firefox, "8.1.1b4948", "tablet", "iOS"},
// Andorid
{"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", ua.Chrome, "59.0.3071.125", "mobile", "Android"},
{"Mozilla/5.0 (Android 4.3; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0", ua.Firefox, "54.0", "mobile", "Android"},
{"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.9.2246.119956", ua.Opera, "42.9.2246.119956", "mobile", ua.Android},
{"Opera/9.80 (Android; Opera Mini/28.0.2254/66.318; U; en) Presto/2.12.423 Version/12.16", ua.OperaMini, "28.0.2254/66.318", "mobile", "Android"},
{"Mozilla/5.0 (Linux; U; Android 4.3; en-us; GT-I9300 Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", "Android browser", "4.0", "mobile", "Android"},
{"Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F/A310FXXU2BQB1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", "Samsung Browser", "5.4", "mobile", "Android"},
// Windows phone
{"Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; NOKIA; Lumia 630)", ua.InternetExplorer, "7.0", "mobile", ua.WindowsPhone},
// Bots
{"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", ua.Googlebot, "2.1", "mobile", "Android"},
{"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", ua.Googlebot, "2.1", "bot", ""},
{"Twitterbot/1.0", ua.Twitterbot, "1.0", "bot", ""},
{"facebookexternalhit/1.1", ua.FacebookExternalHit, "1.1", "bot", ""},
// other
{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 Google (+https://developers.google.com/+/web/snippet/)", ua.Chrome, "56.0.2924.87", "bot", ua.Linux}, // Google+ fetch
// tools
{"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.6.0 Chrome/45.0.2454.101 Safari/537.36", "QtWebEngine", "5.6.0", "", "macOS"},
{"Go-http-client/1.1", "Go-http-client", "1.1", "", ""},
{"Wget/1.12 (linux-gnu)", "Wget", "1.12", "", ""},
{"Wget/1.17.1 (darwin15.2.0)", "Wget", "1.17.1", "", ""},
// unstandard stuff
{"BUbiNG (+http://law.di.unimi.it/BUbiNG.html)", "BUbiNG", "", "", ""},
//GooglePlus "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 Google (+https://developers.google.com/+/web/snippet/)"
//Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5 (Applebot/0.1; +http://www.apple.com/go/applebot)
//Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.6.0 Chrome/45.0.2454.101 Safari/537.36
}
for _, test := range testTable {
ua := ua.Parse(test[0])
if ua.Name != test[1] {
t.Error("\n", test[0], "\nName should be", test[1], "not", ua.Name)
}
if ua.Version != test[2] {
t.Error("\nVersion should be", test[2], "not", ua.Version)
}
if len(test) > 3 {
if test[3] == "desktop" && ua.Mobile {
t.Error("\n", ua.String, "should be desktop type not mobile")
}
if test[3] == "mobile" && !ua.Mobile {
t.Error("\n", ua.String, "should be mobile")
}
if test[3] == "tablet" && !ua.Tablet {
t.Error("\n", ua.String, "should be tablet")
}
}
if len(test) > 4 && test[4] != ua.OS {
t.Error("\n", test[0], "OS should", test[4], "not", ua.OS)
}
//fmt.Println(ua.OS, ua.OSVersion, ua.Device)
}
}
func ExampleParse() {
userAgents := []string{
// Mac
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.91 Safari/537.36 Vivaldi/1.92.917.39",
// Windows
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2; GWX:RED)",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) NS8/0.9.6",
// iPhone
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) CriOS/60.0.3112.89 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) OPiOS/14.0.0.104835 Mobile/13E233 Safari/9537.53",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) FxiOS/8.1.1b4948 Mobile/14F89 Safari/603.2.4",
// iPad
"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.0 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/58.0.3029.113 Mobile/14F89 Safari/602.1",
"Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) FxiOS/8.1.1b4948 Mobile/14F89 Safari/603.2.4",
// Andorid
"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36",
"Mozilla/5.0 (Android 4.3; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0",
"Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.9.2246.119956",
"Opera/9.80 (Android; Opera Mini/28.0.2254/66.318; U; en) Presto/2.12.423 Version/12.16",
"Mozilla/5.0 (Linux; U; Android 4.3; en-us; GT-I9300 Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A310F/A310FXXU2BQB1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36",
}
for _, s := range userAgents {
ua := ua.Parse(s)
fmt.Println()
fmt.Println(ua.String)
fmt.Println(strings.Repeat("=", len(ua.String)))
fmt.Println("Name:", ua.Name, "v", ua.Version)
fmt.Println("OS:", ua.OS, "v", ua.OSVersion)
fmt.Println("Device:", ua.Device)
if ua.Mobile {
fmt.Println("(Mobile)")
}
if ua.Tablet {
fmt.Println("(Tablet)")
}
if ua.Desktop {
fmt.Println("(Desktop)")
}
if ua.Bot {
fmt.Println("(Bot)")
}
if ua.URL != "" {
fmt.Println(ua.URL)
}
}
}