tsweb

package
v1.73.0-pre Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2024 License: BSD-3-Clause Imports: 34 Imported by: 36

Documentation

Overview

Package tsweb contains code used in various Tailscale webservers.

Index

Examples

Constants

View Source
const RequestIDHeader = "X-Tailscale-Request-Id"

RequestIDHeader is a custom HTTP header that the WithRequestID middleware uses to determine whether to re-use a given request ID from the client or generate a new one.

Variables

View Source
var DevMode bool

DevMode controls whether extra output in shown, for when the binary is being run in dev mode.

View Source
var RequestIDKey ctxkey.Key[RequestID]

RequestIDKey stores and loads RequestID values within a context.Context.

Functions

func AcceptsEncoding added in v1.22.0

func AcceptsEncoding(r *http.Request, enc string) bool

AcceptsEncoding reports whether r accepts the named encoding ("gzip", "br", etc).

func AddBrowserHeaders added in v1.46.0

func AddBrowserHeaders(w http.ResponseWriter)

AddBrowserHeaders sets various HTTP security headers for browser-facing endpoints.

The specific headers:

  • require HTTPS access (HSTS)
  • disallow iframe embedding
  • mitigate MIME confusion attacks

These headers are based on https://infosec.mozilla.org/guidelines/web_security

func AllowDebugAccess

func AllowDebugAccess(r *http.Request) bool

AllowDebugAccess reports whether r should be permitted to access various debug endpoints.

func BrowserHeaderHandler added in v1.46.0

func BrowserHeaderHandler(h http.Handler) http.Handler

BrowserHeaderHandler wraps the provided http.Handler with a call to AddBrowserHeaders.

func BrowserHeaderHandlerFunc added in v1.46.0

func BrowserHeaderHandlerFunc(h http.HandlerFunc) http.HandlerFunc

BrowserHeaderHandlerFunc wraps the provided http.HandlerFunc with a call to AddBrowserHeaders.

func CleanRedirectURL added in v1.60.0

func CleanRedirectURL(urlStr string, allowedHosts []string) (*url.URL, error)

CleanRedirectURL ensures that urlStr is a valid redirect URL to the current server, or one of allowedHosts. Returns the cleaned URL or a validation error.

func DefaultCertDir

func DefaultCertDir(leafDir string) string

func ErrorHandler added in v1.70.0

func ErrorHandler(h ReturnHandler, opts ErrorOptions) http.Handler

ErrorHandler converts a ReturnHandler into a standard http.Handler. Errors are handled as specified by the [ReturnHandler.ServeHTTPReturn] method. When wrapped in a LogHandler, panics are added to the AccessLogRecord; otherwise, panics continue up the stack.

func IsProd443

func IsProd443(addr string) bool

IsProd443 reports whether addr is a Go listen address for port 443.

func LogHandler added in v1.70.0

func LogHandler(h http.Handler, opts LogOptions) http.Handler

LogHandler returns an http.Handler that logs to opts.Logf. It logs both successful and failing requests. The log line includes the first error returned to ErrorHandler within. The outer-most LogHandler(LogHandler(...)) does all of the logging. Inner LogHandler instance do nothing. Panics are swallowed and their stack traces are put in the error.

func NormalizedPath added in v1.60.0

func NormalizedPath(p string) string

NormalizedPath returns the given path with the following modifications:

  • any query parameters are removed
  • any path component with a hex string of 9 or more characters is replaced by an ellipsis
  • any path component containing a period with at least two characters after the period (i.e. an email or domain)
  • any path component consisting of a common Tailscale Stable ID
  • any path segment *@passkey.

func Protected

func Protected(h http.Handler) http.Handler

Protected wraps a provided debug handler, h, returning a Handler that enforces AllowDebugAccess and returns forbidden replies for unauthorized requests.

func SetRequestID added in v1.56.0

func SetRequestID(h http.Handler) http.Handler

SetRequestID is an HTTP middleware that injects a RequestID in the *http.Request Context. The value of that request id is either retrieved from the RequestIDHeader or a randomly generated one if not exists. Inner handlers can retrieve this ID from the RequestIDFromContext function.

