github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/rest/url.go (about) 1 package rest 2 3 import ( 4 "fmt" 5 "log" 6 "net/url" 7 "regexp" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/bingoohuang/gg/pkg/osx" 13 "github.com/bingoohuang/gg/pkg/rotate" 14 "github.com/bingoohuang/gg/pkg/ss" 15 "github.com/bingoohuang/gg/pkg/timex" 16 ) 17 18 var reScheme = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9+-.]*://`) 19 20 type FixURIConfig struct { 21 DefaultScheme string 22 DefaultHost string 23 DefaultPort int 24 FatalErr bool 25 Auth string 26 } 27 28 func WithDefaultScheme(v string) FixURIConfigFn { return func(c *FixURIConfig) { c.DefaultScheme = v } } 29 func WithDefaultHost(v string) FixURIConfigFn { return func(c *FixURIConfig) { c.DefaultHost = v } } 30 func WithDefaultPort(v int) FixURIConfigFn { return func(c *FixURIConfig) { c.DefaultPort = v } } 31 func WithFatalErr(v bool) FixURIConfigFn { return func(c *FixURIConfig) { c.FatalErr = v } } 32 func WithAuth(v string) FixURIConfigFn { return func(c *FixURIConfig) { c.Auth = v } } 33 34 type FixURIResult struct { 35 Data *url.URL 36 Err error 37 } 38 39 func (r FixURIResult) OK() bool { return r.Err == nil } 40 41 func FixURI(uri string, fns ...FixURIConfigFn) (rr FixURIResult) { 42 config := (FixURIConfigFns(fns)).Create() 43 defer func() { 44 if rr.Err != nil && config.FatalErr { 45 log.Fatal(rr.Err) 46 } 47 }() 48 49 if uri == ":" { 50 uri = ":" + strconv.Itoa(config.DefaultPort) 51 } 52 53 // ex) :8080/hello or /hello or : 54 if strings.HasPrefix(uri, ":") || strings.HasPrefix(uri, "/") { 55 uri = config.DefaultHost + uri 56 } 57 58 // ex) example.com/hello 59 if !reScheme.MatchString(uri) { 60 uri = config.DefaultScheme + "://" + uri 61 } 62 63 u, err := url.Parse(uri) 64 if err != nil { 65 rr.Err = fmt.Errorf("parse %s failed: %s", uri, err) 66 return rr 67 } 68 69 u.Host = strings.TrimSuffix(u.Host, ":") 70 if u.Path == "" { 71 u.Path = "/" 72 } 73 74 if config.Auth != "" { 75 if userpass := strings.Split(config.Auth, ":"); len(userpass) == 2 { 76 u.User = url.UserPassword(userpass[0], userpass[1]) 77 } else { 78 u.User = url.User(config.Auth) 79 } 80 } 81 82 return FixURIResult{Data: u} 83 } 84 85 func MaybeURL(out string) (string, bool) { 86 if out == "stdout" || out == "sterr" || strings.HasPrefix(out, "stdout:") || strings.HasPrefix(out, "stderr:") { 87 return "", false 88 } 89 90 if ss.HasPrefix(out, "http://", "https://") { 91 return out, true 92 } 93 94 if ss.HasPrefix(out, ":", "/", ".") { 95 uri := FixURI(out) 96 return uri.Data.String(), uri.OK() 97 } 98 99 if osx.CanExpandHome(out) { 100 return osx.ExpandHome(out), false 101 } 102 103 if ss.Contains(out, ".txt", ".log", ".gz", ".out", ".http", ".json") { 104 return out, false 105 } 106 107 if fn := timex.FormatTime(time.Now(), out); fn != out { 108 return "", false 109 } 110 111 // like ip:port 112 if regexp.MustCompile(`^\d{1,3}((.\d){1,3}){3}(:\d+)?`).MatchString(out) { 113 uri := FixURI(out) 114 return uri.Data.String(), uri.OK() 115 } 116 117 c := &rotate.Config{} 118 if rotate.ParseOutputPath(c, out); c.Append || c.MaxSize > 0 { 119 return "", false 120 } 121 122 uri := FixURI(out) 123 return uri.Data.String(), uri.OK() 124 } 125 126 type FixURIConfigFn func(*FixURIConfig) 127 128 type FixURIConfigFns []FixURIConfigFn 129 130 func (fns FixURIConfigFns) Create() *FixURIConfig { 131 c := &FixURIConfig{ 132 DefaultScheme: "http", 133 DefaultHost: "127.0.0.1", 134 } 135 136 for _, f := range fns { 137 f(c) 138 } 139 140 return c 141 }