wsproxy

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package wsproxy provides a reusable WebSocket proxy handler with hook-based observation points and target resolution abstractions.

The package intentionally does not own persistence, monitor payloads, or any application-specific storage schema. Callers can attach their own hooks and keep UI or backend compatibility layers outside the transport engine.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"

	"github.com/gorilla/websocket"
)

func main() {
	upgrader := websocket.Upgrader{CheckOrigin: func(*http.Request) bool { return true }}
	upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			return
		}
		defer conn.Close()
		mt, msg, err := conn.ReadMessage()
		if err != nil {
			return
		}
		_ = conn.WriteMessage(mt, []byte("upstream:"+string(msg)))
	}))
	defer upstream.Close()

	handler, err := New(Options{
		Resolver: QueryTargetResolver{NormalizeScheme: true},
	})
	if err != nil {
		panic(err)
	}
	proxy := httptest.NewServer(handler)
	defer proxy.Close()

	target := url.QueryEscape(upstream.URL + "/echo")
	conn, _, err := websocket.DefaultDialer.Dial(httpToWS(proxy.URL)+"/proxy?_target="+target, nil)
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	if err := conn.WriteMessage(websocket.TextMessage, []byte("hello")); err != nil {
		panic(err)
	}
	_, msg, err := conn.ReadMessage()
	if err != nil {
		panic(err)
	}

	fmt.Println(string(msg))
}

func httpToWS(raw string) string {
	return "ws" + strings.TrimPrefix(raw, "http")
}
Output:
upstream:hello

Index

Examples

Constants

View Source
const (
	DirectionClientToUpstream = observe.DirectionClientToUpstream
	DirectionUpstreamToClient = observe.DirectionUpstreamToClient
)
View Source
const (
	MessageText   = observe.WSMessageText
	MessageBinary = observe.WSMessageBinary
	MessagePing   = observe.WSMessagePing
	MessagePong   = observe.WSMessagePong
	MessageClose  = observe.WSMessageClose
	MessageOther  = observe.WSMessageOther
)

Variables

View Source
var (
	ErrMissingTarget = errors.New("missing target")
	ErrInvalidTarget = errors.New("invalid target")
)

Functions

This section is empty.

Types

type CloseInfo

type CloseInfo = observe.CloseInfo

type Direction

type Direction = observe.Direction

type ErrorInfo

type ErrorInfo = observe.ErrorInfo

type ErrorWriter

type ErrorWriter func(http.ResponseWriter, *http.Request, int, error)

type ForwardDecision

type ForwardDecision struct {
	Drop  bool
	Delay time.Duration
}

type Frame

type Frame = observe.WSFrame

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

func New

func New(opts Options) (*Handler, error)

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Hooks

type Hooks struct {
	OnSessionOpen      func(context.Context, Session) error
	OnSessionConnected func(context.Context, Session, *websocket.Conn, *websocket.Conn)
	OnFrame            func(context.Context, Frame) error
	OnError            func(context.Context, ErrorInfo)
	OnSessionClose     func(context.Context, CloseInfo)
}

type MessageType

type MessageType = observe.WSMessageType

type Options

type Options struct {
	Resolver               TargetResolver
	ObserveTarget          func(*url.URL) bool
	GenerateSessionID      func() string
	HandshakeTimeout       time.Duration
	InsecureTLS            bool
	AllowPlaintextFallback bool
	BeforeForward          func(Direction, MessageType, int) ForwardDecision
	ForwardHeaders         []string
	SynthesizeOrigin       bool
	WriteError             ErrorWriter
	Hooks                  Hooks
	Upgrader               websocket.Upgrader
}

type QueryTargetResolver

type QueryTargetResolver struct {
	Param           string
	DefaultTarget   string
	DropParams      []string
	NormalizeScheme bool
}

func (QueryTargetResolver) Resolve

func (r QueryTargetResolver) Resolve(req *http.Request) (*url.URL, error)

type ResolveTargetFunc

type ResolveTargetFunc func(*http.Request) (*url.URL, error)

func (ResolveTargetFunc) Resolve

func (f ResolveTargetFunc) Resolve(r *http.Request) (*url.URL, error)

type Session

type Session = observe.Session

type TargetResolver

type TargetResolver interface {
	Resolve(*http.Request) (*url.URL, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL