server

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package server is vrok's HTTP layer: it maps share URLs onto local files, directories and upstream applications, and enforces expiry, passwords and download limits on every request.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Chain

func Chain(h http.Handler, mw ...Middleware) http.Handler

Chain applies middleware so that the first argument is the outermost layer.

func SharePath

func SharePath(token string) string

SharePath returns the path a share is served under, for callers that need to build an absolute URL from a public origin.

Types

type Crumb

type Crumb struct {
	Name string
	URL  string
}

Crumb is one breadcrumb entry. It mirrors viewer.Crumb so the server can build navigation without the viewer package leaking into every handler.

type DirectoryHandler

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

DirectoryHandler serves a directory tree, confined to its root.

func (DirectoryHandler) ServeShare

func (h DirectoryHandler) ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)

ServeShare implements ShareHandler.

type FileSetHandler

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

FileSetHandler serves several unrelated files through a generated index.

func (FileSetHandler) ServeShare

func (h FileSetHandler) ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)

ServeShare implements ShareHandler.

type Gate

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

Gate enforces the optional share password.

A successful unlock is remembered with a signed cookie rather than by storing the password client-side. The signing key is generated per process, so cookies die with the share — which is the same lifetime promise the URL itself makes.

func NewGate

func NewGate(hasher security.Hasher, signer security.Signer, p *pages, logger *slog.Logger) *Gate

NewGate returns a Gate.

func (*Gate) Allow

func (g *Gate) Allow(w http.ResponseWriter, r *http.Request, sr *shareRequest) bool

Allow reports whether the request may proceed to the share content.

When it returns false it has already written the response: the unlock form, or a redirect back to the requested page after a successful unlock.

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

Links builds every URL a share page needs. Centralising this means path escaping is done once, correctly, instead of at each call site.

func NewLinks(token string) Links

NewLinks returns a link builder for a share token. The token is the whole path, so a link reads https://host/<token>/ with no extra segment.

func NewRootLinks() Links

NewRootLinks builds links for a share served at the origin itself. A Cloudflare quick tunnel's hostname is already unguessable, so the public link is https://<host> with nothing after it.

func (Links) Archive added in v0.2.0

func (l Links) Archive(rel string) string

Archive returns the URL that streams a folder, or a whole multi-file share, as one zip.

func (Links) Breadcrumbs

func (l Links) Breadcrumbs(root, rel string) []Crumb

Breadcrumbs splits a relative path into cumulative links, excluding the final element, which the page renders as plain text.

func (Links) Download

func (l Links) Download(rel string) string

Download returns the URL that streams the bytes as an attachment.

func (Links) Page

func (l Links) Page(rel string) string

Page returns the viewer page for a path relative to the share root.

func (Links) Raw

func (l Links) Raw(rel string) string

Raw returns the URL that streams the bytes inline, with Range support.

func (Links) Root

func (l Links) Root() string

Root is the share's landing URL.

func (Links) Static

func (l Links) Static() string

Static is the URL prefix for the viewer's own assets.

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware decorates a handler. Keeping cross-cutting concerns in this shape lets the router compose them in one readable place.

type Offer added in v0.7.0

type Offer struct {
	Files []OfferFile
	Total int64
	// contains filtered or unexported fields
}

Offer is a batch of files a visitor asks to send. Nothing is written until the owner accepts it, and then only the files it lists, at the sizes it gave: an upload that was not offered and accepted is refused.

func (*Offer) Accept added in v0.7.0

func (o *Offer) Accept()

Accept lets the files in. It does nothing once the offer is answered.

func (*Offer) Decided added in v0.7.0

func (o *Offer) Decided() <-chan struct{}

Decided is closed once the offer is accepted, declined or expires.

func (*Offer) Decline added in v0.7.0

func (o *Offer) Decline()

Decline refuses the files. It does nothing once the offer is answered.

func (*Offer) Expired added in v0.7.0

func (o *Offer) Expired() bool

Expired reports whether the offer ended without an answer.

func (*Offer) State added in v0.7.0

func (o *Offer) State() string

State is "pending", "accepted", "declined" or "expired".

type OfferFile added in v0.7.0

type OfferFile struct {
	// Name is made safe to print: no path, no control characters.
	Name string
	Size int64
}

OfferFile is one file in an offer, as the owner is shown it.

type Options