func StdHandler added in v0.98.0

func StdHandler(h ReturnHandler, opts HandlerOptions) http.Handler

StdHandler converts a ReturnHandler into a standard http.Handler. Handled requests are logged using opts.Logf, as are any errors. Errors are handled as specified by the ReturnHandler interface. Short-hand for LogHandler(ErrorHandler()).

func VarzHandler added in v1.4.0

func VarzHandler(w http.ResponseWriter, r *http.Request)

VarzHandler writes expvar values as Prometheus metrics. TODO: migrate all users to varz.Handler or promvarz.Handler and remove this.

func WriteHTTPError added in v1.72.0

func WriteHTTPError(w http.ResponseWriter, r *http.Request, e HTTPError)

WriteHTTPError is the default error response formatter.

Types

type AccessLogRecord added in v0.98.0

type AccessLogRecord struct {
	// Timestamp at which request processing started.
	Time time.Time `json:"time"`
	// Time it took to finish processing the request. It does not
	// include the entire lifetime of the underlying connection in
	// cases like connection hijacking, only the lifetime of the HTTP
	// request handler.
	Seconds float64 `json:"duration,omitempty"`

	// The client's ip:port.
	RemoteAddr string `json:"remote_addr,omitempty"`
	// The HTTP protocol version, usually "HTTP/1.1 or HTTP/2".
	Proto string `json:"proto,omitempty"`
	// Whether the request was received over TLS.
	TLS bool `json:"tls,omitempty"`
	// The target hostname in the request.
	Host string `json:"host,omitempty"`
	// The HTTP method invoked.
	Method string `json:"method,omitempty"`
	// The unescaped request URI, including query parameters.
	RequestURI string `json:"request_uri,omitempty"`

	// The client's user-agent
	UserAgent string `json:"user_agent,omitempty"`
	// Where the client was before making this request.
	Referer string `json:"referer,omitempty"`

	// The HTTP response code sent to the client.
	Code int `json:"code,omitempty"`
	// Number of bytes sent in response body to client. If the request
	// was hijacked, only includes bytes sent up to the point of
	// hijacking.
	Bytes int `json:"bytes,omitempty"`
	// Error encountered during request processing.
	Err string `json:"err,omitempty"`
	// RequestID is a unique ID for this request. If the *http.Request context
	// carries this value via SetRequestID, then it will be displayed to the
	// client immediately after the error text, as well as logged here. This
	// makes it easier to correlate support requests with server logs. If a
	// RequestID generator is not configured, RequestID will be empty.
	RequestID RequestID `json:"request_id,omitempty"`
}

AccessLogRecord is a record of one HTTP request served.

func (AccessLogRecord) String added in v0.98.0

func (m AccessLogRecord) String() string

String returns m as a JSON string.

type BucketedStatsOptions added in v1.60.0

type BucketedStatsOptions struct {
	// Bucket returns which bucket the given request is in.
	// If nil, [NormalizedPath] is used to compute the bucket.
	Bucket func(req *http.Request) string

	// If non-nil, Started maintains a counter of all requests which
	// have begun processing.
	Started *metrics.LabelMap

	// If non-nil, Finished maintains a counter of all requests which
	// have finished processing with success (that is, the HTTP handler has
	// returned).
	Finished *metrics.LabelMap
}

BucketedStatsOptions describes tsweb handler options surrounding the generation of metrics, grouped into buckets.

type DebugHandler added in v1.10.0

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

DebugHandler is an http.Handler that serves a debugging "homepage", and provides helpers to register more debug endpoints and reports.

The rendered page consists of three sections: informational key/value pairs, links to other pages, and additional program-specific HTML. Callers can add to these sections using the KV, URL and Section helpers respectively.

Additionally, the Handle method offers a shorthand for correctly registering debug handlers and cross-linking them from /debug/.

func Debugger added in v1.10.0

func Debugger(mux *http.ServeMux) *DebugHandler

Debugger returns the DebugHandler registered on mux at /debug/, creating it if necessary.

func (*DebugHandler) Handle added in v1.10.0

func (d *DebugHandler) Handle(slug, desc string, handler http.Handler)

