Documentation
¶
Overview ¶
Package browserproxy renders web pages server-side with the pure-Go go-webengine/engine and streams frames (plus a hyperlink hit-map) to a client over a simple JSON WebSocket protocol, forwarding the client's input back as navigation. This file is the SSRF guard: the security boundary that keeps a proxied page from reaching the host's own network.
Index ¶
- Constants
- Variables
- func CheckAddr(network, address string) error
- func CheckURL(rawurl string) error
- type Config
- type Options
- type RenderFunc
- type Server
- type Session
- func (s *Session) Back(ctx context.Context) error
- func (s *Session) Click(ctx context.Context, x, y int) (bool, error)
- func (s *Session) Forward(ctx context.Context) error
- func (s *Session) FrameSlice() (png []byte, w, h, offsetY int, err error)
- func (s *Session) Navigate(ctx context.Context, url string) error
- func (s *Session) Resize(ctx context.Context, w, h int) error
- func (s *Session) Scroll(dy int) int
- func (s *Session) StateMsg() *browserpb.State
- func (s *Session) Viewport() (w, h int)
Constants ¶
const (
// DefaultPath is the HTTP path the gRPC-over-WebSocket endpoint is served on.
DefaultPath = "/ws"
)
Variables ¶
var ( // ErrRateLimited is returned when a session navigates faster than the // configured per-session minimum interval. ErrRateLimited = fmt.Errorf("browserproxy: navigation rate limit exceeded") // ErrNoHistory is returned by Back/Forward when there is nowhere to go. ErrNoHistory = fmt.Errorf("browserproxy: no history entry") )
Session-level errors (in addition to guard's ErrBlocked).
var ErrBlocked = fmt.Errorf("browserproxy: request blocked by SSRF guard")
ErrBlocked is the sentinel wrapped by every guard rejection, so callers can test errors.Is(err, ErrBlocked) without matching on message text.
Functions ¶
func CheckAddr ¶
CheckAddr is the dynamic (post-DNS) half of the guard, wired as a net.Dialer.Control so it runs after resolution and immediately before the socket connects — covering the top navigation, every subresource, every redirect target and DNS-rebinding. address is "host:port" with host already an IP literal (Control always receives a resolved address).
func CheckURL ¶
CheckURL is the static (pre-DNS) half of the SSRF guard. It rejects any URL that is not a plain http(s) request to a public host: a non-http(s) scheme (file:, data:, gopher:, ftp:, javascript:, …), a missing host, an internal-namespace host suffix, or a host given as a literal private/loopback/link-local IP. DNS names that *resolve* to a blocked address are caught later by CheckAddr at dial time (so DNS-rebinding cannot slip past this static check).
Types ¶
type Config ¶
type Config struct {
// AllowedOrigins is the WebSocket Origin allowlist. An empty list allows any
// origin (development default); a list containing "*" also allows any;
// otherwise the browser Origin must match one entry. Non-browser clients
// (no Origin header) are always allowed.
AllowedOrigins []string
// DefaultW, DefaultH are the initial viewport size for a new session.
DefaultW, DefaultH int
// MaxConcurrentRenders caps concurrent renders across all sessions. Zero
// means unlimited.
MaxConcurrentRenders int
MinNavInterval time.Duration
// RenderTimeout bounds a single navigation/render. Zero uses defaultRenderTimeout.
RenderTimeout time.Duration
// Logger, when non-nil, receives non-fatal transport diagnostics.
Logger *log.Logger
}
Config configures a Server.
type Options ¶
type Options struct {
// GlobalLimiter caps the number of concurrent renders across all sessions
// sharing it. A nil limiter means unlimited.
GlobalLimiter chan struct{}
// session (rate limit). Zero disables it.
MinNavInterval time.Duration
// MaxHistory caps each of the back/forward stacks. Zero uses defaultMaxHistory.
MaxHistory int
}
Options configures a session's limits.
type RenderFunc ¶
type RenderFunc func(ctx context.Context, url string, w, h int) (*image.RGBA, *engine.RenderInfo, []engine.Link, error)
RenderFunc fetches and renders url at viewport w×h, returning the full-page image, page info and hyperlink hit-map. The default is engine-backed; tests inject a fake so all session logic is exercisable without the network.
type Server ¶
type Server struct {
browserpb.UnimplementedBrowserServer
// contains filtered or unexported fields
}
Server implements the browserpb.Browser gRPC service: each Session stream drives one browser tab. It is transport-agnostic — mount it with Server.HandlerListener (gRPC over WebSocket, browser-reachable) or register it on any grpc.Server via Server.Register.
func (*Server) HandlerListener ¶
HandlerListener returns an http.Handler that upgrades WebSocket requests on path into gRPC connections for this service, plus a shutdown func that stops the backing grpc.Server gracefully. Mounting the handler on an http.ServeMux lets the gRPC endpoint and a wasm client share one origin. The empty path defaults to DefaultPath.
func (*Server) Register ¶
Register registers the Server on gs as the browserpb.Browser service. Use it when embedding the service in a grpc.Server you own (e.g. alongside other services or a custom transport); otherwise prefer Server.HandlerListener.
func (*Server) Session ¶
func (srv *Server) Session(stream browserpb.Browser_SessionServer) error
Session implements browserpb.BrowserServer: it runs one browser tab for the lifetime of the bidirectional stream. It sends the initial (empty) chrome state, then loops receiving client input and streaming back the resulting frames and state until the client closes the stream or a send fails.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is one browser tab's server-side state: the current full-page image and its hit-map, the scroll offset, the viewport size, and a back/forward history. All exported methods are safe for concurrent use.
func NewSession ¶
NewSession creates a session with a real engine-backed renderer whose HTTP client is wrapped by the SSRF-guarded dial control (so navigation and every subresource are guarded at dial time).
func (*Session) Click ¶
Click resolves a content-area click (viewport pixel coords) against the hit-map at the current scroll and, if it lands inside a link, navigates to it. It reports whether a navigation happened. A miss (or a click before any page loads) is a no-op returning (false, nil).
func (*Session) FrameSlice ¶
FrameSlice returns the current viewport as a fresh w×h PNG taken at the current scroll offset, plus the slice size and offset. Before any page loads (or where the page is shorter than the viewport) the uncovered area is white, so the client canvas is always fully painted.
func (*Session) Navigate ¶
Navigate loads url as a new history entry: the current page (if any) is pushed onto the back stack and the forward stack is cleared.
func (*Session) Resize ¶
Resize sets a new viewport size and re-renders the current page at the new width (a width change changes layout). If no page is loaded it just records the size. The scroll offset is preserved and re-clamped.
func (*Session) Scroll ¶
Scroll adjusts the vertical scroll by dy pixels (positive = down), clamped to the page, without re-rendering. It reports the new offset.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
browserproxy
command
Command browserproxy serves the go-webengine remote-browser endpoint: it renders web pages server-side with the pure-Go engine and streams frames to a client (e.g.
|
Command browserproxy serves the go-webengine remote-browser endpoint: it renders web pages server-side with the pure-Go engine and streams frames to a client (e.g. |
|
Command wasmclient is the browser-side half of the wasm end-to-end test and a worked example of a GOOS=js/wasm browserproxy client.
|
Command wasmclient is the browser-side half of the wasm end-to-end test and a worked example of a GOOS=js/wasm browserproxy client. |
