blob: 6018da4fb5943d19ea2f8c30c0ee58005e716230 [file] [log] [blame]
// Copyright 2019 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net
import (
"fmt"
"net"
"strconv"
"unicode/utf8"
"golang.org/x/net/idna"
"cuelang.org/go/cue"
)
var idnaProfile = idna.New(
idna.ValidateLabels(true),
idna.VerifyDNSLength(true),
idna.StrictDomainName(true),
)
// SplitHostPort splits a network address of the form "host:port",
// "host%zone:port", "[host]:port" or "[host%zone]:port" into host or host%zone
// and port.
//
// A literal IPv6 address in hostport must be enclosed in square brackets, as in
// "[::1]:80", "[::1%lo0]:80".
func SplitHostPort(s string) (hostport []string, err error) {
host, port, err := net.SplitHostPort(s)
if err != nil {
return nil, err
}
return []string{host, port}, nil
}
// JoinHostPort combines host and port into a network address of the
// form "host:port". If host contains a colon, as found in literal
// IPv6 addresses, then JoinHostPort returns "[host]:port".
//
// See func Dial for a description of the host and port parameters.
func JoinHostPort(host, port cue.Value) (string, error) {
var err error
hostStr := ""
switch host.Kind() {
case cue.ListKind:
ipdata := netGetIP(host)
if len(ipdata) != 4 && len(ipdata) != 16 {
err = fmt.Errorf("invalid host %q", host)
}
hostStr = ipdata.String()
case cue.BytesKind:
var b []byte
b, err = host.Bytes()
hostStr = string(b)
default:
hostStr, err = host.String()
}
if err != nil {
return "", err
}
portStr := ""
switch port.Kind() {
case cue.StringKind:
portStr, err = port.String()
case cue.BytesKind:
var b []byte
b, err = port.Bytes()
portStr = string(b)
default:
var i int64
i, err = port.Int64()
portStr = strconv.Itoa(int(i))
}
if err != nil {
return "", err
}
return net.JoinHostPort(hostStr, portStr), nil
}
// FQDN reports whether is is a valid fully qualified domain name.
//
// FQDN allows only ASCII characters as prescribed by RFC 1034 (A-Z, a-z, 0-9
// and the hyphen).
func FQDN(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf {
return false
}
}
_, err := idnaProfile.ToASCII(s)
return err == nil
}