go-hep.org/x/hep@v0.40.0/xrootd/xrdio/parse.go (about)

     1  // Copyright ©2018 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package xrdio
     6  
     7  import (
     8  	"fmt"
     9  	"net"
    10  	"strings"
    11  )
    12  
    13  // URL stores an absolute reference to a XRootD path.
    14  type URL struct {
    15  	Addr string // address (host [:port]) of the server
    16  	User string // user name to use to log in
    17  	Path string // path to the remote file or directory
    18  }
    19  
    20  // Parse parses name into an xrootd URL structure.
    21  func Parse(name string) (URL, error) {
    22  	// FIXME(sbinet): just use url.Parse instead ?
    23  
    24  	var (
    25  		user string
    26  		addr string
    27  		path string
    28  		err  error
    29  	)
    30  
    31  	idx := strings.Index(name, "://")
    32  	switch idx {
    33  	case -1:
    34  		path = name
    35  	default:
    36  		uri := name[idx+len("://"):]
    37  		tok := strings.SplitN(uri, "/", 2)
    38  		user, addr, err = parseUA(tok[0])
    39  		if err != nil {
    40  			return URL{}, fmt.Errorf("could not parse URI %q: %w", name, err)
    41  		}
    42  		path = "/" + tok[1]
    43  	}
    44  
    45  	if strings.HasPrefix(path, "//") {
    46  		path = path[1:]
    47  	}
    48  
    49  	return URL{Addr: addr, User: user, Path: path}, nil
    50  }
    51  
    52  func parseUA(s string) (user, addr string, err error) {
    53  	switch {
    54  	case strings.Contains(s, "@"):
    55  		toks := strings.SplitN(s, "@", 2)
    56  		user = parseUser(toks[0])
    57  		addr = toks[1]
    58  	default:
    59  		addr = s
    60  	}
    61  
    62  	switch {
    63  	case strings.HasPrefix(addr, "["): // IPv6 literal
    64  		idx := strings.LastIndex(addr, "]")
    65  		col := strings.Index(addr[idx+1:], ":")
    66  		if col >= 0 {
    67  			_, _, err = net.SplitHostPort(addr)
    68  		}
    69  	case strings.Contains(addr, ":"):
    70  		_, _, err = net.SplitHostPort(addr)
    71  	}
    72  
    73  	if err != nil {
    74  		return "", "", fmt.Errorf("could not extract host+port from URI: %w", err)
    75  	}
    76  
    77  	return user, addr, nil
    78  }
    79  
    80  func parseUser(s string) string {
    81  	usr, _, ok := strings.Cut(s, ":")
    82  	if !ok {
    83  		return s
    84  	}
    85  	return usr
    86  }