Skip to content

Commit 2aff559

Browse files
committed
tunnel: introduce custom Duration for time fields
All Tunnel timeout values are based on seconds however, there isn't a great way to do this in a flexible way with Go due to `time.Duration` not having marshal/unmarshal support in Go 1[1]. Instead, we introduce a custom `TunnelDuration` value here and ensure it always converts durations into seconds without impacting other users of `time.Duration`. [1]: golang/go#10275
1 parent bddcc22 commit 2aff559

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

.changelog/1303.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:breaking-change
2+
tunnel: swap `ConnectTimeout`, `TLSTimeout`, `TCPKeepAlive` and `KeepAliveTimeout` to `TunnelDuration` instead of `time.Duration`
3+
```

tunnel.go

+29-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,34 @@ import (
66
"errors"
77
"fmt"
88
"net/http"
9+
"strconv"
910
"time"
1011
)
1112

13+
// A TunnelDuration is a Duration that has custom serialization for JSON.
14+
// JSON in Javascript assumes that int fields are 32 bits and Duration fields
15+
// are deserialized assuming that numbers are in nanoseconds, which in 32bit
16+
// integers limits to just 2 seconds. This type assumes that when
17+
// serializing/deserializing from JSON, that the number is in seconds, while it
18+
// maintains the YAML serde assumptions.
19+
type TunnelDuration struct {
20+
time.Duration
21+
}
22+
23+
func (s TunnelDuration) MarshalJSON() ([]byte, error) {
24+
return json.Marshal(s.Duration.Seconds())
25+
}
26+
27+
func (s *TunnelDuration) UnmarshalJSON(data []byte) error {
28+
seconds, err := strconv.ParseInt(string(data), 10, 64)
29+
if err != nil {
30+
return err
31+
}
32+
33+
s.Duration = time.Duration(seconds * int64(time.Second))
34+
return nil
35+
}
36+
1237
// ErrMissingTunnelID is for when a required tunnel ID is missing from the
1338
// parameters.
1439
var ErrMissingTunnelID = errors.New("required missing tunnel ID")
@@ -118,17 +143,17 @@ type UnvalidatedIngressRule struct {
118143
// config.
119144
type OriginRequestConfig struct {
120145
// HTTP proxy timeout for establishing a new connection
121-
ConnectTimeout *time.Duration `json:"connectTimeout,omitempty"`
146+
ConnectTimeout *TunnelDuration `json:"connectTimeout,omitempty"`
122147
// HTTP proxy timeout for completing a TLS handshake
123-
TLSTimeout *time.Duration `json:"tlsTimeout,omitempty"`
148+
TLSTimeout *TunnelDuration `json:"tlsTimeout,omitempty"`
124149
// HTTP proxy TCP keepalive duration
125-
TCPKeepAlive *time.Duration `json:"tcpKeepAlive,omitempty"`
150+
TCPKeepAlive *TunnelDuration `json:"tcpKeepAlive,omitempty"`
126151
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
127152
NoHappyEyeballs *bool `json:"noHappyEyeballs,omitempty"`
128153
// HTTP proxy maximum keepalive connection pool size
129154
KeepAliveConnections *int `json:"keepAliveConnections,omitempty"`
130155
// HTTP proxy timeout for closing an idle connection
131-
KeepAliveTimeout *time.Duration `json:"keepAliveTimeout,omitempty"`
156+
KeepAliveTimeout *TunnelDuration `json:"keepAliveTimeout,omitempty"`
132157
// Sets the HTTP Host header for the local webserver.
133158
HTTPHostHeader *string `json:"httpHostHeader,omitempty"`
134159
// Hostname on the origin server certificate.

tunnel_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ func TestUpdateTunnelConfiguration(t *testing.T) {
189189
fmt.Fprint(w, loadFixture("tunnel", "configuration"))
190190
}
191191

192+
timeout, _ := time.ParseDuration("10s")
192193
mux.HandleFunc(fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/configurations", testAccountID, testTunnelID), handler)
193194
want := TunnelConfigurationResult{
194195
TunnelID: testTunnelID,
@@ -210,7 +211,7 @@ func TestUpdateTunnelConfiguration(t *testing.T) {
210211
Enabled: true,
211212
},
212213
OriginRequest: OriginRequestConfig{
213-
ConnectTimeout: DurationPtr(10),
214+
ConnectTimeout: &TunnelDuration{timeout},
214215
},
215216
}}
216217

@@ -233,7 +234,7 @@ func TestUpdateTunnelConfiguration(t *testing.T) {
233234
Enabled: true,
234235
},
235236
OriginRequest: OriginRequestConfig{
236-
ConnectTimeout: DurationPtr(10 * time.Second),
237+
ConnectTimeout: &TunnelDuration{10},
237238
},
238239
},
239240
})
@@ -254,6 +255,7 @@ func TestGetTunnelConfiguration(t *testing.T) {
254255
fmt.Fprint(w, loadFixture("tunnel", "configuration"))
255256
}
256257

258+
timeout, _ := time.ParseDuration("10s")
257259
mux.HandleFunc(fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/configurations", testAccountID, testTunnelID), handler)
258260
want := TunnelConfigurationResult{
259261
TunnelID: testTunnelID,
@@ -275,7 +277,7 @@ func TestGetTunnelConfiguration(t *testing.T) {
275277
Enabled: true,
276278
},
277279
OriginRequest: OriginRequestConfig{
278-
ConnectTimeout: DurationPtr(10),
280+
ConnectTimeout: &TunnelDuration{timeout},
279281
},
280282
}}
281283

0 commit comments

Comments
 (0)