Handle registers handler at /debug/<slug> and creates a descriptive entry in /debug/ for it.

Example
mux := http.NewServeMux()
dbg := Debugger(mux)
// Registers /debug/flushcache with the given handler, and adds a
// link to /debug/ with the description "Flush caches".
dbg.Handle("flushcache", "Flush caches", http.HandlerFunc(http.NotFound))
Output:

func (*DebugHandler) HandleSilent added in v1.50.0

func (d *DebugHandler) HandleSilent(slug string, handler http.Handler)

HandleSilent registers handler at /debug/<slug>. It does not create a descriptive entry in /debug/ for it. This should be used sparingly, for things that need to be registered but would pollute the list of debug links.

func (*DebugHandler) KV added in v1.10.0

func (d *DebugHandler) KV(k string, v any)

KV adds a key/value list item to /debug/.

Example
mux := http.NewServeMux()
dbg := Debugger(mux)
// Adds two list items to /debug/, showing that the condition is
// red and there are 42 donuts.
dbg.KV("Condition", "red")
dbg.KV("Donuts", 42)
Output:

func (*DebugHandler) KVFunc added in v1.10.0

func (d *DebugHandler) KVFunc(k string, v func() any)

KVFunc adds a key/value list item to /debug/. v is called on every render of /debug/.

Example
mux := http.NewServeMux()
dbg := Debugger(mux)
// Adds an count of page renders to /debug/. Note this example
// isn't concurrency-safe.
views := 0
dbg.KVFunc("Debug pageviews", func() any {
	views = views + 1
	return views
})
dbg.KV("Donuts", 42)
Output:

func (*DebugHandler) Section added in v1.10.0

func (d *DebugHandler) Section(f func(w io.Writer, r *http.Request))

Section invokes f on every render of /debug/ to add supplemental HTML to the page body.

Example
mux := http.NewServeMux()
dbg := Debugger(mux)
// Adds a section to /debug/ that dumps the HTTP request of the
// visitor.
dbg.Section(func(w io.Writer, r *http.Request) {
	io.WriteString(w, "<h3>Dump of your HTTP request</h3>")
	fmt.Fprintf(w, "<code>%#v</code>", r)
})
Output:

func (*DebugHandler) ServeHTTP added in v1.10.0

