bettercap/vendor/github.com/jpillora/go-tld/parse.go
2018-03-23 15:25:11 +01:00

109 lines
2 KiB
Go

//go:generate sh generate.sh
//The tld package has the same API as net/url except
//tld.URL contains extra fields: Subdomain, Domain, TLD and Port.
package tld
import (
"errors"
"net/url"
)
//URL embeds net/url and adds extra fields ontop
type URL struct {
Subdomain, Domain, TLD, Port string
*url.URL
}
//Parse mirrors net/url.Parse except instead it returns
//a tld.URL, which contains extra fields.
func Parse(s string) (*URL, error) {
url, err := url.Parse(s)
if err != nil {
return nil, err
}
if url.Host == "" {
return &URL{URL: url}, nil
}
//index of tld
tld := 0
dom, port := domainPort(url.Host)
i := 0
l := len(dom) - 1
//binary search the TLD list
lo := 0
hi := count - 1
for lo != hi && lo+1 != hi {
mid := (hi + lo) / 2
guess := list[mid]
//for binary search debugging...
// log.Printf("[%d - %d - %d] %s == %s (%s)", lo, mid, hi, string(dom[l-i]), string(guess[i]), guess)
if i < len(guess) && guess[i] == dom[l-i] {
//store partial match
if i > tld && guess[i] == '.' {
tld = i
}
//advance!
i++
//checked all is in guess
if len(guess) == i && dom[l-i] == '.' {
tld = i
break
}
} else if i >= len(guess) || guess[i] < dom[l-i] {
lo = mid
i = 0
} else {
hi = mid
i = 0
}
}
if tld == 0 {
return nil, errors.New("tld not found")
}
//extract the tld
t := dom[l-tld+1:]
//we can calculate the root domain
dom = dom[:l-tld]
//and subdomain
sub := ""
for i := len(dom) - 1; i >= 0; i-- {
if dom[i] == '.' {
sub = dom[:i]
dom = dom[i+1:]
break
}
}
return &URL{
Subdomain: sub,
Domain: dom,
TLD: t,
Port: port,
URL: url,
}, nil
}
func domainPort(host string) (string, string) {
for i := len(host) - 1; i >= 0; i-- {
if host[i] == ':' {
return host[:i], host[i+1:]
} else if host[i] < '0' || host[i] > '9' {
return host, ""
}
}
//will only land here if the string is all digits,
//net/url should prevent that from happening
return host, ""
}