github.com/milanaleksic/devd@v1.0.4/routespec/routespec.go (about)

     1  package routespec
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/url"
     7  	"strings"
     8  )
     9  
    10  const defaultDomain = "devd.io"
    11  
    12  func checkURL(s string) (isURL bool, err error) {
    13  	var parsed *url.URL
    14  
    15  	parsed, err = url.Parse(s)
    16  	if err != nil {
    17  		return
    18  	}
    19  
    20  	switch {
    21  	case parsed.Scheme == "": // No scheme means local file system
    22  		isURL = false
    23  	case parsed.Scheme == "http", parsed.Scheme == "https":
    24  		isURL = true
    25  	case parsed.Scheme == "ws":
    26  		err = fmt.Errorf("Websocket protocol not supported: %s", s)
    27  	default:
    28  		// A route of "localhost:1234/abc" without the "http" or "https" triggers this case.
    29  		// Unfortunately a route of "localhost/abc" just looks like a file and is not caught here.
    30  		err = fmt.Errorf("Unknown scheme '%s': did you mean http or https?: %s", parsed.Scheme, s)
    31  	}
    32  	return
    33  }
    34  
    35  // A RouteSpec is a parsed route specification
    36  type RouteSpec struct {
    37  	Host  string
    38  	Path  string
    39  	Value string
    40  	IsURL bool
    41  }
    42  
    43  // MuxMatch produces a match clause suitable for passing to a Mux
    44  func (rp *RouteSpec) MuxMatch() string {
    45  	// Path is guaranteed to start with /
    46  	return rp.Host + rp.Path
    47  }
    48  
    49  // ParseRouteSpec parses a string route specification
    50  func ParseRouteSpec(s string) (*RouteSpec, error) {
    51  	seq := strings.SplitN(s, "=", 2)
    52  	var path, value, host string
    53  	if len(seq) == 1 {
    54  		path = "/"
    55  		value = seq[0]
    56  	} else {
    57  		path = seq[0]
    58  		value = seq[1]
    59  	}
    60  	if path == "" || value == "" {
    61  		return nil, errors.New("Invalid specification")
    62  	}
    63  	if path[0] != '/' {
    64  		seq := strings.SplitN(path, "/", 2)
    65  		host = seq[0] + "." + defaultDomain
    66  		switch len(seq) {
    67  		case 1:
    68  			path = "/"
    69  		case 2:
    70  			path = "/" + seq[1]
    71  		}
    72  	}
    73  	if value[0] == ':' {
    74  		value = "http://localhost" + value
    75  	}
    76  	isURL, err := checkURL(value)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return &RouteSpec{host, path, value, isURL}, nil
    81  }