blob: a690fac2ba8a2e591cf270c8f459f403568c67d7 [file] [log] [blame]
Marcel van Lohuizen1588fe02019-07-29 21:33:24 +02001// 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
15package net
16
17import (
18 "fmt"
19 "net"
20 "strconv"
21 "unicode/utf8"
22
23 "cuelang.org/go/cue"
24 "golang.org/x/net/idna"
25)
26
27var idnaProfile = idna.New(
28 idna.ValidateLabels(true),
29 idna.VerifyDNSLength(true),
30 idna.StrictDomainName(true),
31)
32
33// SplitHostPort splits a network address of the form "host:port",
34// "host%zone:port", "[host]:port" or "[host%zone]:port" into host or host%zone
35// and port.
36//
37// A literal IPv6 address in hostport must be enclosed in square brackets, as in
38// "[::1]:80", "[::1%lo0]:80".
39func SplitHostPort(s string) (hostport []string, err error) {
40 host, port, err := net.SplitHostPort(s)
41 if err != nil {
42 return nil, err
43 }
44 return []string{host, port}, nil
45}
46
47// JoinHostPort combines host and port into a network address of the
48// form "host:port". If host contains a colon, as found in literal
49// IPv6 addresses, then JoinHostPort returns "[host]:port".
50//
51// See func Dial for a description of the host and port parameters.
52func JoinHostPort(host, port cue.Value) (string, error) {
53 var err error
54 hostStr := ""
55 switch host.Kind() {
56 case cue.ListKind:
57 ipdata := netGetIP(host)
58 if len(ipdata) != 4 && len(ipdata) != 16 {
59 err = fmt.Errorf("invalid host %q", host)
60 }
61 hostStr = ipdata.String()
62 case cue.BytesKind:
63 var b []byte
64 b, err = host.Bytes()
65 hostStr = string(b)
66 default:
67 hostStr, err = host.String()
68 }
69 if err != nil {
70 return "", err
71 }
72
73 portStr := ""
74 switch port.Kind() {
75 case cue.StringKind:
76 portStr, err = port.String()
77 case cue.BytesKind:
78 var b []byte
79 b, err = port.Bytes()
80 portStr = string(b)
81 default:
82 var i int64
83 i, err = port.Int64()
84 portStr = strconv.Itoa(int(i))
85 }
86 if err != nil {
87 return "", err
88 }
89
90 return net.JoinHostPort(hostStr, portStr), nil
91}
92
93// FQDN reports whether is is a valid fully qualified domain name.
94//
95// FQDN allows only ASCII characters as prescribed by RFC 1034 (A-Z, a-z, 0-9
96// and the hyphen).
97func FQDN(s string) bool {
98 for i := 0; i < len(s); i++ {
99 if s[i] >= utf8.RuneSelf {
100 return false
101 }
102 }
103 _, err := idnaProfile.ToASCII(s)
104 return err == nil
105}