func (d *DebugHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

func (*DebugHandler) URL added in v1.10.0

func (d *DebugHandler) URL(url, desc string)

URL adds a URL and description list item to /debug/.

Example
mux := http.NewServeMux()
dbg := Debugger(mux)
// Links to the Tailscale website from /debug/.
dbg.URL("https://www.tailscale.com", "Homepage")
Output:

type ErrorHandlerFunc added in v1.28.0

type ErrorHandlerFunc func(http.ResponseWriter, *http.Request, HTTPError)

ErrorHandlerFunc is called to present a error response.

type ErrorOptions added in v1.70.0

type ErrorOptions struct {
	// Logf is used to record unexpected behaviours when returning HTTPError but
	// different error codes have already been written to the client.
	Logf logger.Logf
	// OnError is called if the handler returned a HTTPError. This
	// is intended to be used to present pretty error pages if
	// the user agent is determined to be a browser.
	OnError ErrorHandlerFunc
}

ErrorOptions are options used by ErrorHandler.

type HTTPError added in v0.98.0

type HTTPError struct {
	Code   int         // HTTP response code to send to client; 0 means 500
	Msg    string      // Response body to send to client
	Err    error       // Detailed error to log on the server
	Header http.Header // Optional set of HTTP headers to set in the response
}

HTTPError is an error with embedded HTTP response information.

It is the error type to be (optionally) used by Handler.ServeHTTPReturn.

func Error added in v0.98.0

func Error(code int, msg string, err error) HTTPError

Error returns an HTTPError containing the given information.

func (HTTPError) Error added in v0.98.0

func (e HTTPError) Error() string

Error implements the error interface.

func (HTTPError) Unwrap added in v1.32.0

func (e HTTPError) Unwrap() error

type HandlerOptions added in v1.2.1

type HandlerOptions struct {
	QuietLoggingIfSuccessful bool // if set, do not log successfully handled HTTP requests (200 and 304 status codes)
	Logf                     logger.Logf
	Now                      func() time.Time // if nil, defaults to time.Now

	// If non-nil, StatusCodeCounters maintains counters
	// of status codes for handled responses.
	// The keys are "1xx", "2xx", "3xx", "4xx", and "5xx".
	StatusCodeCounters *expvar.Map
	// If non-nil, StatusCodeCountersFull maintains counters of status
	// codes for handled responses.
	// The keys are HTTP numeric response codes e.g. 200, 404, ...
	StatusCodeCountersFull *expvar.Map

	// If non-nil, BucketedStats computes and exposes statistics
	// for each bucket based on the contained parameters.
	BucketedStats *BucketedStatsOptions

	// OnStart is called inline before ServeHTTP is called. Optional.
	OnStart OnStartFunc

	// OnError is called if the handler returned a HTTPError. This
	// is intended to be used to present pretty error pages if
	// the user agent is determined to be a browser.
	OnError ErrorHandlerFunc

	// OnCompletion is called inline when ServeHTTP is finished and gets
	// useful data that the implementor can use for metrics. Optional.
	OnCompletion OnCompletionFunc
}

HandlerOptions are options used by StdHandler, containing both LogOptions used by LogHandler and ErrorOptions used by ErrorHandler.

type LogOptions added in v1.70.0

type LogOptions struct {
	// Logf is used to log HTTP requests and responses.
	Logf logger.Logf
	// Now is a function giving the current time. Defaults to [time.Now].
	Now func() time.Time

	// QuietLogging suppresses all logging of handled HTTP requests, even if
	// there are errors or status codes considered unsuccessful. Use this option
	// to add your own logging in OnCompletion.
	QuietLogging bool
	// QuietLoggingIfSuccessful suppresses logging of handled HTTP requests
	// where the request's response status code is 200 or 304.
	QuietLoggingIfSuccessful bool

	// StatusCodeCounters maintains counters of status code classes.
	// The keys are "1xx", "2xx", "3xx", "4xx", and "5xx".
	// If nil, no counting is done.
	StatusCodeCounters *expvar.Map
	// StatusCodeCountersFull maintains counters of status codes.
	// The keys are HTTP numeric response codes e.g. 200, 404, ...
	// If nil, no counting is done.
	StatusCodeCountersFull *expvar.Map
	// BucketedStats computes and exposes statistics for each bucket based on
	// the contained parameters. If nil, no counting is done.
	BucketedStats *BucketedStatsOptions

	// OnStart is called inline before ServeHTTP is called. Optional.
	OnStart OnStartFunc
	// OnCompletion is called inline when ServeHTTP is finished and gets
	// useful data that the implementor can use for metrics. Optional.
	OnCompletion OnCompletionFunc
}

LogOptions are the options used by LogHandler. These options are a subset of HandlerOptions.

type Middleware added in v1.56.0

type Middleware func(h http.Handler) http.Handler

A Middleware is a function that wraps an http.Handler to extend or modify its behaviour.

The implementation of the wrapper is responsible for delegating its input request to the underlying handler, if appropriate.

func MiddlewareStack added in v1.72.0

func MiddlewareStack(mw ...Middleware) Middleware

MiddlewareStack combines multiple middleware into a single middleware for decorating a http.Handler. The first middleware argument will be the first to process an incoming request, before passing the request onto subsequent middleware and eventually the wrapped handler.

For example:

MiddlewareStack(A, B)(h).ServeHTTP(w, r)

calls in sequence:

   a.ServeHTTP(w, r)
-> b.ServeHTTP(w, r)
-> h.ServeHTTP(w, r)

(where the lowercase handlers were generated by the uppercase middleware).

Example
// setHeader returns a middleware that sets header k = vs.
setHeader := func(k string, vs ...string) Middleware {
	k = textproto.CanonicalMIMEHeaderKey(k)
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header()[k] = vs
			h.ServeHTTP(w, r)
		})
	}
}

