garnish

package module
v1.0.1-0...-099a076 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2015 License: MIT Imports: 24 Imported by: 0

README

Garnish

A reverse proxy

Usage

Using Garnish comes down to configuring it. You'll most likely want to import two projects:

import(
  "gopkg.in/karlseguin/garnish.v1"
  "gopkg.in/karlseguin/garnish.v1/gc"
)

You begin this process by creating a configuration object:

config := gc.Configure()

You'll then:

  1. Configure global settings
  2. Configure / enable middlewares
  3. Configure specific routes

Finally, you can start garnish:

runtime, err := config.Build()
if err != nil {
  panic(err)
}
garnish.Start(runtime)

You can see example/main.go for a basic example.

Global Settings

The most common global setting is:

  • Address(address string) - the address to listen on

Other settings you likely won't have to change:

  • Debug() - Enable debug logging
  • Logger(garnish.Logs) - Use your own logger
  • BytePool(capacity, size uint32) - A byte pool used whenever your upstreams reply with a Content-Length less than capacity. Bytes required will be capacity * size.
  • DnsTTL(ttl time.Duration) - The default TTL to cache dns lookups for. Can be overwritten on a per-upstream basis.
  • NotFound(response garnish.Response) - The response to return for a 404
  • Fatal(response garnish.Response) - The response to return for a 500
Middleware
Stats

The stats middleware is disabled by default.

Every minute, the stats middleware writes performance metrics to a file. Stats will generate information about:

  1. The runtime
    • of GCs

    • of Goroutines

  2. Your routes
    • of hits

    • of hits by status code (2xx, 4xx, 5xx)

    • of cache hits

    • of slow requests

    • 75 percentile load time
    • 95 percentile load time
  3. Other
    • Infomration on your byte pool (hits/size/...)

The middleware overwrites the file on each write.

config.Stats().FileName("stats.json").Slow(time.Millisecond * 100)
  • FileName(name string) - the path to save the statistics to
  • Slow(d time.Duration) - the default value to consider a request as being slow. (overwritable on a per-route basis)
Cache

The cache middleware is disabled by default.

