gig

package module
v0.9.8 Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2021 License: MIT Imports: 23 Imported by: 5

README

Gig - Gemini framework

Sourcegraph godocs.io GoDoc Go Report Card Codecov License

API is subject to change until v1.0

Protocol compatibility

Version Supported Gemini version
0.9.4 v0.14.*
< 0.9.4 v0.13.*

Contents

Feature Overview

  • Client certificate suppport (access x509.Certificate directly from context)
  • Highly optimized router with zero dynamic memory allocation which smartly prioritizes routes
  • Group APIs
  • Extensible middleware framework
  • Define middleware at root, group or route level
  • Handy functions to send variety of Gemini responses
  • Centralized error handling
  • Template rendering with any template engine
  • Define your format for the logger
  • Highly customizable

Guide

Quick Start
package main

import "github.com/pitr/gig"

func main() {
  // Gig instance
  g := gig.Default()

  // Routes
  g.Handle("/", func(c gig.Context) error {
    return c.Gemini("# Hello, World!")
  })

  // Start server on PORT or default port
  g.Run("my.crt", "my.key")
}
$ go run main.go
Parameters in path
package main

import "github.com/pitr/gig"

func main() {
  g := gig.Default()

  g.Handle("/user/:name", func(c gig.Context) error {
    return c.Gemini("# Hello, %s!", c.Param("name"))
  })

  g.Run("my.crt", "my.key")
}
Query
package main

import "github.com/pitr/gig"

func main() {
  g := gig.Default()

  g.Handle("/user", func(c gig.Context) error {
    query, err := c.QueryString()
    if err != nil {
      return err
    }
    return c.Gemini("# Hello, %s!", query)
  })

  g.Run("my.crt", "my.key")
}
Client Certificate
package main

import "github.com/pitr/gig"

func main() {
  g := gig.Default()

  g.Handle("/user", func(c gig.Context) error {
    cert := c.Certificate()
    if cert == nil {
      return NewError(gig.StatusClientCertificateRequired, "We need a certificate")
    }
    return c.Gemini("# Hello, %s!", cert.Subject.CommonName)
  })

  // OR
  g.Handle("/user", func(c gig.Context) error {
    return c.Gemini("# Hello, %s!", c.Get("subject"))
  }, gig.CertAuth(gig.ValidateHasCertificate))

  g.Run("my.crt", "my.key")
}
Grouping routes
func main() {
  g := gig.Default()

  // Simple group: v1
  v1 := g.Group("/v1")
  {
    v1.Handle("/page1", page1Endpoint)
    v1.Handle("/page2", page2Endpoint)
  }

  // Simple group: v2
  v2 := g.Group("/v2")
  {
    v2.Handle("/page1", page1Endpoint)
    v2.Handle("/page2", page2Endpoint)
  }

  g.Run("my.crt", "my.key")
}
Blank Gig without middleware by default

Use

g := gig.New()

instead of

// Default With the Logger and Recovery middleware already attached
g := gig.Default()
Using middleware
func main() {
  // Creates a router without any middleware by default
  g := gig.New()

  // Global middleware
  // Logger middleware will write the logs to gig.DefaultWriter.
  // By default gig.DefaultWriter = os.Stdout
  g.Use(gig.Logger())

  // Recovery middleware recovers from any panics and return StatusPermanentFailure.
  g.Use(gig.Recovery())

  // Private group
  // same as private := g.Group("/private", gig.CertAuth(gig.ValidateHasCertificate))
  private := g.Group("/private")
  private.Use(gig.CertAuth(gig.ValidateHasCertificate))
  {
    private.Handle("/user", userEndpoint)
  }

  g.Run("my.crt", "my.key")
}
Writing logs to file
func main() {
  f, _ := os.Create("access.log")
  gig.DefaultWriter = io.MultiWriter(f)

  // Use the following code if you need to write the logs to file and console at the same time.
  // gig.DefaultWriter = io.MultiWriter(f, os.Stdout)

  g := gig.Default()

  g.Handle("/", func(c gig.Context) error {
      return c.Gemini("# Hello, World!")
  })

  g.Run("my.crt", "my.key")
}
Custom Log Format
func main() {
  g := gig.New()

  // See LoggerConfig documentation for more
  g.Use(gig.LoggerWithConfig(gig.LoggerConfig{Format: "${remote_ip} ${status}"}))

  g.Handle("/", func(c gig.Context) error {
      return c.Gemini("# Hello, World!")
  })

  g.Run("my.crt", "my.key")
}
Serving static files
func main() {
  g := gig.Default()

  g.Static("/images", "images")
  g.Static("/robots.txt", "files/robots.txt")

  g.Run("my.crt", "my.key")
}
Serving data from file
func main() {
  g := gig.Default()

  g.Handle("/robots.txt", func(c gig.Context) error {
      return c.File("robots.txt")
  })

  g.Run("my.crt", "my.key")
}
Serving data from reader
func main() {
  g := gig.Default()

  g.Handle("/data", func(c gig.Context) error {
    response, err := http.Get("https://google.com/")
    if err != nil || response.StatusCode != http.StatusOK {
      return gig.ErrProxyError
    }

    return c.Stream("text/html", response.Body)
  })

  g.Run("my.crt", "my.key")
}
Templates

Use text/template, https://github.com/valyala/quicktemplate, or anything else. This example uses text/template

import (
  "text/template"

  "github.com/pitr/gig"
)

type Template struct {
    templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c gig.Context) error {
    return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
  g := gig.Default()

  // Register renderer
  g.Renderer = &Template{
    templates: template.Must(template.ParseGlob("public/views/*.gmi")),
  }

  g.Handle("/user/:name", func(c gig.Context) error {
    return c.Render("user", c.Param("name"))
  })

  g.Run("my.crt", "my.key")
}

Consider bundling assets with the binary by using go-assets or similar.

Redirects
func main() {
  g := gig.Default()

  g.Handle("/old", func(c gig.Context) error {
    return c.NoContent(gig.StatusRedirectPermanent, "/new")
  })

  g.Run("my.crt", "my.key")
}
Subdomains
func main() {
  apps := map[string]*gig.Gig{}

  // App A
  a := gig.Default()
  apps["app-a.example.com"] = a

  a.Handle("/", func(c gig.Context) error {
      return c.Gemini("I am App A")
  })

  // App B
  b := gig.Default()
  apps["app-b.example.com"] = b

  b.Handle("/", func(c gig.Context) error {
      return c.Gemini("I am App B")
  })

  // Server
  g := gig.New()
  g.Handle("/*", func(c gig.Context) error {
      app := apps[c.URL().Host]

      if app == nil {
          return gig.ErrNotFound
      }

      app.ServeGemini(c)
      return nil
  })

  g.Run("my.crt", "my.key") // must be wildcard SSL certificate for *.example.com
}
Username/password authentication middleware

This assumes that there is a db module that does user management. This middleware ensures that there is a client certificate and validates its fingerprint using passed function. If authentication is required, user is redirected to path returned by middleware. Login handlers are setup using PassAuthLoginHandle function, which collectss username and password and pass to provided function. That function should return an error if login failed, or absolute path to redirect user to.

func main() {
  g := Default()

  secret := g.Group("/secret", gig.PassAuth(func(sig string, c gig.Context) (string, error) {
    ok, err := db.CheckValid(sig)
    if err != nil {
      return "/login", err
    }
    if !ok {
      return "/login", nil
    }
    return "", nil
  }))
  // secret.Handle("/page", func(c gig.Context) {...})

  g.PassAuthLoginHandle("/login", func(user, pass, sig string, c Context) (string, error) {
    // check user/pass combo, and activate cert signature if valid
    err := db.Login(user, pass, sig)
    if err != nil {
      return "", err
    }
    return "/secret/page", nil
  })

  g.Run("my.crt", "my.key")
}
Custom middleware
func MyMiddleware(next gig.HandlerFunc) gig.HandlerFunc {
  return func(c gig.Context) error {
    // Set example variable
    c.Set("example", "123")

    if err := next(c); err != nil {
      c.Error(err)
    }

    // Do something after request is done
    // ...

    return err
  }
}

func main() {
  g := gig.Default()
  g.Use(MyMiddleware)

  g.Handle("/", func(c gig.Context) error {
    return c.Gemini("# Example %s", c.Get("example"))
  })

  g.Run("my.crt", "my.key")
}
Custom port