// h is a http.Handler which prints the A, B & C response headers, wrapped
// in a few middleware which set those headers.
var h http.Handler = MiddlewareStack(
	setHeader("A", "mw1"),
	MiddlewareStack(
		setHeader("A", "mw2.1"),
		setHeader("B", "mw2.2"),
		setHeader("C", "mw2.3"),
		setHeader("C", "mw2.4"),
	),
	setHeader("B", "mw3"),
)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	fmt.Println("A", w.Header().Get("A"))
	fmt.Println("B", w.Header().Get("B"))
	fmt.Println("C", w.Header().Get("C"))
}))

// Invoke the handler.
h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("", "/", nil))
Output:

A mw2.1
B mw3
C mw2.4

type OnCompletionFunc added in v1.68.0

type OnCompletionFunc func(*http.Request, AccessLogRecord)

OnCompletionFunc is called when ServeHTTP is finished and gets useful data that the implementor can use for metrics.

type OnStartFunc added in v1.70.0

type OnStartFunc func(*http.Request, AccessLogRecord)

OnStartFunc is called before ServeHTTP is called.

type Port80Handler

type Port80Handler struct {
	Main http.Handler
	// FQDN is used to redirect incoming requests to https://<FQDN>.
	// If it is not set, the hostname is calculated from the incoming
	// request.
	FQDN string
}

Port80Handler is the handler to be given to autocert.Manager.HTTPHandler. The inner handler is the mux returned by NewMux containing registered /debug handlers.

func (Port80Handler) ServeHTTP

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

type RequestID added in v1.50.0

type RequestID string

RequestID is an opaque identifier for a HTTP request, used to correlate user-visible errors with backend server logs. The RequestID is typically threaded through an HTTP Middleware (WithRequestID) and then can be extracted by HTTP Handlers to include in their logs.

RequestID is an opaque identifier for a HTTP request, used to correlate user-visible errors with backend server logs. If present in the context, the RequestID will be printed alongside the message text and logged in the AccessLogRecord.

A RequestID has the format "REQ-1{ID}", and the ID should be treated as an opaque string. The current implementation uses a UUID.

func GenerateRequestID added in v1.62.0

func GenerateRequestID() RequestID

GenerateRequestID generates a new request ID with the current format.

func RequestIDFromContext deprecated added in v1.56.0

func RequestIDFromContext(ctx context.Context) RequestID

RequestIDFromContext retrieves the RequestID from context that can be set by the SetRequestID function.

Deprecated: Use [RequestIDKey.Value] instead.

func (RequestID) String added in v1.62.0

func (r RequestID) String() string

String returns the string format of the request ID, for use in e.g. setting a http.Header.

type ReturnHandler added in v0.98.0

type ReturnHandler interface {
	// ServeHTTPReturn is like http.Handler.ServeHTTP, except that
	// it can choose to return an error instead of writing to its
	// http.ResponseWriter.
	//
	// If ServeHTTPReturn returns an error, it caller should handle
	// an error by serving an HTTP 500 response to the user. The
	// error details should not be sent to the client, as they may
	// contain sensitive information. If the error is an
	// HTTPError, though, callers should use the HTTP response
	// code and message as the response to the client.
	ServeHTTPReturn(http.ResponseWriter, *http.Request) error
}

ReturnHandler is like net/http.Handler, but the handler can return an error instead of writing to its ResponseWriter.

type ReturnHandlerFunc added in v0.98.1

type ReturnHandlerFunc func(http.ResponseWriter, *http.Request) error

ReturnHandlerFunc is an adapter to allow the use of ordinary functions as ReturnHandlers. If f is a function with the appropriate signature, ReturnHandlerFunc(f) is a ReturnHandler that calls f.

func (ReturnHandlerFunc) ServeHTTPReturn added in v0.98.1

func (f ReturnHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Request) error

ServeHTTPReturn calls f(w, r).

Directories

Path Synopsis
Package promvarz combines Prometheus metrics exported by our expvar converter (tsweb/varz) with metrics exported by the official Prometheus client.
Package promvarz combines Prometheus metrics exported by our expvar converter (tsweb/varz) with metrics exported by the official Prometheus client.
Package varz contains code to export metrics in Prometheus format.
Package varz contains code to export metrics in Prometheus format.

Jump to

Keyboard shortcuts

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