frp/pkg/util/net/websocket.go

91 lines
1.7 KiB
Go

package net
import (
"errors"
"net"
"net/http"
"time"
"golang.org/x/net/websocket"
)
var ErrWebsocketListenerClosed = errors.New("websocket listener closed")
var FrpWebsocketPath = "/~!frp"
type WebsocketListener struct {
ln net.Listener
acceptCh chan net.Conn
server *http.Server
}
// NewWebsocketListener to handle websocket connections
// ln: tcp listener for websocket connections
func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
wl = &WebsocketListener{
acceptCh: make(chan net.Conn),
}
muxer := http.NewServeMux()
muxer.Handle(FrpWebsocketPath, websocket.Handler(func(c *websocket.Conn) {
notifyCh := make(chan struct{})
conn := WrapCloseNotifyConn(c, func() {
close(notifyCh)
})
wl.acceptCh <- conn
<-notifyCh
}))
wl.server = &http.Server{
Addr: ln.Addr().String(),
Handler: muxer,
ReadHeaderTimeout: 60 * time.Second,
}
go func() {
_ = wl.server.Serve(ln)
}()
return
}
func (p *WebsocketListener) Accept() (net.Conn, error) {
c, ok := <-p.acceptCh
if !ok {
return nil, ErrWebsocketListenerClosed
}
return c, nil
}
func (p *WebsocketListener) Close() error {
return p.server.Close()
}
func (p *WebsocketListener) Addr() net.Addr {
return p.ln.Addr()
}
func GetWsPrefixPath() string {
return FrpWebsocketPath
}
func SetWsPrefixPath(path string) {
if path != "" {
if HasPrefix(path, "/") {
FrpWebsocketPath = path
} else {
FrpWebsocketPath = "/" + path
}
} else {
FrpWebsocketPath = "/~!frp"
}
}
func HasPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}
func HasSuffix(s, suffix string) bool {
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}