config.Cache().Grace(time.Minute * 2)
  • Count(num int) - The maximum number of responses to keep in the cache
  • Grace(window time.Duration) - The window to allow a grace response
  • NoSaint() - Disables saint mode
  • KeyLookup(garnish.CacheKeyLookup) - The function that determines the cache keys to use for this request. A default based on the request's URL + QueryString is used. (overwritable on a per-route basis)
  • PurgeHandler(garnish.PurgeHandler) - The function to call on PURGE requests. No default is provided (it's good to authorize purge requests). If the handler returns a nil response, the request proceeds as normal (thus allowing you to purge the garnish cache and still send the request to the upstream). When a PurgeHandler is configured, a route is automatically added to handle any PURGE request.
Hydration

The Hydration middleware is disabled by default.

Hydration is a form of SSI (Server Side Include) aimed at reducing duplication and latency issues which often come with using a service oriented architecture. The approach is detailed here.

config.Hydrate(func (fragment garnish.ReferenceFragment) []byte {
	return redis.Get(fragment.String("id"))
}).Header("X-Hydrate")

To enable Hydration, a garnish.HydrateLoader function must be provided. This function is responsible for taking the hydration meta data provided by the upstream and converting it to the actual object. In the above example, the payload is retrieved from Redis.

The provided garnish.ReferenceFragment exposes a typed.Typed object. However, despite this potential flexibility, the current parser is severely limited. Upstreams should provide very basic meta data. Namely, no nested objects are currently supported and values cannot contain a {} (for real, teehee).

  • Header(name string) - The HTTP header the upstream will set to enable hydration against the response.
Upstreams

Configures your upstreams. Garnish requires at least 1 upstream to be defined:

config.Upstream("users").Address("http://localhost:4005")
config.Upstream("search").Address("http://localhost:4006")

The name given to the upstream is used later whe defining routes.

  • Address(address string) - The address of the upstream. Must begin with http://, https:// or unix:/
  • KeepAlive(count int) - The number of keepalive connections to maintain with the upstream. Set to 0 to disable
  • DnsCache(ttl time.Duration) - The length of time to cache the upstream's IP. Even setting this to a short value (1s) can have a significant impact
  • Headers(headers ...string) - The headers to forward to the upstream
  • Tweaker(tweaker garnish.RequestTweaker) - A RequestTweaker exposes the incoming and outgoing request, allowing you to make any custom changes to the outgoing request.
Route

At least 1 route must be registered. Routes are registered with a method and associated with an upstream:

config.Route("users").Get("/user/:id").Upstream("test")

All routes must have a unique name. Paths support parameters in the form of :name, which will be exposed via the *garnish.Request's Param method. Paths can also end with a wildcard *, which acts as a prefix match.

  • Upstream(name string) - The name of the upstream to send this request to
  • Get(path string) - The path for a GET method
  • Post(path string) - The path for a POST method
  • Put(path string) - The path for a PUT method
  • Delete(path string) - The path for a DELETE method
  • Purge(path string) - The path for a PURGE method
  • Patch(path string) - The path for a PATCH method
  • Head(path string) - The path for a HEAD method
  • Options(path string) - The path for a OPTIONS method
  • All(path string) - The path for a all methods. Can be overwritten for specific methods by specifying the method route first.
  • Slow(t time.Duration) - Any requests that take longer than t to process will be flagged as a slow request by the stats worker. Overwrite's the stat's slow value for this route.
  • CacheTTL(ttl time.Duration) - The amount of time to cache the response for. Values < 0 will cause the item to never be cached. If the value isn't set, the Cache-Control header received from the upstream will be used.
  • CacheKeyLookup(garnish.CacheKeyLookup) - The function that generates the cache key to use. Overwrites the cache's lookup for this route.
  • Handler(garnish.Handler) garnish.Reponse - Provide a custom handler for this route (see handler section)
Handers

Each route can have a custom handler. This allows routes to be handled directly in-process, without going to an upstream. For example:

func LoadUser(req *garnish.Request, next garnish.Middleware) garnish.Response {
  id := req.Params().Get("id")
  if len(id) == 0 {
    return garnish.NotFoundResponse()
  }
  //todo handle
}

By using the next argument, it's possible to use a handler AND an upstream:

func DeleteUser(req *garnish.Request, next garnish.Middleware) garnish.Response {
  if isAuthorized(req) == false {
    return garnish.Respond(401, "not authorized")
  }
  res := next(req)
  //can manipulate res
  return res
}

Because of when it executes (immediately before the upstream), the handler can return a response which takes full advantage of the other middlewares (stats, caching, hydration, authentication, ...)

Custom Middleware

You can inject your own middle handler:

config.Insert(garnish.BEFORE_STATS, "auth", authHandler)

func authHandler(req *garnish.Request, next garnish.Middleware) garnish.Response{
  if .... {
    return garnish.Respond(401, "not authorized")
  }
  return next(req)
}

Middlewares can be inserted:

  • BEFORE_STATS
  • BEFORE_CACHE
  • BEFORE_HYDRATE
  • BEFORE_DISPATCH

Cache Persistence

The default cache implementation is an in-memory LRU cache. This means that a restart wipes the cache resulting in a traffic spike to upstreams servers. Garnish can help mitigate this problem by letting you snapshot a part of the cache on shutdown (and restoring from this snapshot on startup). This snapshot is an approximation: Garnish continues to serve requests while snapshotting and thus its possible for an entry to be updated after being persisted to disk.

To reduce the impact of this possible inconsistency, items restored to the cache on startup are cached for a brief period of time (1 to 2 minutes). In other words, the goal of cache persistence isn't to be fully transparent during a restart, but rather to reduce the impact of a restart by spreading out the load.

To persist the cache (likely triggered by a signal), you use:

if err := runtime.Cache.Save("cache.save", 10000, time.Second*10); err != nil {
  log.Println("cache save", err)
}

The above will save the 10 000 most recently used entries. It'll ignore any entry that expire within the next 10 seconds.

On startup, the cache can be restored via:

if err := runtime.Cache.Load("cache.save")); err != nil {
  log.Println("cache load", err)
}

