Skip to content

Commit 656d524

Browse files
committed
frontent/dockerfile: apply improvements from go-connections
Apply the improvements from; docker/go-connections@ccab5a8 Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent ce1dd0b commit 656d524

File tree

2 files changed

+72
-22
lines changed

2 files changed

+72
-22
lines changed

frontend/dockerfile/dockerfile2llb/convert_expose.go

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func parsePortSpecs(ports []string) (exposedPorts []string, _ error) {
5858
func splitProtoPort(rawPort string) (proto string, port string, _ error) {
5959
port, proto, _ = strings.Cut(rawPort, "/")
6060
if port == "" {
61-
return "", "", errors.Errorf("no port specified: %s<empty>", rawPort)
61+
return "", "", errors.New("no port specified")
6262
}
6363
proto = strings.ToLower(proto)
6464
switch proto {
@@ -92,7 +92,7 @@ func parsePortSpec(rawPort string) (portProto []string, _ error) {
9292
ip, hostPort, containerPort := splitParts(rawPort)
9393
proto, containerPort, err := splitProtoPort(containerPort)
9494
if err != nil {
95-
return nil, err
95+
return nil, errors.Wrapf(err, "invalid port: %q", rawPort)
9696
}
9797

9898
// TODO(thaJeztah): mapping IP-addresses should not be allowed for EXPOSE; see https://github.com/moby/buildkit/issues/2173
@@ -114,9 +114,8 @@ func parsePortSpec(rawPort string) (portProto []string, _ error) {
114114
}
115115

116116
// TODO(thaJeztah): mapping host-ports should not be allowed for EXPOSE; see https://github.com/moby/buildkit/issues/2173
117-
var startHostPort, endHostPort uint64
118117
if hostPort != "" {
119-
startHostPort, endHostPort, err = parsePortRange(hostPort)
118+
startHostPort, endHostPort, err := parsePortRange(hostPort)
120119
if err != nil {
121120
return nil, errors.New("invalid hostPort: " + hostPort)
122121
}
@@ -134,36 +133,53 @@ func parsePortSpec(rawPort string) (portProto []string, _ error) {
134133
ports := make([]string, 0, count)
135134

136135
for i := range count {
137-
ports = append(ports, strconv.FormatUint(startPort+i, 10)+"/"+proto)
136+
ports = append(ports, strconv.Itoa(startPort+i)+"/"+proto)
138137
}
139138
return ports, nil
140139
}
141140

142-
// parsePortRange parses and validates the specified string as a port-range (8000-9000)
143-
func parsePortRange(ports string) (uint64, uint64, error) {
141+
// parsePortRange parses and validates the specified string as a port range (e.g., "8000-9000").
142+
func parsePortRange(ports string) (startPort, endPort int, _ error) {
144143
if ports == "" {
145144
return 0, 0, errors.New("empty string specified for ports")
146145
}
147-
if !strings.Contains(ports, "-") {
148-
start, err := strconv.ParseUint(ports, 10, 16)
149-
end := start
150-
return start, end, err
151-
}
146+
start, end, ok := strings.Cut(ports, "-")
152147

153-
parts := strings.Split(ports, "-")
154-
if len(parts) != 2 {
155-
return 0, 0, errors.Errorf("invalid port range format: %s", ports)
148+
startPort, err := parsePortNumber(start)
149+
if err != nil {
150+
return 0, 0, fmt.Errorf("invalid start port '%s': %w", start, err)
151+
}
152+
if !ok || start == end {
153+
return startPort, startPort, nil
156154
}
157-
start, err := strconv.ParseUint(parts[0], 10, 16)
155+
156+
endPort, err = parsePortNumber(end)
158157
if err != nil {
159-
return 0, 0, err
158+
return 0, 0, fmt.Errorf("invalid end port '%s': %w", end, err)
159+
}
160+
if endPort < startPort {
161+
return 0, 0, errors.New("invalid port range: " + ports)
160162
}
161-
end, err := strconv.ParseUint(parts[1], 10, 16)
163+
return startPort, endPort, nil
164+
}
165+
166+
// parsePortNumber parses rawPort into an int, unwrapping strconv errors
167+
// and returning a single "out of range" error for any value outside 0–65535.
168+
func parsePortNumber(rawPort string) (int, error) {
169+
if rawPort == "" {
170+
return 0, errors.New("value is empty")
171+
}
172+
port, err := strconv.ParseInt(rawPort, 10, 0)
162173
if err != nil {
163-
return 0, 0, err
174+
var numErr *strconv.NumError
175+
if errors.As(err, &numErr) {
176+
err = numErr.Err
177+
}
178+
return 0, err
164179
}
165-
if end < start {
166-
return 0, 0, errors.New("invalid range specified for port: " + ports)
180+
if port < 0 || port > 65535 {
181+
return 0, errors.New("value out of range (0–65535)")
167182
}
168-
return start, end, nil
183+
184+
return int(port), nil
169185
}

frontend/dockerfile/dockerfile2llb/convert_expose_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,40 @@ import (
66
"github.com/stretchr/testify/assert"
77
)
88

9+
func TestParsePortSpecEmptyContainerPort(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
spec string
13+
expError string
14+
}{
15+
{
16+
name: "empty spec",
17+
spec: "",
18+
expError: `invalid port: "": no port specified`,
19+
},
20+
{
21+
name: "empty container port",
22+
spec: `0.0.0.0:1234-1235:/tcp`,
23+
expError: `invalid port: "0.0.0.0:1234-1235:/tcp": no port specified`,
24+
},
25+
{
26+
name: "empty container port and proto",
27+
spec: `0.0.0.0:1234-1235:`,
28+
expError: `invalid port: "0.0.0.0:1234-1235:": no port specified`,
29+
},
30+
}
31+
for _, tc := range tests {
32+
t.Run(tc.name, func(t *testing.T) {
33+
_, err := parsePortSpec(tc.spec)
34+
if tc.expError != "" {
35+
assert.EqualError(t, err, tc.expError)
36+
} else {
37+
assert.NoError(t, err)
38+
}
39+
})
40+
}
41+
}
42+
943
func TestParsePortSpecFull(t *testing.T) {
1044
exposedPorts, err := parsePortSpec("0.0.0.0:1234-1235:3333-3334/tcp")
1145
assert.NoError(t, err)

0 commit comments

Comments
 (0)