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  }