File Based Configuration

Rather than initiating a new configuration object via the Configure() function, the LoadConfig(path string) (*Configuration, error) function can be used. LoadConfig expects the path to a TOML file, a sample of which is provided in example/sample.toml.

The configuration file supplements, but does not replace, the main configuration mechanism. Specifically, the goal of the configuration file is to allow the addition of upstreams and routes without having to restart the server. Configuration which is expected to be more static, such as the cache or stats tracking, cannot be configured via the file.

Hot Reload

The Reload(runtime) function can be used to change the configuration of a running Garnish server. Reloading is thread-safe and guarantees that requests will see a consistent configuration (running requests will see their existing configuration, while new request will run on the new configuration). Hot reloading is meant to be paired with the file-based configuration in order to add or modify routes and upstreams without downtime.

Reload takes a new runtime instance. Its up to you to decide when/how to get a new configuration, but it'll probably be signal driven. The example app illustrates this.

Currently, changes to the listening address/port are ignored.

TODO

  • Upstream load balancing
  • TCP upstream

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	PurgeHitResponse    = Empty(200)
	PurgeMissResponse   = Empty(204)
	NotModifiedResponse = Empty(304)
)
View Source
var (
	EmptyOk             = Empty(200)
	EmptyCreated        = Empty(201)
	EmptyInvalidRequest = Empty(401)
	EmptyNotFound       = Empty(404)
	EmptyServerError    = Empty(500)
)
View Source
var DefaultUserAgent = []string{""}

The User Agent to send to the upstream

View Source
var (
	EmptyParams = params.New(0)
)
View Source
var STATS_PERCENTILES = map[string]float64{"75p": 0.75, "95p": 0.95}

The percentiles to measure. The key is used as the stat name.

View Source
var STATS_SAMPLE_SIZE int64 = 1000

The number of samples to keep

View Source
var STATS_SAMPLE_SIZE_F = float64(STATS_SAMPLE_SIZE)

The number of samples to keep as a float

View Source
var (
	UnauthorizedResponse = Empty(401)
)

Functions

func DefaultCacheKeyLookup

func DefaultCacheKeyLookup(req *Request) (string, string)

func Reload

func Reload(runtime *Runtime)

func Start

func Start(runtime *Runtime)

Types

type AuthHandler

type AuthHandler func(req *Request) Response

Authorization / authentication handler

type Cache

type Cache struct {
	sync.Mutex

	Storage      CacheStorage
	Saint        bool
	GraceTTL     time.Duration
	PurgeHandler PurgeHandler
	// contains filtered or unexported fields
}

func NewCache

func NewCache() *Cache

func (*Cache) Grace

func (c *Cache) Grace(primary string, secondary string, req *Request, next Handler)

A clone is critical since the original request is likely to be closed before we're finishing with Grace and we might end up with a request that contains data from multiple sources.

func (*Cache) Load

func (c *Cache) Load(path string) error

func (*Cache) Save

func (c *Cache) Save(path string, count int, cutoff time.Duration) error

func (*Cache) Set

func (c *Cache) Set(primary string, secondary string, config *RouteCache, res Response)

type CacheKeyLookup

type CacheKeyLookup func(req *Request) (string, string)

A function that generates cache keys from a request

type CacheStorage

type CacheStorage interface {
	Get(primary, secondary string) CachedResponse
	Set(primary string, secondary string, response CachedResponse)
	Delete(primary, secondary string) bool
	DeleteAll(primary string) bool
	Save(path string, count int, cutoff time.Duration) error
	Load(path string) error
	SetSize(size int)
	GetSize() int
	Stop()
}