Use PORT environment variable:

PORT=12345 ./myapp

Alternatively, pass it to Run:

func main() {
  g := gig.Default()

  g.Handle("/", func(c gig.Context) error {
    return c.Gemini("# Hello world")
  })

  g.Run(":12345", "my.crt", "my.key")
}
Custom TLS config
func main() {
  g := gig.Default()
  g.TLSConfig.MinVersion = tls.VersionTLS13

  g.Handle("/", func(c gig.Context) error {
    return c.Gemini("# Hello world")
  })

  g.Run("my.crt", "my.key")
}
Testing
func setupServer() *gig.Gig {
  g := gig.Default()

  g.Handle("/private", func(c gig.Context) error {
    return c.Gemini("Hello %s", c.Get("subject"))
  }, gig.CertAuth(gig.ValidateHasCertificate))

  return g
}

func TestServer(t *testing.T) {
  g := setupServer()
  c, res := g.NewFakeContext("/private", nil)

  g.ServeGemini(c)

  if res.Written != "60 Client Certificate Required\r\n" {
    t.Fail()
  }
}

func TestCertificate(t *testing.T) {
  g := setupServer()
  c, res := g.NewFakeContext("/", &tls.ConnectionState{
    PeerCertificates: []*x509.Certificate{
      {Subject: pkix.Name{CommonName: "john"}},
    },
  })

  g.ServeGemini(c)

  if resp.Written != "20 text/gemini\r\nHello john" {
    t.Fail()
  }
}

Contribute

If something is missing, please open an issue. If possible, send a PR.

License

MIT

Documentation

Overview

Package gig implements high performance, minimalist Go framework for Gemini protocol.

Example:

package main

import (
  "github.com/pitr/gig"
)

func main() {
  // Gig instance
  g := gig.Default()

  // Routes
  g.Handle("/user/:name", func(c gig.Context) error {
      return c.Gemini(gig.StatusSuccess, "# Hello, %s!", c.Param("name"))
  })

  // Start server
  g.Run("my.crt", "my.key")
}

Index

Constants

View Source
const (
	MIMETextGemini            = "text/gemini"
	MIMETextGeminiCharsetUTF8 = "text/gemini; charset=UTF-8"
	MIMETextPlain             = "text/plain"
	MIMETextPlainCharsetUTF8  = "text/plain; charset=UTF-8"
)

MIME types.

View Source
const (
	// Version of Gig.
	Version = "0.9.8"
)

Variables

View Source
var (
	// DefaultWriter is the default io.Writer used by gig for debug output and
	// middleware output like Logger() or Recovery().
	// Note that both Logger and Recovery provides custom ways to configure their
	// output io.Writer.
	// To support coloring in Windows use:
	// 		import "github.com/mattn/go-colorable"
	// 		gig.DefaultWriter = colorable.NewColorableStdout()
	DefaultWriter io.Writer = os.Stdout

	// Debug enables gig to print its internal debug messages.
	Debug = true
)
View Source
var (
	ErrTemporaryFailure          = NewError(StatusTemporaryFailure, "Temporary Failure")
	ErrServerUnavailable         = NewError(StatusServerUnavailable, "Server Unavailable")
	ErrCGIError                  = NewError(StatusCGIError, "CGI Error")
	ErrProxyError                = NewError(StatusProxyError, "Proxy Error")
	ErrSlowDown                  = NewError(StatusSlowDown, "Slow Down")
	ErrPermanentFailure          = NewError(StatusPermanentFailure, "Permanent Failure")
	ErrNotFound                  = NewError(StatusNotFound, "Not Found")
	ErrGone                      = NewError(StatusGone, "Gone")
	ErrProxyRequestRefused       = NewError(StatusProxyRequestRefused, "Proxy Request Refused")
	ErrBadRequest                = NewError(StatusBadRequest, "Bad Request")
	ErrClientCertificateRequired = NewError(StatusClientCertificateRequired, "Client Certificate Required")
	ErrCertificateNotAuthorised  = NewError(StatusCertificateNotAuthorised, "Certificate Not Authorised")
	ErrCertificateNotValid       = NewError(StatusCertificateNotValid, "Certificate Not Valid")

	ErrRendererNotRegistered = errors.New("renderer not registered")
	ErrInvalidCertOrKeyType  = errors.New("invalid cert or key type, must be string or []byte")

	ErrServerClosed = errors.New("gemini: Server closed")
)