type Options struct {
	// Addr is the listen address, e.g. "127.0.0.1:0" to pick a free port.
	Addr string
	// Resolver maps URL tokens to shares.
	Resolver sharing.Resolver
	// Guards decide whether a share is still available. Defaults to
	// sharing.DefaultGuards().
	Guards sharing.Guard
	// Hasher verifies share passwords.
	Hasher security.Hasher
	// Signer signs unlock cookies.
	Signer security.Signer
	// Clock supplies the current time. Defaults to the system clock.
	Clock sharing.Clock
	// Detector classifies files for previews.
	Detector preview.Detector
	// Previews renders file previews.
	Previews *preview.Registry
	// Viewer renders HTML pages.
	Viewer *viewer.Renderer
	// Logger receives request and error logs.
	Logger *slog.Logger
	// Checksums works out the SHA-256 shown on file pages. Defaults to a
	// new cache.
	Checksums *checksum.Cache
	// OnReceived, when set, is told about every file a receive share has
	// taken in completely.
	OnReceived func(sharing.Spec, inbox.Received)
	// OnOffer, when set, asks the owner whether a batch of files may be
	// sent to a receive share; it answers with Offer.Accept or Decline.
	// When nil, every batch is accepted.
	OnOffer func(sharing.Spec, *Offer)
	// AtOrigin serves the single registered share at / as well as under its
	// token. A Cloudflare quick tunnel sets this, because the hostname is
	// already the secret and the public link has no path.
	AtOrigin bool
}

Options configures a Server. Every dependency is an interface so the server can be built against test doubles, and so none of its collaborators need to know they are being used by an HTTP server.

type PathResolver

type PathResolver interface {
	Root() string
	Resolve(rel string) (string, error)
}

PathResolver maps an untrusted relative path to a real file inside a root.

type ProxyHandler

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

ProxyHandler exposes a local HTTP service through a share URL.

It is a thin reverse proxy on purpose: HTTP semantics are preserved end-to-end so WebSockets, server-sent events, streaming responses and range requests all keep working exactly as they do against localhost.

func NewProxyHandler

func NewProxyHandler(p *pages, logger *slog.Logger) *ProxyHandler

NewProxyHandler returns a handler that proxies HTTP shares.

func (*ProxyHandler) ServeShare

func (h *ProxyHandler) ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)

ServeShare implements ShareHandler.

type ReceiveHandler added in v0.7.0

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

ReceiveHandler serves a receive share: the upload page and the chunked upload API behind it.

func (ReceiveHandler) ServeShare added in v0.7.0

func (h ReceiveHandler) ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)

ServeShare implements ShareHandler.

type RootProvider

type RootProvider interface {
	Resolver(spec sharing.Spec) (PathResolver, error)
}

RootProvider hands out the confined resolver for a share. The interface exists so the confinement strategy can be swapped (or stubbed in tests) without touching the handler.

type Server

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

Server owns the listener and the HTTP handler for a set of shares.

func New

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

New validates the options and assembles the handler graph.

func (*Server) Addr

func (s *Server) Addr() string

Addr returns the bound address, valid after Listen.

func (*Server) Forget

func (s *Server) Forget(shareID string)

Forget releases cached per-share state. Call it when a share is revoked.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the request handler, so the share routes can be mounted elsewhere or exercised directly in tests without binding a port.

func (*Server) Listen

func (s *Server) Listen() error

Listen binds the socket without serving yet.

Binding is separate from serving so the caller can learn the real port before any URL is printed or any tunnel is started — which is what makes "listen on :0" usable.

func (*Server) Serve

func (s *Server) Serve() error

Serve accepts connections until the server is shut down. It calls Listen first if the caller has not already done so.

func (*Server) ServeAtOrigin added in v0.8.0

func (s *Server) ServeAtOrigin()

ServeAtOrigin serves the single registered share at / as well as under its token. The CLI calls this once it knows the public link is a Cloudflare quick tunnel, whose hostname is already unguessable.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown stops accepting connections and waits for in-flight requests, up to the deadline carried by ctx.

func (*Server) Warm added in v0.2.0

func (s *Server) Warm(spec sharing.Spec)

Warm starts working out the checksums of a share's files in the background, so a single large file has its fingerprint ready by the time a visitor opens the page. Directory shares are hashed per file on first view instead: hashing a whole tree up front could read gigabytes nobody asks for.

type ShareHandler

type ShareHandler interface {
	ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)
}

ShareHandler serves one kind of share. The router dispatches on sharing.Kind, so support for a new kind means adding an implementation here rather than extending a switch inside an existing handler.

type SingleFileHandler

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

SingleFileHandler serves a share of exactly one file. The file is the share root, so there is nothing to navigate.

func (SingleFileHandler) ServeShare

func (h SingleFileHandler) ServeShare(w http.ResponseWriter, r *http.Request, sr *shareRequest)

ServeShare implements ShareHandler.

Jump to

Keyboard shortcuts

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