type CachedResponse

type CachedResponse interface {
	Response
	Size() int
	Expire(at time.Time)
	Expires() time.Time
	Serialize(serializer Serializer) error
	Deserialize(deserializer Deserializer) error
}

type Deserializer

type Deserializer interface {
	ReadInt() int
	ReadByte() byte
	ReadBytes() []byte
	CloneBytes() []byte
	ReadString() string
}

type FakeLogger

type FakeLogger struct {
	Infos  []string
	Warns  []string
	Errors []string
}

func NewFakeLogger

func NewFakeLogger() *FakeLogger

func (*FakeLogger) Error

func (f *FakeLogger) Error(message string)

func (*FakeLogger) Errorf

func (f *FakeLogger) Errorf(format string, v ...interface{})

func (*FakeLogger) Info

func (f *FakeLogger) Info(message string)

func (*FakeLogger) Infof

func (f *FakeLogger) Infof(format string, v ...interface{})

func (*FakeLogger) IsVerbose

func (f *FakeLogger) IsVerbose() bool

func (*FakeLogger) Verbose

func (f *FakeLogger) Verbose()

func (*FakeLogger) Warn

func (f *FakeLogger) Warn(message string)

func (*FakeLogger) Warnf

func (f *FakeLogger) Warnf(format string, v ...interface{})

type Fragment

type Fragment interface {
	Render(runtime *Runtime) []byte
	Size() int
	// contains filtered or unexported methods
}

type Garnish

type Garnish struct {
	*atomic.Value
}

func (*Garnish) ServeHTTP

func (g *Garnish) ServeHTTP(out http.ResponseWriter, request *http.Request)

type Handler

type Handler func(req *Request) Response

func WrapMiddleware

func WrapMiddleware(name string, m Middleware, next Handler) Handler

type HydrateLoader

type HydrateLoader func(fragment ReferenceFragment) []byte

type HydrateResponse

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

func NewHydraterResponse

func NewHydraterResponse(status int, header http.Header, fragments []Fragment) *HydrateResponse

func (*HydrateResponse) AddHeader

func (r *HydrateResponse) AddHeader(key, value string) Response

func (*HydrateResponse) Cached

func (r *HydrateResponse) Cached() bool

func (*HydrateResponse) Close

func (r *HydrateResponse) Close()

func (*HydrateResponse) ContentLength

func (r *HydrateResponse) ContentLength() int

func (*HydrateResponse) Deserialize

func (r *HydrateResponse) Deserialize(deserializer Deserializer) error

func (*HydrateResponse) Expire

func (r *HydrateResponse) Expire(at time.Time)

func (*HydrateResponse) Expires

func (r *HydrateResponse) Expires() time.Time

func (*HydrateResponse) Header

func (r *HydrateResponse) Header() http.Header

func (*HydrateResponse) Serialize

func (r *HydrateResponse) Serialize(serializer Serializer) error

func (*HydrateResponse) Size

func (r *HydrateResponse) Size() int

func (*HydrateResponse) Status

func (r *HydrateResponse) Status() int

func (*HydrateResponse) ToCacheable

func (r *HydrateResponse) ToCacheable(expires time.Time) CachedResponse

func (*HydrateResponse) Write

func (r *HydrateResponse) Write(runtime *Runtime, w io.Writer)

type LiteralFragment

type LiteralFragment []byte

func (LiteralFragment) Render

func (f LiteralFragment) Render(runtime *Runtime) []byte

func (LiteralFragment) Size

func (f LiteralFragment) Size() int

type Logger

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

func (*Logger) Error

func (l *Logger) Error(message string)

func (*Logger) Errorf

func (l *Logger) Errorf(format string, v ...interface{})

func (*Logger) Info

func (l *Logger) Info(message string)

func (*Logger) Infof

func (l *Logger) Infof(format string, v ...interface{})

func (*Logger) IsVerbose

