cuelang.org/go@v0.10.1/pkg/net/host.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package net
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"strconv"
    21  	"unicode/utf8"
    22  
    23  	"golang.org/x/net/idna"
    24  
    25  	"cuelang.org/go/cue"
    26  )
    27  
    28  var idnaProfile = idna.New(
    29  	idna.ValidateLabels(true),
    30  	idna.VerifyDNSLength(true),
    31  	idna.StrictDomainName(true),
    32  )
    33  
    34  // SplitHostPort splits a network address of the form "host:port",
    35  // "host%zone:port", "[host]:port" or "[host%zone]:port" into host or host%zone
    36  // and port.
    37  //
    38  // A literal IPv6 address in hostport must be enclosed in square brackets, as in
    39  // "[::1]:80", "[::1%lo0]:80".
    40  func SplitHostPort(s string) (hostport []string, err error) {
    41  	host, port, err := net.SplitHostPort(s)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	return []string{host, port}, nil
    46  }
    47  
    48  // JoinHostPort combines host and port into a network address of the
    49  // form "host:port". If host contains a colon, as found in literal
    50  // IPv6 addresses, then JoinHostPort returns "[host]:port".
    51  //
    52  // See func Dial for a description of the host and port parameters.
    53  func JoinHostPort(host, port cue.Value) (string, error) {
    54  	var err error
    55  	hostStr := ""
    56  	switch host.Kind() {
    57  	case cue.ListKind:
    58  		ipdata := netGetIP(host)
    59  		if !ipdata.IsValid() {
    60  			err = fmt.Errorf("invalid host %s", host)
    61  		}
    62  		hostStr = ipdata.String()
    63  	case cue.BytesKind:
    64  		var b []byte
    65  		b, err = host.Bytes()
    66  		hostStr = string(b)
    67  	default:
    68  		hostStr, err = host.String()
    69  	}
    70  	if err != nil {
    71  		return "", err
    72  	}
    73  
    74  	portStr := ""
    75  	switch port.Kind() {
    76  	case cue.StringKind:
    77  		portStr, err = port.String()
    78  	case cue.BytesKind:
    79  		var b []byte
    80  		b, err = port.Bytes()
    81  		portStr = string(b)
    82  	default:
    83  		var i int64
    84  		i, err = port.Int64()
    85  		portStr = strconv.Itoa(int(i))
    86  	}
    87  	if err != nil {
    88  		return "", err
    89  	}
    90  
    91  	return net.JoinHostPort(hostStr, portStr), nil
    92  }
    93  
    94  // FQDN reports whether is a valid fully qualified domain name.
    95  //
    96  // FQDN allows only ASCII characters as prescribed by RFC 1034 (A-Z, a-z, 0-9
    97  // and the hyphen).
    98  func FQDN(s string) bool {
    99  	for i := 0; i < len(s); i++ {
   100  		if s[i] >= utf8.RuneSelf {
   101  			return false
   102  		}
   103  	}
   104  	_, err := idnaProfile.ToASCII(s)
   105  	return err == nil
   106  }