v2zgo.at/goatcounter/v2/handlers Index | Files

package handlers

import "zgo.at/goatcounter/v2/handlers"

Index

Variables

var Started time.Time

Started is set when the server is started.

var T = z18n.T

Functions

func Account

func Account(ctx context.Context) *goatcounter.Site

func ErrPage

func ErrPage(w http.ResponseWriter, r *http.Request, reported error)

Identical to the default errpage, but replaces slog calls with our log calls.

func NewBackend

func NewBackend(db zdb.DB, acmeh http.HandlerFunc, dev, goatcounterCom bool,
	domainStatic string, basePath string, dashTimeout, apiMax int, ratelimits Ratelimits,
) chi.Router

func NewStatic

func NewStatic(r chi.Router, dev, goatcounterCom bool, basePath string) chi.Router

func NewWebsite

func NewWebsite(db zdb.DB, dev bool) chi.Router

func Newi18n

func Newi18n() i18n

func Ratelimit

func Ratelimit(withUA bool, getStore func(r *http.Request) (limiter.Store, string)) func(http.Handler) http.Handler

func ResetBufferKey

func ResetBufferKey()

ResetBufferKey resets the buffer key, for tests.

func SameSite

func SameSite(r *http.Request) http.SameSite

Set SameSite=None to allow embedding GoatCounter in a frame and allowing login; there is no way to make this work with Lax or Strict as far as I can find (there is no way to add exceptions for trusted sites).

This is not a huge problem because every POST/DELETE/etc. request already has a CSRF token in the request, which protects against the same thing as SameSite does.

Only do this for secure connections, as Google Chrome developers decided to silently reject these cookies if there's no TLS.

func Site

func Site(ctx context.Context) *goatcounter.Site

Site calls goatcounter.MustGetSite; it's just shorter :-)

func User

func User(ctx context.Context) *goatcounter.User

Types

type APICountRequest

type APICountRequest struct {
	// By default it's an error to send pageviews that don't have either a
	// Session or UserAgent and IP set. This avoids accidental errors.
	//
	// When this is set it will just continue without recording sessions for
	// pageviews that don't have these parameters set.
	NoSessions bool `json:"no_sessions"`

	// Filter pageviews; accepted values:
	//
	//   ip     Ignore requests coming from IP addresses listed in "Settings → Ignore IP". Requires the IP field to be set.
	//
	// ["ip"] is used if this field isn't sent; send an empty array ([]) to not
	// filter anything.
	//
	// The X-Goatcounter-Filter header will be set to a list of indexes if any
	// pageviews are filtered; for example:
	//
	//    X-Goatcounter-Filter: 5, 10
	//
	// This header will be omitted if nothing is filtered.
	Filter []string `json:"filter"`

	// Hits is the list of pageviews.
	Hits []APICountRequestHit `json:"hits"`
}

type APICountRequestHit

type APICountRequestHit struct {
	// Path of the pageview, or the event name. {required}
	Path string `json:"path" query:"p"`

	// Page title, or some descriptive event title.
	Title string `json:"title" query:"t"`

	// Is this an event?
	Event zbool.Bool `json:"event" query:"e"`

	// Referrer value, can be an URL (i.e. the Referal: header) or any
	// string.
	Ref string `json:"ref" query:"r"`

	// Screen width.
	//
	// For compatibility it also accepts the size as "width,height,scaling", but
	// the height and scaling are not used and this format is deprecated.
	Size goatcounter.Floats `json:"size" query:"s"`

	// Query parameters for this pageview, used to get campaign parameters.
	Query string `json:"query" query:"q"`

	// Hint if this should be considered a bot; should be one of the JSBot*`
	// constants from isbot; note the backend may override this if it
	// detects a bot using another method.
	// https://github.com/zgoat/isbot/blob/master/isbot.go#L28
	Bot int `json:"bot" query:"b"`

	// User-Agent header.
	UserAgent string `json:"user_agent"`

	// Location as ISO-3166-1 alpha2 string (e.g. NL, ID, etc.)
	Location string `json:"location"`

	// IP to get location from; not used if location is set. Also used for
	// session generation.
	IP string `json:"ip"`

	// Time this pageview should be recorded at; this can be in the past,
	// but not in the future.
	CreatedAt time.Time `json:"created_at"`

	// Normally a session is based on hash(User-Agent+IP+salt), but if you don't
	// send the IP address then we can't determine the session.
	//
	// In those cases, you can store your own session identifiers and send them
	// along. Note these will not be stored in the database as the sessionID
	// (just as the hashes aren't), they're just used as a unique grouping
	// identifier.
	Session string `json:"session"`

	// {omitdoc}
	Host string `json:"-"`

	// {omitdoc} Line when importing, for displaying errors.
	Line string `json:"-"`
	// {omitdoc} Line when importing, for displaying errors.
	LineNo uint64 `json:"-"`
}

func (APICountRequestHit) String

func (h APICountRequestHit) String() string

type Globals

type Globals struct {
	Context        context.Context
	User           *goatcounter.User
	Site           *goatcounter.Site
	Path           string
	Base           string
	Flash          *zhttp.FlashMessage
	Static         string
	StaticDomain   string
	Domain         string
	Version        string
	GoatcounterCom bool
	Dev            bool
	Port           string
	Websocket      bool
	JSTranslations map[string]string
	HideUI         bool
}

func (Globals) T

func (g Globals) T(msg string, data ...any) template.HTML

type Ratelimits

type Ratelimits struct {
	Count, API, APICount, Export, Login limiter.Store
}

func NewRatelimits

func NewRatelimits() Ratelimits

func (*Ratelimits) Set

func (r *Ratelimits) Set(name string, tokens int, secs int64)

Set the rate limits for name.

Source Files

api.go backend.go bosmang.go count.go dashboard.go handlers.go i18n.go loader.go mw.go settings.go settings_user.go user.go vcounter.go website.go

Version
v2.7.0 (latest)
Published
Dec 15, 2025
Platform
linux/amd64
Imports
85 packages
Last checked
1 day ago

Tools for package owners.