func (l *Logger) IsVerbose() bool

func (*Logger) Verbose

func (l *Logger) Verbose()

func (*Logger) Warn

func (l *Logger) Warn(message string)

func (*Logger) Warnf

func (l *Logger) Warnf(format string, v ...interface{})

type Logs

type Logs interface {
	// Log an information message
	Info(message string)
	// Log an informational message using the specified format
	Infof(format string, v ...interface{})

	// Log a warning message
	Warn(message string)
	// Log a warning message using the specified format
	Warnf(format string, v ...interface{})

	// Log an error message
	Error(message string)
	// Log an error message using the specified format
	Errorf(format string, v ...interface{})

	// Enable logging info messages
	Verbose()

	// Returns true if verbose logging is enabled
	IsVerbose() bool
}
var Log Logs = new(Logger)

Garnish's global logger If you want to log something and have access to a *garnish.Request, you should consider using its Info and Error methods for more context-aware messages

type Middleware

type Middleware func(req *Request, next Handler) Response

type MultiTransportUpstream

type MultiTransportUpstream struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func (*MultiTransportUpstream) Headers

func (u *MultiTransportUpstream) Headers() []string

func (*MultiTransportUpstream) Transport

func (u *MultiTransportUpstream) Transport() *Transport

func (*MultiTransportUpstream) Tweaker

type NormalResponse

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

A standard response. This response is used by the cache. It's also used when the upstream didn't provide a Content-Length, or whe the Content-Length was greater then the configured BytePool's capacity

func (*NormalResponse) AddHeader

func (r *NormalResponse) AddHeader(key, value string) Response

func (*NormalResponse) Cached

func (r *NormalResponse) Cached() bool

func (*NormalResponse) Close

func (r *NormalResponse) Close()

func (*NormalResponse) ContentLength

func (r *NormalResponse) ContentLength() int

func (*NormalResponse) Deserialize

func (r *NormalResponse) Deserialize(deserializer Deserializer) error

func (*NormalResponse) Expire

func (r *NormalResponse) Expire(at time.Time)

func (*NormalResponse) Expires

func (r *NormalResponse) Expires() time.Time

func (*NormalResponse) Header

func (r *NormalResponse) Header() http.Header

func (*NormalResponse) Serialize

func (r *NormalResponse) Serialize(serializer Serializer) error

func (*NormalResponse) Size

func (r *NormalResponse) Size() int

func (*NormalResponse) Status

func (r *NormalResponse) Status() int

func (*NormalResponse) ToCacheable

func (r *NormalResponse) ToCacheable(expires time.Time) CachedResponse

func (*NormalResponse) Write

func (r *NormalResponse) Write(runtime *Runtime, w io.Writer)

type PurgeHandler

type PurgeHandler func(req *Request, lookup CacheKeyLookup, cache CacheStorage) Response

A function that purges the cache Returning a nil response means that the request will be forward onwards

type ReferenceFragment

type ReferenceFragment struct {
	typed.Typed
	// contains filtered or unexported fields
}

func NewReferenceFragment

func NewReferenceFragment(data []byte) (ReferenceFragment, error)

func (ReferenceFragment) Render

func (f ReferenceFragment) Render(runtime *Runtime) []byte

func (ReferenceFragment) Size

func (f ReferenceFragment) Size() int

type Reporter

type Reporter func() map[string]int64

A reporter of metrics

type ReqBuilder

type ReqBuilder struct {
	Request *Request
}

a request builder

func RB

func RB() *ReqBuilder

func (*ReqBuilder) Param

func (rb *ReqBuilder) Param(key, value string) *ReqBuilder

func (*ReqBuilder) Query

func (rb *ReqBuilder) Query(key, value string) *ReqBuilder

type Request