Errors that can be inherited from using NewErrorFrom.

View Source
var (
	// DefaultCertAuthConfig is the default CertAuth middleware config.
	DefaultCertAuthConfig = CertAuthConfig{
		Skipper:   DefaultSkipper,
		Validator: ValidateHasCertificate,
	}
)
View Source
var (
	// DefaultLoggerConfig is the default Logger middleware config.
	DefaultLoggerConfig = LoggerConfig{
		Skipper:          DefaultSkipper,
		Format:           "time=\"${time_rfc3339}\" path=${path} status=${status} duration=${latency} ${error}\n",
		CustomTimeFormat: "2006-01-02 15:04:05.00000",
	}
)
View Source
var (
	// DefaultRecoverConfig is the default Recover middleware config.
	DefaultRecoverConfig = RecoverConfig{
		Skipper:           DefaultSkipper,
		StackSize:         4 << 10,
		DisableStackAll:   false,
		DisablePrintStack: false,
	}
)
View Source
var (
	NotFoundHandler = func(c Context) error {
		return ErrNotFound
	}
)

Error handlers.

Functions

func DefaultGeminiErrorHandler added in v0.9.2

func DefaultGeminiErrorHandler(err error, c Context)

DefaultGeminiErrorHandler is the default HTTP error handler. It sends a JSON response with status code.

func DefaultSkipper added in v0.9.3

func DefaultSkipper(Context) bool

DefaultSkipper returns false which processes the middleware.

Types

type CertAuthConfig added in v0.9.3

type CertAuthConfig struct {
	// Skipper defines a function to skip middleware.
	Skipper Skipper

	// Validator is a function to validate client certificate.
	// Required.
	Validator CertAuthValidator
}

CertAuthConfig defines the config for CertAuth middleware.

type CertAuthValidator added in v0.9.3

type CertAuthValidator func(*x509.Certificate, Context) *GeminiError

CertAuthValidator defines a function to validate CertAuth credentials.

type Context

type Context interface {
	// Response returns `*Response`.
	Response() *Response

	// IP returns the client's network address.
	IP() string

	// Certificate returns client's leaf certificate or nil if none provided
	Certificate() *x509.Certificate

	// CertHash returns a hash of client's leaf certificate or empty string is none
	CertHash() string

	// URL returns the URL for the context.
	URL() *url.URL

	// Path returns the registered path for the handler.
	Path() string

	// QueryString returns unescaped URL query string or error. Use
	// Context#URL().RawQuery to get raw query string
	QueryString() (string, error)

	// RequestURI is the unmodified URL string as sent by the client
	// to a server. Usually the URL() or Path() should be used instead.
	RequestURI() string

	// Param returns path parameter by name.
	Param(name string) string

	// Get retrieves data from the context.
	Get(key string) interface{}

	// Set saves data in the context.
	Set(key string, val interface{})

	// Render renders a template with data and sends a text/gemini response with status
	// code Success. Renderer must be registered using `Gig.Renderer`.
	Render(name string, data interface{}) error

	// Gemini sends a text/gemini response with status code Success.
	Gemini(text string, args ...interface{}) error

	// GeminiBlob sends a text/gemini blob response with status code Success.
	GeminiBlob(b []byte) error

	// Text sends a text/plain response with status code Success.
	Text(format string, values ...interface{}) error

	// Blob sends a blob response with status code Success and content type.
	Blob(contentType string, b []byte) error

	// Stream sends a streaming response with status code Success and content type.
	Stream(contentType string, r io.Reader) error

	// File sends a response with the content of the file.
	File(file string) error

	// NoContent sends a response with no body, and a status code and meta field.
	// Use for any non-2x status codes
	NoContent(code Status, meta string, values ...interface{}) error

	// Error invokes the registered error handler. Generally used by middleware.
	Error(err error)

	// Handler returns the matched handler by router.
	Handler() HandlerFunc

	// Gig returns the `Gig` instance.
	Gig() *Gig
}

