Help us shape the future of Go! Take the 2026 Go Developer Survey

httpx

package
v0.56.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package httpx holds the small HTTP details that have to be identical everywhere filex writes a response.

Index

Constants

View Source
const InertCSP = "" /* 139-byte string literal not displayed */

InertCSP is the policy an active kind is served under: rendered, but as an inert document in an opaque origin — no script, no request anywhere, no form, nothing it could reach as the filex origin.

Variables

This section is empty.

Functions

func ContentDisposition

func ContentDisposition(disposition, name string) string

ContentDisposition builds a `Content-Disposition` value that is safe for EVERY client, for a file whose name may be anything the user typed.

The trap it exists for: an HTTP header is bytes, and a header value is ASCII by specification. Writing `filename="Türkçe adlı dosya.txt"` puts raw UTF-8 in the header. Browsers guess their way through it, which is why this survives for years unnoticed — but a strict client does not:

TypeError: Cannot convert argument to a ByteString because the character
at index 32 has a value of 305 which is greater than 255

That is Electron's `net.fetch` (undici) refusing byte 0x131 — `ı` — while parsing the response, thrown from an event handler where the caller's try/catch cannot reach it. Measured 2026-08-29: the filex desktop app took an uncaught exception in its main process, and a folder being dragged out stopped filling in halfway, silently.

RFC 6266 has the answer, and it is to send BOTH forms:

attachment; filename="Turkce adli dosya.txt"; filename*=UTF-8''T%C3%BCrk%C3%A7e...

`filename` is a plain-ASCII fallback for anything old or strict; `filename*` (RFC 5987) carries the real name percent-encoded, and every current browser prefers it. The result is pure ASCII either way, so no client has to guess.

func InertPolicy added in v0.48.0

func InertPolicy(contentType string) string

InertPolicy is the Content-Security-Policy a served file carries: "" for the kinds a browser shows as themselves, else a script-less sandbox.

⚠ A PDF stays unsandboxed on purpose: Chrome refuses to show a PDF in a sandboxed document, and the preview and the signing page exist to show one.

func ProtectServedFile added in v0.48.0

func ProtectServedFile(h http.Header, contentType string)

ProtectServedFile sets the headers every served file body carries: its Content-Type (never sniffed) and, for an active kind, InertPolicy.

func ServedType added in v0.48.0

func ServedType(recorded, name string) string

ServedType is the Content-Type a file's bytes are answered with: the type recorded for it, else the one its name implies, else opaque bytes. Never empty — net/http would otherwise guess one after the policy was decided.

Types

type RequestLog

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

RequestLog carries who a request turned out to be, from the middleware that authenticated it back out to the access log.

⚠ Why a holder and not a context value read afterwards: the access log (api.Logger) is the OUTERMOST middleware, and every authenticating middleware sits further in, inside its own route group. Each one hands the rest of the chain a NEW context (auth.WithUser, auth.WithToken, tenant.WithScope); when the handler returns, the logger still holds the request it started with, whose context never saw any of it. So the logger puts this holder on the context FIRST, and the functions that attach a caller write into it on their way past. One place records, whatever door the request came through — session, API token, /dav, /s3, a WebSocket ticket.

The fields are atomic because a WebSocket handler keeps the request's context alive in goroutines that can still be running when the logger reads.

func RequestLogFrom

func RequestLogFrom(ctx context.Context) *RequestLog

RequestLogFrom returns the holder on ctx, or nil when there is none — a background job, a test, a request that did not come through the router. Every method below is safe on nil, so a caller never has to check.

func WithRequestLog

func WithRequestLog(ctx context.Context) (context.Context, *RequestLog)

WithRequestLog returns ctx carrying a fresh holder, and the holder itself.

func (*RequestLog) NoteTenant

func (l *RequestLog) NoteTenant(slug string)

NoteTenant records the tenant (provider) slug the request is scoped to.

func (*RequestLog) NoteToken

func (l *RequestLog) NoteToken(id int64)

NoteToken records the API token the request was authenticated by — its row id, never the secret.

func (*RequestLog) NoteUser

func (l *RequestLog) NoteUser(id int64)

NoteUser records the authenticated account. Zero is not an account (a synthesized principal carries it) and is ignored rather than logged as one.

func (*RequestLog) Tenant

func (l *RequestLog) Tenant() string

Tenant is the recorded tenant slug, "" when the request was not scoped.

func (*RequestLog) TokenID

func (l *RequestLog) TokenID() int64

TokenID is the recorded token id, 0 when the request carried no API token.

func (*RequestLog) UserID

func (l *RequestLog) UserID() int64

UserID is the recorded account id, 0 when none was.

Jump to

Keyboard shortcuts

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