type Request struct {

	// wraps request.Url.Query without having to re-parse it on each request
	Query url.Values

	// the underlying bytepool for the body. Consumers should use the Body() method
	B *bytepool.Bytes

	// Every request has a unique id. This is forwarded to the upstreams in the X-Request-Id header
	Id string

	// The time the request started at (used by stats to track the time taken to process)
	Start time.Time

	// The actual *http.Request
	*http.Request

	// The route this request is associated with
	Route *Route

	// Garnish's runtime
	Runtime *Runtime

	// To be used by consumer as-needed, unused by Garnish itself.
	Context interface{}
	// contains filtered or unexported fields
}

Extends an *http.Request

func NewRequest

func NewRequest(req *http.Request, route *Route, params *params.Params) *Request

func (*Request) Body

func (r *Request) Body() []byte

The request's body. This value is only available before the upstream is called (at which point it is drained)

func (*Request) Cacheable

func (r *Request) Cacheable() bool

Whether the request could be cached or not

func (*Request) Cached

func (r *Request) Cached(reason string)

func (*Request) Clone

func (r *Request) Clone() *Request

For now we don't clone the body. Clone is only used by the cache/grace right now, what are the chances that we want to cache a GET request with a body?

func (*Request) Close

func (r *Request) Close()

Used internally to release any resources associated with the request

func (*Request) Error

func (r *Request) Error(message string)

Context-aware error message

func (*Request) Errorf

func (r *Request) Errorf(format string, args ...interface{})

Context-aware error message

func (*Request) FatalResponse

func (r *Request) FatalResponse(message string) Response

func (*Request) FatalResponseErr

func (r *Request) FatalResponseErr(message string, err error) Response

func (*Request) Info

func (r *Request) Info(message string)

func (*Request) Infof

func (r *Request) Infof(format string, args ...interface{})

Context-aware info message (only displayed if the global configuration has Debug logging enabled)

func (*Request) Params

func (r *Request) Params(key string) string

Params are values extracted from the URL of a route. Given a route /users/:id we can expect a param with a key of "id"

func (*Request) Q

func (r *Request) Q(key string) string

Gets a querystring value. If the key holds an array of values, returns the first one. Use the Query field to get an array

type RequestTweaker

type RequestTweaker func(in *Request, out *http.Request)

Tweaks request `out` before sending it to the upstream

type Response

type Response interface {
	// The response's content length
	// Should return -1 when unknown
	ContentLength() int

	// Write out the response
	Write(runtime *Runtime, w io.Writer)

	// The status code
	Status() int

	// The headers
	Header() http.Header

	// Write a header
	AddHeader(key, value string) Response

	// Returns a cacheable version of this response
	// When detached is true, it's expected that the original
	// response will continue to be used. Detached = false is
	// an optimization for grace mode which discards the original response
	ToCacheable(ttl time.Time) CachedResponse

	// Releases any resources associated with the response
	Close()

	// Whether or not the response came from a cached source
	// (affects the cache stat)
	Cached() bool
}

An http response

func Empty

func Empty(status int) Response

Builds a response with no body and the given status

func EmptyH

func EmptyH(status int, header http.Header) Response

Builds a response with no body and the given status an headers

func Json

func Json(status int, body interface{}) Response

Builds a response with the given status code and body The body can be a string, []byte, or io.ReadCloser. Will generate a generic Fatal (500) response for other types A Json response is the same as a normal response, except that the content-type is set to application/json

func Respond

func Respond(status int, body interface{}) Response

Builds a response with the given status code and body The body can be a string, []byte, or io.ReadCloser. Will generate a generic Fatal (500) response for other types

func RespondH

func RespondH(status int, header http.Header, body interface{}) Response

Builds a response with the given status code, headers and body The body can be a string, []byte, or io.ReadCloser. Will generate a generic Fatal (500) response for other types

func Streaming

func Streaming(status int, header http.Header, contentLength int64, body io.ReadCloser) Response

type Route

type Route struct {
	Name        string
	Method      string
	Upstream    Upstream
	Stats       *RouteStats
	Cache       *RouteCache
	StopHandler Handler
	FlowHandler Middleware
}