Context represents the context of the current request. It holds connection reference, path, path parameters, data and registered handler. DO NOT retain Context instance, as it will be reused by other connections.

type FakeAddr added in v0.9.3

type FakeAddr struct{}

FakeAddr ia a fake net.Addr implementation.

func (*FakeAddr) Network added in v0.9.3

func (a *FakeAddr) Network() string

Network returns dummy data.

func (*FakeAddr) String added in v0.9.3

func (a *FakeAddr) String() string

String returns dummy data.

type FakeConn added in v0.9.3

type FakeConn struct {
	FailAfter int
	Written   string
}

FakeConn ia a fake net.Conn that can record what is written and can fail after FailAfter bytes were written.

func (*FakeConn) Close added in v0.9.3

func (c *FakeConn) Close() error

Close always returns nil.

func (*FakeConn) LocalAddr added in v0.9.3

func (c *FakeConn) LocalAddr() net.Addr

LocalAddr returns fake address.

func (*FakeConn) Read added in v0.9.3

func (c *FakeConn) Read(b []byte) (n int, err error)

Read always returns success.

func (*FakeConn) RemoteAddr added in v0.9.3

func (c *FakeConn) RemoteAddr() net.Addr

RemoteAddr returns fake address.

func (*FakeConn) SetDeadline added in v0.9.3

func (c *FakeConn) SetDeadline(t time.Time) error

SetDeadline always returns nil.

func (*FakeConn) SetReadDeadline added in v0.9.3

func (c *FakeConn) SetReadDeadline(t time.Time) error

SetReadDeadline always returns nil.

func (*FakeConn) SetWriteDeadline added in v0.9.3

func (c *FakeConn) SetWriteDeadline(t time.Time) error

SetWriteDeadline always returns nil.

func (*FakeConn) Write added in v0.9.3

func (c *FakeConn) Write(b []byte) (n int, err error)

Write records bytes written and fails after FailAfter bytes.

type GeminiError

type GeminiError struct {
	Code    Status
	Message string
}

GeminiError represents an error that occurred while handling a request.

func NewError

func NewError(code Status, message string) *GeminiError

NewError creates a new GeminiError instance.

func NewErrorFrom

func NewErrorFrom(err *GeminiError, message string) *GeminiError

NewErrorFrom creates a new GeminiError instance using Code from existing GeminiError.

func ValidateHasCertificate added in v0.9.3

func ValidateHasCertificate(cert *x509.Certificate, c Context) *GeminiError

ValidateHasCertificate returns ErrClientCertificateRequired if no certificate is sent. It also stores subject name in context under "subject".

func (*GeminiError) Error

func (ge *GeminiError) Error() string

Error makes it compatible with `error` interface.

type GeminiErrorHandler

type GeminiErrorHandler func(error, Context)

GeminiErrorHandler is a centralized error handler.

type Gig

type Gig struct {

	// HideBanner disables banner on startup.
	HideBanner bool
	// HidePort disables startup message.
	HidePort bool
	// GeminiErrorHandler allows setting custom error handler
	GeminiErrorHandler GeminiErrorHandler
	// Renderer must be set for Context#Render to work
	Renderer Renderer
	// ReadTimeout set max read timeout on socket.
	// Default is none.
	ReadTimeout time.Duration
	// WriteTimeout set max write timeout on socket.
	// Default is none.
	WriteTimeout time.Duration
	// TLSConfig is passed to tls.NewListener and needs to be modified
	// before Run is called.
	TLSConfig *tls.Config
	// contains filtered or unexported fields
}

Gig is the top-level framework instance.

func Default added in v0.9.3

func Default() *Gig

Default returns a Gig instance with Logger and Recover middleware enabled.

func New

func New() *Gig

New creates an instance of Gig.

func (*Gig) Close

func (g *Gig) Close() error

Close immediately stops the server. It internally calls `net.Listener#Close()`.

func (*Gig) File

func (g *Gig) File(path, file string, m ...MiddlewareFunc) *Route

File registers a new route with path to serve a static file with optional route-level middleware.

func (*Gig) Group

func (g *Gig) Group(prefix string, m ...MiddlewareFunc) (gg *Group)

