+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
\ No newline at end of file
diff --git a/vendor/github.com/fumiama/terasu/README.md b/vendor/github.com/fumiama/terasu/README.md
new file mode 100644
index 00000000..5f25408a
--- /dev/null
+++ b/vendor/github.com/fumiama/terasu/README.md
@@ -0,0 +1,21 @@
+
+
+
+
+# TeRaSu (TRS)
+
+よの光遍く空へ照しつつ
+
+土棲むものは孰れか見ゆや
+
+
+
+
+
+## Usage
+
+```go
+tls.Client(terasu.NewConn(conn), &tls.Config{
+ ServerName: host,
+}).Handshake()
+```
diff --git a/vendor/github.com/fumiama/terasu/builder.go b/vendor/github.com/fumiama/terasu/builder.go
new file mode 100644
index 00000000..39668c17
--- /dev/null
+++ b/vendor/github.com/fumiama/terasu/builder.go
@@ -0,0 +1,28 @@
+package terasu
+
+import (
+ "io"
+ "net"
+)
+
+type builder net.Buffers
+
+func newbuilder() builder {
+ return builder{}
+}
+
+// move is write without copy
+func (bd *builder) move(b []byte) {
+ *bd = append(*bd, b)
+}
+
+func (bd *builder) send(conn *net.TCPConn, rs ...io.Reader) (int64, error) {
+ if len(rs) == 0 {
+ return conn.ReadFrom((*net.Buffers)(bd))
+ }
+ return conn.ReadFrom(io.MultiReader(append([]io.Reader{(*net.Buffers)(bd)}, rs...)...))
+}
+
+func (bd *builder) reset() {
+ *bd = (*bd)[:0]
+}
diff --git a/vendor/github.com/fumiama/terasu/conn.go b/vendor/github.com/fumiama/terasu/conn.go
new file mode 100644
index 00000000..be4b8118
--- /dev/null
+++ b/vendor/github.com/fumiama/terasu/conn.go
@@ -0,0 +1,203 @@
+package terasu
+
+import (
+ "encoding/binary"
+ "io"
+ "net"
+ "reflect"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// DefaultFirstFragmentLen ...
+var DefaultFirstFragmentLen = 4
+
+// Conn remote: real server; local: relay
+type Conn struct {
+ relay relay
+ isold uintptr
+ init *sync.Once
+ conn *net.TCPConn
+}
+
+// NewConn wraps *net.TCPConn (net.Conn must be *net.TCPConn)
+func NewConn(conn net.Conn) *Conn {
+ c := &Conn{
+ relay: newrelay(),
+ init: &sync.Once{},
+ conn: conn.(*net.TCPConn),
+ }
+ switch o := conn.(type) {
+ case *net.TCPConn:
+ c.conn = o
+ default:
+ panic("unsupported conn type: " + reflect.TypeOf(conn).String())
+ }
+ return c
+}
+
+// Write is send
+func (conn *Conn) Write(b []byte) (int, error) {
+ if atomic.LoadUintptr(&conn.isold) != 0 || DefaultFirstFragmentLen == 0 {
+ return conn.conn.Write(b)
+ }
+ go conn.init.Do(func() {
+ _, err := io.Copy(conn, &conn.relay)
+ if err != nil {
+ _ = conn.relay.Close()
+ }
+ })
+ return conn.relay.Write(b)
+}
+
+// ReadFrom when client want to send to server, detect and split.
+func (conn *Conn) ReadFrom(r io.Reader) (n int64, err error) {
+ if atomic.LoadUintptr(&conn.isold) != 0 || DefaultFirstFragmentLen == 0 {
+ return conn.conn.ReadFrom(r)
+ }
+
+ defer atomic.StoreUintptr(&conn.isold, 1)
+
+ // ContentType [0:1]
+ // Version [1:3]
+ // Length [3:5]
+ // Payload[Length] ->
+ // HandshakeType [5:6]
+ // HandshakeBodyLength [6:9]
+ var header [1 + 2 + 2 + 1 + 3]byte
+ x := DefaultFirstFragmentLen
+ // preserved as tmp vars
+ plen := uint16(0)
+ var b []byte
+ bd := newbuilder()
+
+ // ContentType [0:1] Version [1:2] 0x03
+ _, err = io.ReadFull(r, header[:2])
+ if err != nil {
+ return
+ }
+ // recordTypeHandshake = 0x16
+ // Version [1:2] = 0x03
+ if binary.BigEndian.Uint16(header[:2]) != 0x1603 {
+ bd.move(header[:2])
+ goto PIPE
+ }
+ // Version [2:3] (0x01 1.0) (0x02 1.1) (0x03 1.2) (0x04 1.3)
+ _, err = io.ReadFull(r, header[2:3])
+ if err != nil {
+ return
+ }
+ // skip unsupported version
+ if header[2] < 1 || header[2] > 4 {
+ bd.move(header[:3])
+ goto PIPE
+ }
+ // Length [3:5] HandshakeType [5:6]
+ _, err = io.ReadFull(r, header[3:6])
+ if err != nil {
+ return
+ }
+ // skip unsupported handshake type
+ if header[5] != 0x01 { // client hello
+ bd.move(header[:6])
+ goto PIPE
+ }
+ // HandshakeBodyLength [6:9]
+ _, err = io.ReadFull(r, header[6:9])
+ if err != nil {
+ return
+ }
+ plen = binary.BigEndian.Uint16(header[3:5])
+ if binary.BigEndian.Uint32(header[5:9])&0x00ffffff+ // body
+ // handshake type, body length
+ 1+3 !=
+ // payload length
+ uint32(plen) {
+ bd.move(header[:9])
+ goto PIPE
+ }
+
+ // split
+ if x <= 4 { // first is in header range
+ // first
+ binary.BigEndian.PutUint16(header[3:5], uint16(x))
+ bd.move(header[:5+x])
+ n, err = bd.send(conn.conn)
+ bd.reset()
+ if err != nil {
+ return
+ }
+ copy(header[5:9-x], header[5+x:9])
+ // second
+ binary.BigEndian.PutUint16(header[3:5], plen-uint16(x))
+ bd.move(header[:9-x])
+ goto PIPE
+ }
+ // first is out of header range
+ // first
+ binary.BigEndian.PutUint16(header[3:5], uint16(x))
+ bd.move(header[:9])
+ b = make([]byte, x-4)
+ _, err = io.ReadFull(r, b)
+ if err != nil {
+ return
+ }
+ bd.move(b)
+ n, err = bd.send(conn.conn)
+ bd.reset()
+ if err != nil {
+ return
+ }
+ // second
+ binary.BigEndian.PutUint16(header[3:5], plen-uint16(x))
+ bd.move(header[:5])
+PIPE:
+ if err != nil {
+ return
+ }
+ _ = conn.relay.Close()
+ cnt, err := bd.send(conn.conn, r)
+ n += cnt
+ return
+}
+
+// Read is recv
+func (conn *Conn) Read(b []byte) (int, error) {
+ return conn.conn.Read(b)
+}
+
+// WriteTo remote response and releay it to local client without any change.
+func (conn *Conn) WriteTo(w io.Writer) (int64, error) {
+ return conn.conn.WriteTo(w)
+}
+
+// Close closes the connection.
+func (conn *Conn) Close() error {
+ return conn.conn.Close()
+}
+
+// LocalAddr returns the local network address.
+func (conn *Conn) LocalAddr() net.Addr {
+ return conn.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (conn *Conn) RemoteAddr() net.Addr {
+ return conn.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+func (conn *Conn) SetDeadline(t time.Time) error {
+ return conn.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the deadline for future Read calls.
+func (conn *Conn) SetReadDeadline(t time.Time) error {
+ return conn.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the deadline for future Write calls.
+func (conn *Conn) SetWriteDeadline(t time.Time) error {
+ return conn.conn.SetWriteDeadline(t)
+}
diff --git a/vendor/github.com/fumiama/terasu/relay.go b/vendor/github.com/fumiama/terasu/relay.go
new file mode 100644
index 00000000..9730d6bf
--- /dev/null
+++ b/vendor/github.com/fumiama/terasu/relay.go
@@ -0,0 +1,72 @@
+package terasu
+
+import (
+ "io"
+ "sync"
+)
+
+type relay struct {
+ mu sync.Mutex
+ buf chan []byte
+ rem []byte
+}
+
+func newrelay() relay {
+ return relay{buf: make(chan []byte, 64)}
+}
+
+// Read ...
+func (r *relay) Read(p []byte) (n int, err error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ switch {
+ case len(p) == 0:
+ return
+ case len(p) <= len(r.rem):
+ n = copy(p, r.rem)
+ r.rem = r.rem[n:]
+ if len(r.rem) == 0 {
+ r.rem = nil
+ }
+ return
+ case len(r.rem) > 0:
+ n = copy(p, r.rem)
+ r.rem = nil
+ fallthrough
+ default:
+ for n < len(p) {
+ buf := <-r.buf
+ if len(buf) == 0 {
+ err = io.EOF
+ return
+ }
+ switch {
+ case len(buf) >= len(p)-n:
+ cnt := copy(p[n:], buf)
+ n += cnt
+ r.rem = buf[cnt:]
+ if len(r.rem) == 0 {
+ r.rem = nil
+ }
+ return
+ default:
+ n += copy(p[n:], buf)
+ }
+ }
+ }
+ panic("unexpected")
+}
+
+// Write ...
+func (r *relay) Write(p []byte) (n int, err error) {
+ buf := make([]byte, len(p))
+ n = copy(buf, p)
+ r.buf <- p
+ return
+}
+
+// Close ...
+func (r *relay) Close() error {
+ close(r.buf)
+ return nil
+}
diff --git a/vendor/github.com/getsentry/sentry-go/transport.go b/vendor/github.com/getsentry/sentry-go/transport.go
index 3722217e..77b329b6 100644
--- a/vendor/github.com/getsentry/sentry-go/transport.go
+++ b/vendor/github.com/getsentry/sentry-go/transport.go
@@ -2,16 +2,19 @@ package sentry
import (
"bytes"
+ "context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
+ "net"
"net/http"
"net/url"
"sync"
"time"
+ "github.com/fumiama/terasu"
"github.com/getsentry/sentry-go/internal/ratelimit"
)
@@ -260,6 +263,17 @@ func (t *HTTPTransport) Configure(options ClientOptions) {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
+ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+ dialer := &net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }
+ conn, err := dialer.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+ return terasu.NewConn(conn), nil
+ },
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
@@ -491,6 +505,17 @@ func (t *HTTPSyncTransport) Configure(options ClientOptions) {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
+ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+ dialer := &net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }
+ conn, err := dialer.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+ return terasu.NewConn(conn), nil
+ },
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
diff --git a/vendor/github.com/gobwas/ws/dialer.go b/vendor/github.com/gobwas/ws/dialer.go
index 64d46811..cf200e78 100644
--- a/vendor/github.com/gobwas/ws/dialer.go
+++ b/vendor/github.com/gobwas/ws/dialer.go
@@ -14,6 +14,7 @@ import (
"strings"
"time"
+ "github.com/fumiama/terasu"
"github.com/gobwas/httphead"
"github.com/gobwas/pool/pbufio"
)
@@ -231,6 +232,7 @@ func (d Dialer) dial(ctx context.Context, u *url.URL) (conn net.Conn, err error)
if err != nil {
return nil, err
}
+ conn = terasu.NewConn(conn)
tlsClient := d.TLSClient
if tlsClient == nil {
tlsClient = d.tlsClient
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
index 2efd8355..c7fa4fee 100644
--- a/vendor/github.com/gorilla/websocket/client.go
+++ b/vendor/github.com/gorilla/websocket/client.go
@@ -17,6 +17,8 @@ import (
"net/url"
"strings"
"time"
+
+ "github.com/fumiama/terasu"
)
// ErrBadHandshake is returned when the server response to opening handshake is
@@ -340,7 +342,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
if cfg.ServerName == "" {
cfg.ServerName = hostNoPort
}
- tlsConn := tls.Client(netConn, cfg)
+ tlsConn := tls.Client(terasu.NewConn(netConn), cfg)
netConn = tlsConn
if trace != nil && trace.TLSHandshakeStart != nil {
diff --git a/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go
index 9549fa92..1f7d490d 100644
--- a/vendor/github.com/miekg/dns/client.go
+++ b/vendor/github.com/miekg/dns/client.go
@@ -10,6 +10,8 @@ import (
"net"
"strings"
"time"
+
+ "github.com/fumiama/terasu"
)
const (
@@ -131,11 +133,23 @@ func (c *Client) DialContext(ctx context.Context, address string) (conn *Conn, e
if useTLS {
network = strings.TrimSuffix(network, "-tls")
- tlsDialer := tls.Dialer{
- NetDialer: &d,
- Config: c.TLSConfig,
+ var rawConn net.Conn
+ rawConn, err = d.DialContext(ctx, network, address)
+ if err == nil {
+ tlsCn := tls.Client(terasu.NewConn(rawConn), c.TLSConfig)
+ if deadline, ok := ctx.Deadline(); ok {
+ rawConn.SetDeadline(deadline)
+ }
+ err = tlsCn.Handshake()
+ if _, ok := ctx.Deadline(); ok {
+ rawConn.SetDeadline(time.Time{})
+ }
+ if err != nil {
+ rawConn.Close()
+ } else {
+ conn.Conn = tlsCn
+ }
}
- conn.Conn, err = tlsDialer.DialContext(ctx, network, address)
} else {
conn.Conn, err = d.DialContext(ctx, network, address)
}
diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go
index f26356b9..d6c1a64a 100644
--- a/vendor/golang.org/x/net/http2/transport.go
+++ b/vendor/golang.org/x/net/http2/transport.go
@@ -31,6 +31,7 @@ import (
"sync/atomic"
"time"
+ "github.com/fumiama/terasu"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
@@ -3275,13 +3276,22 @@ func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.M
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
- dialer := &tls.Dialer{
- Config: cfg,
- }
+ dialer := &net.Dialer{}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
- tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
+ tlsCn := tls.Client(terasu.NewConn(cn), cfg)
+ if deadline, ok := ctx.Deadline(); ok {
+ cn.SetDeadline(deadline)
+ }
+ err = tlsCn.Handshake()
+ if _, ok := ctx.Deadline(); ok {
+ cn.SetDeadline(time.Time{})
+ }
+ if err != nil {
+ cn.Close()
+ return nil, err
+ }
return tlsCn, nil
}
diff --git a/vendor/golang.org/x/net/websocket/dial.go b/vendor/golang.org/x/net/websocket/dial.go
index 8a2d83c4..3e6da5be 100644
--- a/vendor/golang.org/x/net/websocket/dial.go
+++ b/vendor/golang.org/x/net/websocket/dial.go
@@ -8,6 +8,9 @@ import (
"context"
"crypto/tls"
"net"
+ "time"
+
+ "github.com/fumiama/terasu"
)
func dialWithDialer(ctx context.Context, dialer *net.Dialer, config *Config) (conn net.Conn, err error) {
@@ -16,12 +19,23 @@ func dialWithDialer(ctx context.Context, dialer *net.Dialer, config *Config) (co
conn, err = dialer.DialContext(ctx, "tcp", parseAuthority(config.Location))
case "wss":
- tlsDialer := &tls.Dialer{
- NetDialer: dialer,
- Config: config.TlsConfig,
+ var rawConn net.Conn
+ rawConn, err = dialer.DialContext(ctx, "tcp", parseAuthority(config.Location))
+ if err == nil {
+ tlsCn := tls.Client(terasu.NewConn(rawConn), config.TlsConfig)
+ if deadline, ok := ctx.Deadline(); ok {
+ rawConn.SetDeadline(deadline)
+ }
+ err = tlsCn.Handshake()
+ if _, ok := ctx.Deadline(); ok {
+ rawConn.SetDeadline(time.Time{})
+ }
+ if err != nil {
+ rawConn.Close()
+ } else {
+ conn = tlsCn
+ }
}
-
- conn, err = tlsDialer.DialContext(ctx, "tcp", parseAuthority(config.Location))
default:
err = ErrBadScheme
}
diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go
index bd5fe22b..1e868ff6 100644
--- a/vendor/google.golang.org/grpc/credentials/tls.go
+++ b/vendor/google.golang.org/grpc/credentials/tls.go
@@ -27,6 +27,7 @@ import (
"net/url"
"os"
+ "github.com/fumiama/terasu"
"google.golang.org/grpc/grpclog"
credinternal "google.golang.org/grpc/internal/credentials"
"google.golang.org/grpc/internal/envconfig"
@@ -102,7 +103,7 @@ func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawCon
}
cfg.ServerName = serverName
}
- conn := tls.Client(rawConn, cfg)
+ conn := tls.Client(terasu.NewConn(rawConn), cfg)
errChannel := make(chan error, 1)
go func() {
errChannel <- conn.Handshake()
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 32c80864..a0968f18 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -78,6 +78,9 @@ github.com/fortytw2/leaktest
# github.com/fsnotify/fsnotify v1.4.9
## explicit; go 1.13
github.com/fsnotify/fsnotify
+# github.com/fumiama/terasu v1.0.2
+## explicit; go 1.22
+github.com/fumiama/terasu
# github.com/getsentry/sentry-go v0.16.0
## explicit; go 1.19
github.com/getsentry/sentry-go