type RouteCache

type RouteCache struct {
	KeyLookup CacheKeyLookup
	TTL       time.Duration
}

func NewRouteCache

func NewRouteCache(ttl time.Duration, keyLookup CacheKeyLookup) *RouteCache

type RouteStats

type RouteStats struct {
	Treshold time.Duration
	// contains filtered or unexported fields
}

Each route has its own stats. To avoid having to store potentially unlimited values to calculate percentiles, sampling is used. The total memory required for this is:

STATS_SAMPLE_SIZE * 2 * 64 * <NUMBER_OF_ROUTES>

func NewRouteStats

func NewRouteStats(treshold time.Duration) *RouteStats

func (*RouteStats) Hit

func (s *RouteStats) Hit(res Response, t time.Duration)

Called on each request

func (*RouteStats) Snapshot

func (s *RouteStats) Snapshot() Snapshot

Get a snapsnot of this route's current stats Getting a snapshot resets all statistics

type Runtime

type Runtime struct {
	Address          string
	NotFoundResponse Response
	FatalResponse    Response
	Executor         Handler
	Upstreams        map[string]Upstream
	Routes           map[string]*Route
	Router           *router.Router
	BytePool         *bytepool.Pool
	StatsWorker      *StatsWorker
	Cache            *Cache
	Resolver         *dnscache.Resolver
	HydrateLoader    HydrateLoader
}

All the data needed to serve requests Built automatically when the garnish.Start() is called

func (*Runtime) RegisterStats

func (r *Runtime) RegisterStats(name string, reporter Reporter)

func (*Runtime) ReplaceWith

func (o *Runtime) ReplaceWith(n *Runtime)

func (*Runtime) ServeHTTP

func (r *Runtime) ServeHTTP(out http.ResponseWriter, request *http.Request)

type Serializer

type Serializer interface {
	Write(b []byte)
	WriteInt(i int)
	WriteByte(b byte)
	WriteString(s string)
}

type SingleTransportUpstream

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

func (*SingleTransportUpstream) Headers

func (u *SingleTransportUpstream) Headers() []string

func (*SingleTransportUpstream) Transport

func (u *SingleTransportUpstream) Transport() *Transport

func (*SingleTransportUpstream) Tweaker

type Snapshot

type Snapshot map[string]int64

A set of metrics

type StatsWorker

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

Background worker that persists the stats every minute

func NewStatsWorker

func NewStatsWorker(runtime *Runtime, fileName string) *StatsWorker

func (*StatsWorker) Run

func (w *StatsWorker) Run()

Run the worker

func (*StatsWorker) Stop

func (w *StatsWorker) Stop()

type StreamingResponse

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

A standard response. This response is used by the cache. It's also used when the upstream didn't provide a Content-Length, or whe the Content-Length was greater then the configured BytePool's capacity

func (*StreamingResponse) AddHeader

func (r *StreamingResponse) AddHeader(key, value string) Response

func (*StreamingResponse) Cached

func (r *StreamingResponse) Cached() bool

func (*StreamingResponse) Close

func (r *StreamingResponse) Close()

func (*StreamingResponse) ContentLength

func (r *StreamingResponse) ContentLength() int

func (*StreamingResponse) Header

func (r *StreamingResponse) Header() http.Header

func (*StreamingResponse) Status

func (r *StreamingResponse) Status() int

func (*StreamingResponse) ToCacheable

func (r *StreamingResponse) ToCacheable(expires time.Time) CachedResponse

func (*StreamingResponse) Write

func (r *StreamingResponse) Write(runtime *Runtime, w io.Writer)

type Transport

type Transport struct {
	*http.Transport
	Address string
}

type Upstream

type Upstream interface {
	Headers() []string
	Transport() *Transport
	Tweaker() RequestTweaker
}

func CreateUpstream

func CreateUpstream(headers []string, tweaker RequestTweaker, transports []*Transport) (Upstream, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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