Group creates a new router group with prefix and optional group-level middleware.

func (*Gig) Handle

func (g *Gig) Handle(path string, h HandlerFunc, m ...MiddlewareFunc) *Route

Handle registers a new route for a path with matching handler in the router with optional route-level middleware.

func (*Gig) NewFakeContext added in v0.9.3

func (g *Gig) NewFakeContext(uri string, tlsState *tls.ConnectionState) (Context, *FakeConn)

NewFakeContext returns Context that writes to FakeConn.

func (*Gig) PassAuthLoginHandle added in v0.9.7

func (g *Gig) PassAuthLoginHandle(path string, fn PassAuthLogin)

PassAuthLoginHandle sets up handlers to check username/password using PassAuthLogin.

func (*Gig) Pre

func (g *Gig) Pre(middleware ...MiddlewareFunc)

Pre adds middleware to the chain which is run before router.

func (*Gig) Reverse

func (g *Gig) Reverse(name string, params ...interface{}) string

Reverse generates an URL from route name and provided parameters.

func (*Gig) Routes

func (g *Gig) Routes() []*Route

Routes returns the registered routes.

func (*Gig) Run added in v0.9.1

func (g *Gig) Run(args ...interface{}) (err error)

Run starts a Gemini server. If `certFile` or `keyFile` is `string` the values are treated as file paths. If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.

func (*Gig) ServeGemini

func (g *Gig) ServeGemini(c Context)

ServeGemini serves Gemini request.

func (*Gig) Static

func (g *Gig) Static(prefix, root string) *Route

Static registers a new route with path prefix to serve static files from the provided root directory.

func (*Gig) URL

func (g *Gig) URL(handler HandlerFunc, params ...interface{}) string

URL generates a URL from handler.

func (*Gig) Use

func (g *Gig) Use(middleware ...MiddlewareFunc)

Use adds middleware to the chain which is run after router.

type Group

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

Group is a set of sub-routes for a specified route. It can be used for inner routes that share a common middleware or functionality that should be separate from the parent gig instance while still inheriting from it.

func (*Group) File

func (g *Group) File(path, file string)

File implements `Gig#File()` for sub-routes within the Group.

func (*Group) Group

func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) *Group

Group creates a new sub-group with prefix and optional sub-group-level middleware.

func (*Group) Handle

func (g *Group) Handle(path string, h HandlerFunc, m ...MiddlewareFunc) *Route

Handle implements `Gig#Handle()` for sub-routes within the Group.

func (*Group) Static

func (g *Group) Static(prefix, root string)

Static implements `Gig#Static()` for sub-routes within the Group.

func (*Group) Use

func (g *Group) Use(middleware ...MiddlewareFunc)

Use implements `Gig#Use()` for sub-routes within the Group.

type HandlerFunc

type HandlerFunc func(Context) error

HandlerFunc defines a function to serve requests.

type LoggerConfig added in v0.9.3

type LoggerConfig struct {
	// Skipper defines a function to skip middleware.
	Skipper Skipper

	// Tags to construct the logger format.
	//
	// - time_unix
	// - time_unix_nano
	// - time_rfc3339
	// - time_rfc3339_nano
	// - time_custom
	// - remote_ip
	// - uri
	// - host
	// - path
	// - status
	// - error
	// - latency (In nanoseconds)
	// - latency_human (Human readable)
	// - bytes_in (Bytes received)
	// - bytes_out (Bytes sent)
	// - meta
	// - query
	//
	// Example "${remote_ip} ${status}"
	//
	// Optional. Default value DefaultLoggerConfig.Format.
	Format string

	// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
	CustomTimeFormat string
	// contains filtered or unexported fields
}

LoggerConfig defines the config for Logger middleware.

type MiddlewareFunc

type MiddlewareFunc func(HandlerFunc) HandlerFunc

MiddlewareFunc defines a function to process middleware.

func CertAuth added in v0.9.3

func CertAuth(fn CertAuthValidator) MiddlewareFunc

CertAuth returns an CertAuth middleware.

For valid credentials it calls the next handler.

func CertAuthWithConfig added in v0.9.3

func CertAuthWithConfig(config CertAuthConfig) MiddlewareFunc

