refact: remove unnecessary log, helper
Kim committed
Mar 6, 2026 at 14:11 UTC
c54baadde6fdb3cd53c48aad7e613002feb6f61e
7 files changed
+57
-103
cmd/portal-tunnel/main.go
+6
-21
@@ -7,7 +7,6 @@ import (
7
"fmt"
8
"io"
9
"net"
10
- "net/url"
10
"os"
11
"os/signal"
12
"strings"
@@ -18,6 +17,7 @@ import (
17
"github.com/rs/zerolog"
18
"github.com/rs/zerolog/log"
19
20
+ "gosuda.org/portal/portal"
21
"gosuda.org/portal/sdk"
22
)
23
@@ -68,7 +68,7 @@ func runTunnel() error {
68
if len(relayURLs) == 0 {
69
return errors.New("no relay URLs provided")
70
}
71
- relayURL, err := normalizeRelayURLsForReverseConnect(relayURLs)
71
+ relayURL, err := portal.NormalizeRelayURL(relayURLs[0])
72
if err != nil {
73
return err
74
}
@@ -89,7 +89,7 @@ func runTunnel() error {
89
90
listener, err := sdkClient.Listen(ctx, sdk.ListenRequest{
91
Name: flagName,
92
- Metadata: sdk.LeaseMetadata{
92
+ Metadata: portal.LeaseMetadata{
93
Description: flagDesc,
94
Tags: parseURLs(flagTags),
95
Owner: flagOwner,
@@ -172,24 +172,6 @@ loop:
172
return nil
173
}
174
175
-func normalizeRelayURLsForReverseConnect(relayURLs []string) (string, error) {
176
- raw := relayURLs[0]
177
- u, err := url.Parse(strings.TrimSpace(raw))
178
- if err != nil {
179
- return "", fmt.Errorf("parse relay url: %w", err)
180
- }
181
- if !strings.EqualFold(u.Scheme, "https") {
182
- return "", fmt.Errorf("relay url must use https: %q", raw)
183
- }
184
- if u.Host == "" {
185
- return "", fmt.Errorf("relay url host is empty: %q", raw)
186
- }
187
- u.Path = strings.TrimRight(u.Path, "/")
188
- u.RawQuery = ""
189
- u.Fragment = ""
190
- return u.String(), nil
191
-}
192
-
175
var bufferPool = sync.Pool{
176
New: func() any {
177
b := make([]byte, 64*1024)
@@ -250,6 +232,9 @@ func proxyConnection(ctx context.Context, localAddr string, relayConn net.Conn)
232
}
233
234
close(stopCh)
235
+ if errors.Is(firstErr, io.EOF) || errors.Is(firstErr, net.ErrClosed) {
236
+ return nil
237
+ }
238
return firstErr
239
}
240
cmd/relay-server/admin.go
+13
-5
@@ -1,7 +1,9 @@
1
package main
2
3
import (
4
+ "crypto/subtle"
5
"encoding/base64"
6
+ "encoding/json"
7
"fmt"
8
"net/http"
9
"strings"
@@ -39,7 +41,9 @@ func (a *Admin) HandleAdminRequest(w http.ResponseWriter, r *http.Request) {
41
case "/admin":
42
a.handleAdminIndex(w)
43
case "/admin/leases":
42
- writeJSON(w, http.StatusOK, convertLeaseEntriesToRows(a.server, true, a.frontend.portalURL))
44
+ w.Header().Set("Content-Type", "application/json")
45
+ w.WriteHeader(http.StatusOK)
46
+ _ = json.NewEncoder(w).Encode(convertLeaseEntriesToRows(a.server, true, a.frontend.portalURL))
47
default:
48
http.NotFound(w, r)
49
}
@@ -55,18 +59,22 @@ func (a *Admin) authorize(r *http.Request) bool {
59
if a.secret == "" {
60
return true
61
}
58
- if subtleValueMatch(strings.TrimSpace(r.URL.Query().Get("key")), a.secret) {
62
+ queryKey := strings.TrimSpace(r.URL.Query().Get("key"))
63
+ if queryKey != "" && subtle.ConstantTimeCompare([]byte(queryKey), []byte(a.secret)) == 1 {
64
return true
65
}
66
auth := strings.TrimSpace(r.Header.Get("Authorization"))
62
- if strings.HasPrefix(strings.ToLower(auth), "bearer ") && subtleValueMatch(strings.TrimSpace(auth[7:]), a.secret) {
63
- return true
67
+ if strings.HasPrefix(strings.ToLower(auth), "bearer ") {
68
+ bearerToken := strings.TrimSpace(auth[7:])
69
+ if bearerToken != "" && subtle.ConstantTimeCompare([]byte(bearerToken), []byte(a.secret)) == 1 {
70
+ return true
71
+ }
72
}
73
if strings.HasPrefix(strings.ToLower(auth), "basic ") {
74
raw, err := base64.StdEncoding.DecodeString(strings.TrimSpace(auth[6:]))
75
if err == nil {
76
parts := strings.SplitN(string(raw), ":", 2)
69
- if len(parts) == 2 && subtleValueMatch(parts[1], a.secret) {
77
+ if len(parts) == 2 && parts[1] != "" && subtle.ConstantTimeCompare([]byte(parts[1]), []byte(a.secret)) == 1 {
78
return true
79
}
80
}
cmd/relay-server/http_helpers.go
-24
@@ -1,34 +1,10 @@
1
package main
2
3
import (
4
- "crypto/subtle"
5
- "encoding/json"
4
"mime"
7
- "net/http"
5
"strings"
6
)
7
11
-func writeJSON(w http.ResponseWriter, status int, data any) {
12
- w.Header().Set("Content-Type", "application/json")
13
- w.WriteHeader(status)
14
- _ = json.NewEncoder(w).Encode(data)
15
-}
16
-
17
-func hasPathPrefix(path, prefix string) bool {
18
- return strings.HasPrefix(strings.TrimSpace(path), prefix)
19
-}
20
-
21
-func trimPathPrefix(path, prefix string) string {
22
- return strings.TrimPrefix(strings.TrimSpace(path), prefix)
23
-}
24
-
25
-func subtleValueMatch(left, right string) bool {
26
- if left == "" || right == "" {
27
- return false
28
- }
29
- return subtle.ConstantTimeCompare([]byte(left), []byte(right)) == 1
30
-}
31
-
8
func getContentType(ext string) string {
9
ext = strings.TrimSpace(ext)
10
if ext == "" {
cmd/relay-server/serve.go
+9
-21
@@ -3,7 +3,6 @@ package main
3
import (
4
"context"
5
"fmt"
6
- "net"
6
"net/http"
7
"os"
8
"os/signal"
@@ -56,7 +55,7 @@ func runServer(cfg relayServerConfig) error {
55
APIListenAddr: apiListenAddr,
56
SNIListenAddr: sniListenAddr,
57
RootHost: rootHost,
59
- RootFallbackAddr: loopbackAddr(apiListenAddr),
58
+ RootFallbackAddr: portal.HostPortOrLoopback(apiListenAddr),
59
KeylessSignerHandler: func() http.Handler {
60
if signer == nil {
61
return nil
@@ -67,7 +66,7 @@ func runServer(cfg relayServerConfig) error {
66
CertPEM: mustRead(certFile),
67
KeyPEM: mustRead(keyFile),
68
},
70
- APIHandlerWrapper: serveAPI(frontend, admin, signer, cfg),
69
+ APIHandlerWrapper: serveAPI(frontend, admin, cfg),
70
})
71
if err != nil {
72
return fmt.Errorf("create relay server: %w", err)
@@ -83,7 +82,7 @@ func runServer(cfg relayServerConfig) error {
82
defer acmeManager.Stop()
83
84
logger.Info().
86
- Str("api_addr", loopbackAddr(server.APIAddr())).
85
+ Str("api_addr", portal.HostPortOrLoopback(server.APIAddr())).
86
Str("sni_addr", server.SNIAddr()).
87
Str("root_host", rootHost).
88
Bool("acme_enabled", !strings.HasSuffix(rootHost, "localhost") && rootHost != "127.0.0.1" && rootHost != "::1").
@@ -92,7 +91,7 @@ func runServer(cfg relayServerConfig) error {
91
return server.Wait()
92
}
93
95
-func serveAPI(frontend *Frontend, admin *Admin, signer *keyless.Signer, cfg relayServerConfig) func(http.Handler) http.Handler {
94
+func serveAPI(frontend *Frontend, admin *Admin, cfg relayServerConfig) func(http.Handler) http.Handler {
95
return func(base http.Handler) http.Handler {
96
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
97
switch {
@@ -104,19 +103,19 @@ func serveAPI(frontend *Frontend, admin *Admin, signer *keyless.Signer, cfg rela
103
base.ServeHTTP(w, r)
104
case isFrontendRootAssetPath(r.URL.Path):
105
frontend.ServeAsset(w, r, strings.TrimPrefix(r.URL.Path, "/"), "")
107
- case hasPathPrefix(r.URL.Path, "/assets/"):
106
+ case strings.HasPrefix(strings.TrimSpace(r.URL.Path), "/assets/"):
107
frontend.ServeAsset(w, r, strings.TrimPrefix(r.URL.Path, "/"), "")
108
case r.URL.Path == "/" || r.URL.Path == "/app" || r.URL.Path == "/app/":
109
frontend.ServeAppStatic(w, r, "")
111
- case hasPathPrefix(r.URL.Path, "/app/"):
112
- frontend.ServeAppStatic(w, r, trimPathPrefix(r.URL.Path, "/app/"))
110
+ case strings.HasPrefix(strings.TrimSpace(r.URL.Path), "/app/"):
111
+ frontend.ServeAppStatic(w, r, strings.TrimPrefix(strings.TrimSpace(r.URL.Path), "/app/"))
112
case r.URL.Path == "/admin" || r.URL.Path == "/admin/":
113
admin.HandleAdminRequest(w, r)
115
- case hasPathPrefix(r.URL.Path, "/admin/"):
114
+ case strings.HasPrefix(strings.TrimSpace(r.URL.Path), "/admin/"):
115
admin.HandleAdminRequest(w, r)
116
case r.URL.Path == "/tunnel":
117
serveTunnelScript(w, r, cfg.PortalURL)
119
- case hasPathPrefix(r.URL.Path, "/tunnel/bin/"):
118
+ case strings.HasPrefix(strings.TrimSpace(r.URL.Path), "/tunnel/bin/"):
119
serveTunnelBinary(w, r)
120
default:
121
base.ServeHTTP(w, r)
@@ -140,17 +139,6 @@ func isFrontendRootAssetPath(requestPath string) bool {
139
}
140
}
141
143
-func loopbackAddr(addr string) string {
144
- host, port, err := net.SplitHostPort(addr)
145
- if err != nil {
146
- return addr
147
- }
148
- if host == "" || host == "0.0.0.0" || host == "::" {
149
- host = "127.0.0.1"
150
- }
151
- return net.JoinHostPort(host, port)
152
-}
153
-
142
func mustRead(path string) []byte {
143
if path == "" {
144
log.Fatal().Msg("missing required PEM path")
portal/helpers.go
+1
-1
@@ -139,7 +139,7 @@ func normalizeTags(tags []string) []string {
139
return out
140
}
141
142
-func hostPortOrLoopback(addr string) string {
142
+func HostPortOrLoopback(addr string) string {
143
host, port, err := net.SplitHostPort(addr)
144
if err != nil {
145
return addr
portal/server.go
+2
-2
@@ -590,7 +590,7 @@ func (s *Server) handleSNIConn(conn net.Conn) {
590
591
func (s *Server) bridgeToFallback(conn net.Conn) {
592
dialer := &net.Dialer{Timeout: 5 * time.Second}
593
- upstream, err := dialer.DialContext(s.context(), "tcp", hostPortOrLoopback(s.cfg.RootFallbackAddr))
593
+ upstream, err := dialer.DialContext(s.context(), "tcp", HostPortOrLoopback(s.cfg.RootFallbackAddr))
594
if err != nil {
595
_ = conn.Close()
596
return
@@ -644,7 +644,7 @@ func (s *Server) watchContext() error {
644
func (s *Server) connectURL() string {
645
base := strings.TrimRight(s.cfg.PortalURL, "/")
646
if base == "" && s.apiListener != nil {
647
- return "https://" + hostPortOrLoopback(s.apiListener.Addr().String()) + "/sdk/connect"
647
+ return "https://" + HostPortOrLoopback(s.apiListener.Addr().String()) + "/sdk/connect"
648
}
649
return base + "/sdk/connect"
650
}
sdk/client.go
+26
-29
@@ -60,12 +60,24 @@ func NewClient(cfg ClientConfig) (*Client, error) {
60
return nil, err
61
}
62
63
- cfg.DialTimeout = durationOrDefault(cfg.DialTimeout, 5*time.Second)
64
- cfg.RequestTimeout = durationOrDefault(cfg.RequestTimeout, 15*time.Second)
65
- cfg.HandshakeTimeout = durationOrDefault(cfg.HandshakeTimeout, 15*time.Second)
66
- cfg.LeaseTTL = durationOrDefault(cfg.LeaseTTL, 2*time.Minute)
67
- cfg.RenewBefore = durationOrDefault(cfg.RenewBefore, 30*time.Second)
68
- cfg.ReadyTarget = intOrDefault(cfg.ReadyTarget, 1)
63
+ if cfg.DialTimeout <= 0 {
64
+ cfg.DialTimeout = 5 * time.Second
65
+ }
66
+ if cfg.RequestTimeout <= 0 {
67
+ cfg.RequestTimeout = 15 * time.Second
68
+ }
69
+ if cfg.HandshakeTimeout <= 0 {
70
+ cfg.HandshakeTimeout = 15 * time.Second
71
+ }
72
+ if cfg.LeaseTTL <= 0 {
73
+ cfg.LeaseTTL = 2 * time.Minute
74
+ }
75
+ if cfg.RenewBefore <= 0 {
76
+ cfg.RenewBefore = 30 * time.Second
77
+ }
78
+ if cfg.ReadyTarget <= 0 {
79
+ cfg.ReadyTarget = 1
80
+ }
81
82
baseTLS := &tls.Config{
83
MinVersion: tls.VersionTLS12,
@@ -114,8 +126,14 @@ func (c *Client) Listen(ctx context.Context, req ListenRequest) (*Listener, erro
126
reverseToken = randomToken()
127
}
128
117
- readyTarget := intOrDefault(req.ReadyTarget, c.readyTarget)
118
- leaseTTL := durationOrDefault(req.LeaseTTL, c.leaseTTL)
129
+ readyTarget := req.ReadyTarget
130
+ if readyTarget <= 0 {
131
+ readyTarget = c.readyTarget
132
+ }
133
+ leaseTTL := req.LeaseTTL
134
+ if leaseTTL <= 0 {
135
+ leaseTTL = c.leaseTTL
136
+ }
137
138
registerReq := portal.RegisterRequest{
139
Name: req.Name,
@@ -287,27 +305,6 @@ func buildRootCAs(rootCAPEM []byte) (*x509.CertPool, error) {
305
return pool, nil
306
}
307
290
-func durationOrDefault(v, fallback time.Duration) time.Duration {
291
- if v > 0 {
292
- return v
293
- }
294
- return fallback
295
-}
296
-
297
-func intOrDefault(v, fallback int) int {
298
- if v > 0 {
299
- return v
300
- }
301
- return fallback
302
-}
303
-
304
-func max(a, b int) int {
305
- if a > b {
306
- return a
307
- }
308
- return b
309
-}
310
-
308
func randomToken() string {
309
buf := make([]byte, 8)
310
if _, err := rand.Read(buf); err != nil {