mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 05:09:58 +00:00
Add db-connect, a SQL over HTTPS server
This commit is contained in:
179
vendor/github.com/xo/dburl/util.go
generated
vendored
Normal file
179
vendor/github.com/xo/dburl/util.go
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
package dburl
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// contains code taken from go1.8, for purposes of backwards compatability with
|
||||
// older go versions.
|
||||
|
||||
// hostname returns u.Host, without any port number.
|
||||
//
|
||||
// If Host is an IPv6 literal with a port number, Hostname returns the
|
||||
// IPv6 literal without the square brackets. IPv6 literals may include
|
||||
// a zone identifier.
|
||||
func hostname(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return hostport
|
||||
}
|
||||
if i := strings.IndexByte(hostport, ']'); i != -1 {
|
||||
return strings.TrimPrefix(hostport[:i], "[")
|
||||
}
|
||||
return hostport[:colon]
|
||||
}
|
||||
|
||||
// hostport returns the port part of u.Host, without the leading colon.
|
||||
// If u.Host doesn't contain a port, Port returns an empty string.
|
||||
func hostport(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return ""
|
||||
}
|
||||
if i := strings.Index(hostport, "]:"); i != -1 {
|
||||
return hostport[i+len("]:"):]
|
||||
}
|
||||
if strings.Contains(hostport, "]") {
|
||||
return ""
|
||||
}
|
||||
return hostport[colon+len(":"):]
|
||||
}
|
||||
|
||||
// genOptions takes URL values and generates options, joining together with
|
||||
// joiner, and separated by sep, with any multi URL values joined by valSep,
|
||||
// ignoring any values with keys in ignore.
|
||||
//
|
||||
// For example, to build a "ODBC" style connection string, use like the following:
|
||||
// genOptions(u.Query(), "", "=", ";", ",")
|
||||
func genOptions(q url.Values, joiner, assign, sep, valSep string, skipWhenEmpty bool, ignore ...string) string {
|
||||
qlen := len(q)
|
||||
if qlen == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// make ignore map
|
||||
ig := make(map[string]bool, len(ignore))
|
||||
for _, v := range ignore {
|
||||
ig[strings.ToLower(v)] = true
|
||||
}
|
||||
|
||||
// sort keys
|
||||
s := make([]string, len(q))
|
||||
var i int
|
||||
for k := range q {
|
||||
s[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(s)
|
||||
|
||||
var opts []string
|
||||
for _, k := range s {
|
||||
if !ig[strings.ToLower(k)] {
|
||||
val := strings.Join(q[k], valSep)
|
||||
if !skipWhenEmpty || val != "" {
|
||||
if val != "" {
|
||||
val = assign + val
|
||||
}
|
||||
opts = append(opts, k+val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts) != 0 {
|
||||
return joiner + strings.Join(opts, sep)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// genOptionsODBC is a util wrapper around genOptions that uses the fixed settings
|
||||
// for ODBC style connection strings.
|
||||
func genOptionsODBC(q url.Values, skipWhenEmpty bool, ignore ...string) string {
|
||||
return genOptions(q, "", "=", ";", ",", skipWhenEmpty, ignore...)
|
||||
}
|
||||
|
||||
// genQueryOptions generates standard query options.
|
||||
func genQueryOptions(q url.Values) string {
|
||||
if s := q.Encode(); s != "" {
|
||||
return "?" + s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// convertOptions converts an option value based on name, value pairs.
|
||||
func convertOptions(q url.Values, pairs ...string) url.Values {
|
||||
n := make(url.Values)
|
||||
for k, v := range q {
|
||||
x := make([]string, len(v))
|
||||
for i, z := range v {
|
||||
for j := 0; j < len(pairs); j += 2 {
|
||||
if pairs[j] == z {
|
||||
z = pairs[j+1]
|
||||
}
|
||||
}
|
||||
x[i] = z
|
||||
}
|
||||
n[k] = x
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// mode returns the mode of the path.
|
||||
func mode(path string) os.FileMode {
|
||||
if fi, err := os.Stat(path); err == nil {
|
||||
return fi.Mode()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// resolveSocket tries to resolve a path to a Unix domain socket based on the
|
||||
// form "/path/to/socket/dbname" returning either the original path and the
|
||||
// empty string, or the components "/path/to/socket" and "dbname", when
|
||||
// /path/to/socket/dbname is reported by os.Stat as a socket.
|
||||
//
|
||||
// Used for MySQL DSNs.
|
||||
func resolveSocket(path string) (string, string) {
|
||||
dir, dbname := path, ""
|
||||
for dir != "" && dir != "/" && dir != "." {
|
||||
if m := mode(dir); m&os.ModeSocket != 0 {
|
||||
return dir, dbname
|
||||
}
|
||||
dir, dbname = stdpath.Dir(dir), stdpath.Base(dir)
|
||||
}
|
||||
|
||||
return path, ""
|
||||
}
|
||||
|
||||
// resolveDir resolves a directory with a :port list.
|
||||
//
|
||||
// Used for PostgreSQL DSNs.
|
||||
func resolveDir(path string) (string, string, string) {
|
||||
dir := path
|
||||
for dir != "" && dir != "/" && dir != "." {
|
||||
port := ""
|
||||
i, j := strings.LastIndex(dir, ":"), strings.LastIndex(dir, "/")
|
||||
if i != -1 && i > j {
|
||||
port = dir[i+1:]
|
||||
dir = dir[:i]
|
||||
}
|
||||
|
||||
if mode(dir)&os.ModeDir != 0 {
|
||||
rest := strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(path, dir), ":"+port), "/")
|
||||
return dir, port, rest
|
||||
}
|
||||
|
||||
if j != -1 {
|
||||
dir = dir[:j]
|
||||
} else {
|
||||
dir = ""
|
||||
}
|
||||
}
|
||||
|
||||
return path, "", ""
|
||||
}
|
Reference in New Issue
Block a user