CertAuthWithConfig returns an CertAuth middleware with config. See `CertAuth()`.

func Logger

func Logger() MiddlewareFunc

Logger returns a middleware that logs Gemini requests.

func LoggerWithConfig added in v0.9.3

func LoggerWithConfig(config LoggerConfig) MiddlewareFunc

LoggerWithConfig returns a Logger middleware with config. See: `Logger()`.

func PassAuth added in v0.9.6

func PassAuth(check PassAuthCertCheck) MiddlewareFunc

PassAuth is a middleware that implements username/password authentication by first requiring a certificate, checking username/password using PassAuthValidator, and then pinning certificate to it.

For valid credentials it calls the next handler.

func Recover added in v0.9.3

func Recover() MiddlewareFunc

Recover returns a middleware which recovers from panics anywhere in the chain and handles the control to the centralized GeminiErrorHandler.

func RecoverWithConfig added in v0.9.3

func RecoverWithConfig(config RecoverConfig) MiddlewareFunc

RecoverWithConfig returns a Recover middleware with config. See: `Recover()`.

type PassAuthCertCheck added in v0.9.6

type PassAuthCertCheck func(string, Context) (string, error)

PassAuthCertCheck defines a function to validate certificate fingerprint. Must return path on unsuccessful login.

type PassAuthLogin added in v0.9.6

type PassAuthLogin func(username, password, sig string, c Context) (string, error)

PassAuthLogin defines a function to login user. It may pin certificate to user if login is successful. Must return path to redirect to after login.

type RecoverConfig added in v0.9.3

type RecoverConfig struct {
	// Skipper defines a function to skip middleware.
	Skipper Skipper

	// Size of the stack to be printed.
	// Optional. Default value 4KB.
	StackSize int

	// DisableStackAll disables formatting stack traces of all other goroutines
	// into buffer after the trace for the current goroutine.
	// Optional. Default value false.
	DisableStackAll bool

	// DisablePrintStack disables printing stack trace.
	// Optional. Default value as false.
	DisablePrintStack bool
}

RecoverConfig defines the config for Recover middleware.

type Renderer

type Renderer interface {
	Render(io.Writer, string, interface{}, Context) error
}

Renderer is the interface that wraps the Render function.

type Response

type Response struct {
	Writer    io.Writer
	Status    Status
	Meta      string
	Size      int64
	Committed bool
	// contains filtered or unexported fields
}

Response wraps net.Conn, to be used by a context to construct a response.

func NewResponse

func NewResponse(w io.Writer) (r *Response)

NewResponse creates a new instance of Response. Typically used for tests.

func (*Response) Write

func (r *Response) Write(b []byte) (int, error)

Write writes the data to the connection as part of a reply.

func (*Response) WriteHeader

func (r *Response) WriteHeader(code Status, meta string) error

WriteHeader sends a Gemini response header with status code. If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(StatusSuccess, "text/gemini"). Thus explicit calls to WriteHeader are mainly used to send error codes.

type Route

type Route struct {
	Path string
	Name string
}

Route contains a handler and information for matching against requests.

type Skipper added in v0.9.3

type Skipper func(Context) bool

Skipper defines a function to skip middleware. Returning true skips processing the middleware.

type Status

type Status int

Status is a Gemini status code type.

const (
	StatusInput                     Status = 10
	StatusSensitiveInput            Status = 11
	StatusSuccess                   Status = 20
	StatusRedirectTemporary         Status = 30
	StatusRedirectPermanent         Status = 31
	StatusTemporaryFailure          Status = 40
	StatusServerUnavailable         Status = 41
	StatusCGIError                  Status = 42
	StatusProxyError                Status = 43
	StatusSlowDown                  Status = 44
	StatusPermanentFailure          Status = 50
	StatusNotFound                  Status = 51
	StatusGone                      Status = 52
	StatusProxyRequestRefused       Status = 53
	StatusBadRequest                Status = 59
	StatusClientCertificateRequired Status = 60
	StatusCertificateNotAuthorised  Status = 61
	StatusCertificateNotValid       Status = 62
)

Gemini status codes as documented by specification. See: https://gemini.circumlunar.space/docs/spec-spec.txt

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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