xweb

package module
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2023 License: Apache-2.0 Imports: 19 Imported by: 14

README

xweb

xweb allows Golang HTTP handlers to be registered with bindings that allow each API to be exposed via YAML configuration. The configuration can expose each API multiple times over different ports, network interfaces, and with the same root identity (x509 certificates) or separate ones. xweb allows Web APIs to be written once and then composed via configuratoin for exposure on publicly reachable network interfaces or not depending on the deployment model desired.

A great use case is development environments where all the APIs would be exposed on a single host/container vs a production environment that would expose each API differently based on sensitivity/security/access.

More to Come!

Documentation

Overview

Copyright NetFoundry Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Package xweb provides facilities to creating composable xweb.ApiHandler instances and http.Server's from configuration files.

Basics

xweb provides customizable and extendable components to stand up multiple http.Server's listening on one or more network interfaces and ports.

Each Instance is responsible for defining configuration sections to be parsed, parsing the configuration, starting servers, and shutting down relevant server. An example implementation is included in the package: InstanceImpl. This implementation should cover most use cases. In addition, InstanceImpl makes use of InstanceConfig which is reusable component for parsing InstanceImpl configuration sections. Both Instance and InstanceConfig assume that configuration will be acquired from some source and be presented as a map of interface{}-to-interface{} values.

InstanceConfig configuration sections allow the definition of an array of ServerConfig. In turn each ServerConfig can listen on many interface/port combinations specified by an array of BindPointConfig's and host many http.Handler's by defining an array of ApiConfig's that are converted into ApiHandler's. ApiHandler's are http.Handler's with metadata and can be as complex or as simple as necessary - using other libraries or only the standard http Go capabilities.

To deal with a single ServerConfig hosting multiple APIs as web.ServerConfig's, incoming requests must be forwarded to the correct ApiHandler. The responsibility is handled by another configurable http.Handler called an "xweb demux handler". This handler's responsibility is to inspect incoming requests and forward them to the correct ApiHandler. It is specified by an DemuxFactory and a reference implementation, PathPrefixDemuxFactory has been provided.

Another way to say it: each Instance defines a configuration section (default `web`) to define ServerConfig's and their hosted APIs. Each ServerConfig maps to one Server/http.Server per BindPointConfig. No two Server instances can have colliding BindPointConfig's due to port conflicts.

Copyright NetFoundry Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Index

Constants

View Source
const (
	HandlerContextKey = ContextKey("xweb.ApiHandler.ContextKey")
	ServerContextKey  = ContextKey("xweb.Server.ContextKey")
)
View Source
const (
	DefaultIdentitySection = "identity"
	DefaultConfigSection   = "web"
)
View Source
const (
	MinTLSVersion = tls.VersionTLS12
	MaxTLSVersion = tls.VersionTLS13

	DefaultHttpWriteTimeout = time.Second * 10
	DefaultHttpReadTimeout  = time.Second * 5
	DefaultHttpIdleTimeout  = time.Second * 5
)
View Source
const (
	ZitiCtrlAddressHeader = "ziti-ctrl-address"
)

Variables

View Source
var ReverseTlsVersionMap = map[int]string{
	tls.VersionTLS10: "TLS1.0",
	tls.VersionTLS11: "TLS1.1",
	tls.VersionTLS12: "TLS1.2",
	tls.VersionTLS13: "TLS1.3",
}

ReverseTlsVersionMap is a map of TLS version identifiers to configuration strings

View Source
var TlsVersionMap = map[string]int{
	"TLS1.0": tls.VersionTLS10,
	"TLS1.1": tls.VersionTLS11,
	"TLS1.2": tls.VersionTLS12,
	"TLS1.3": tls.VersionTLS13,
}

TlsVersionMap is a map of configuration strings to TLS version identifiers

Functions

This section is empty.

Types

type ApiBinding

type ApiBinding interface {
	Binding() string
	Options() map[interface{}]interface{}
}

ApiBinding is an interface defines the minimum operations necessary to convert configuration into a ApiHandler by some ApiHandlerFactory. The ApiBinding.Binding() value is used to map configuration data to specific ApiHandlerFactory instances that generate a ApiHandler with the same binding value.

type ApiConfig

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

ApiConfig represents some "api" or "site" by binding name. Each ApiConfig configuration is used against a Registry to locate the proper factory to generate a ApiHandler. The options provided by this structure are parsed by the ApiHandlerFactory and the behavior, valid keys, and valid values are not defined by xweb components, but by that ApiHandlerFactory and its resulting ApiHandler's.

func (*ApiConfig) Binding

func (api *ApiConfig) Binding() string

Binding returns the string that uniquely identifies bo the ApiHandlerFactory and resulting ApiHandler instances that will be attached to some ServerConfig and its resulting Server.

func (*ApiConfig) Options

func (api *ApiConfig) Options() map[interface{}]interface{}

Options returns the options associated with this ApiConfig binding.

func (*ApiConfig) Parse

func (api *ApiConfig) Parse(apiConfigMap map[interface{}]interface{}) error

Parse the configuration map for an ApiConfig.

func (*ApiConfig) Validate

func (api *ApiConfig) Validate() error

Validate this configuration object.

type ApiHandler

type ApiHandler interface {
	Binding() string
	Options() map[interface{}]interface{}
	RootPath() string
	IsHandler(r *http.Request) bool

	http.Handler
}

ApiHandler is an interface that is a http.Handler with options, binding, and information for a specific ApiConfig that was generated from a ApiHandlerFactory.

func HandlerFromRequestContext

func HandlerFromRequestContext(ctx context.Context) *ApiHandler

HandlerFromRequestContext us a utility function to retrieve a ApiHandler reference, that the demux http.Handler deferred to, during downstream http.Handler processing from the http.Request context.

type ApiHandlerFactory

type ApiHandlerFactory interface {
	// Binding returns the string binding value used in configurations
	Binding() string

	// New creates a new instances of this factories ApiConfig
	New(serverConfig *ServerConfig, options map[interface{}]interface{}) (ApiHandler, error)

	// Validate is used for factory level configuration checks. It is not meant for individual instance validation.
	// It is meant for validating configuration that all instances generated by a factory share (i.e. sanity across
	// instances or configuration from another section).
	Validate(config *InstanceConfig) error
}

The ApiHandlerFactory interface generates ApiHandler instances. Factories can use a single instance or multiple instances based on need. This interface allows ApiHandler logic to be reused across multiple xweb.Server's while delegating the instance management to the factory.

type BindPointConfig

type BindPointConfig struct {
	InterfaceAddress string //<interface>:<port>
	Address          string //<ip/host>:<port>
	NewAddress       string //<ip/host>:<port> sent out as a header for clients to alternatively swap to (ip -> hostname moves)
}

BindPointConfig represents the interface:port address of where a http.Server should listen for a ServerConfig and the public address that should be used to address it.

func (*BindPointConfig) Parse

func (bindPoint *BindPointConfig) Parse(config map[interface{}]interface{}) error

Parse the configuration map for a BindPointConfig.

func (*BindPointConfig) Validate

func (bindPoint *BindPointConfig) Validate() error

Validate this configuration object.

type ContextKey

type ContextKey string

type DefaultApiHandler

type DefaultApiHandler interface {
	ApiHandler
	IsDefault() bool
}

type DefaultHttpHandlerProvider

type DefaultHttpHandlerProvider interface {
	GetDefaultHttpHandler() http.Handler
	SetDefaultHttpHandler(handler http.Handler)
	SetParent(parent DefaultHttpHandlerProvider)
}

DefaultHttpHandlerProvider is an interface that allows different levels of xweb's components: Instance, ServerConfig, Server. The default handler used when no matching ApiHandler is found is: Instance > ServerConfig > Server

type DefaultHttpHandlerProviderImpl

type DefaultHttpHandlerProviderImpl struct {
	Parent      DefaultHttpHandlerProvider
	HttpHandler http.Handler
}

func (*DefaultHttpHandlerProviderImpl) GetDefaultHttpHandler

func (d *DefaultHttpHandlerProviderImpl) GetDefaultHttpHandler() http.Handler

func (*DefaultHttpHandlerProviderImpl) SetDefaultHttpHandler

func (d *DefaultHttpHandlerProviderImpl) SetDefaultHttpHandler(handler http.Handler)

func (*DefaultHttpHandlerProviderImpl) SetParent

type DemuxFactory

type DemuxFactory interface {
	Build(handlers []ApiHandler) (DemuxHandler, error)
}

DemuxFactory generates a http.Handler that interrogates a http.Request and routes them to ApiHandler instances. The selected ApiHandler is added to the context with a key of HandlerContextKey. Each DemuxFactory implementation must define its own behaviors for an unmatched http.Request.

type DemuxHandler

type DemuxHandler interface {
	DefaultHttpHandlerProvider
	http.Handler
}

type DemuxHandlerImpl

type DemuxHandlerImpl struct {
	DefaultHttpHandlerProviderImpl
	Handler http.Handler
}

func (*DemuxHandlerImpl) ServeHTTP

func (d *DemuxHandlerImpl) ServeHTTP(writer http.ResponseWriter, request *http.Request)

type Instance

type Instance interface {
	DefaultHttpHandlerProvider
	Enabled() bool
	LoadConfig(cfgmap map[interface{}]interface{}) error
	Run()
	Shutdown()
	GetRegistry() Registry
	GetDemuxFactory() DemuxFactory
	GetConfig() *InstanceConfig
}

Instance implements config.Subconfig to allow Instance implementations to be used during the normal component startup and configuration phase.

type InstanceConfig

type InstanceConfig struct {
	SourceConfig map[interface{}]interface{}

	ServerConfigs []*ServerConfig
	Section       string

	DefaultIdentity        identity.Identity
	DefaultIdentitySection string
	// contains filtered or unexported fields
}

InstanceConfig is the root configuration options necessary to start numerous http.Server instances

func (*InstanceConfig) Enabled

func (config *InstanceConfig) Enabled() bool

Enabled returns true/false on whether this configuration should be considered "enabled". Set to true after Validate passes.

func (*InstanceConfig) Parse

func (config *InstanceConfig) Parse(configMap map[interface{}]interface{}) error

Parse parses a configuration map, looking for sections that define an identity.InstanceConfig and an array of ServerConfig's.

func (*InstanceConfig) Validate

func (config *InstanceConfig) Validate(registry Registry) error

Validate uses a Registry to validate that all ApiConfig bindings may be fulfilled. All other relevant InstanceConfig values are also validated.

type InstanceImpl

type InstanceImpl struct {
	DefaultHttpHandlerProviderImpl
	Config *InstanceConfig

	Registry     Registry
	DemuxFactory DemuxFactory
	// contains filtered or unexported fields
}

InstanceImpl is a basic implementation of Instance.

func NewDefaultInstance

func NewDefaultInstance(registry Registry, defaultIdentity identity.Identity) *InstanceImpl

func (*InstanceImpl) Build

func (i *InstanceImpl) Build()

Build assembles all the xweb components from configuration and prepares to have Start() called.

func (*InstanceImpl) Enabled

func (i *InstanceImpl) Enabled() bool

Enabled returns true/false on whether this subconfig should be considered enabled

func (*InstanceImpl) GetConfig

func (i *InstanceImpl) GetConfig() *InstanceConfig

GetConfig returns the associated InstanceConfig

func (*InstanceImpl) GetDemuxFactory

func (i *InstanceImpl) GetDemuxFactory() DemuxFactory

GetDemuxFactory returns the associated DemuxFactory

func (*InstanceImpl) GetRegistry

func (i *InstanceImpl) GetRegistry() Registry

GetRegistry returns the associated Registry

func (*InstanceImpl) LoadConfig

func (i *InstanceImpl) LoadConfig(cfgmap map[interface{}]interface{}) error

LoadConfig handles subconfig operations for xweb.Instance components

func (*InstanceImpl) Run

func (i *InstanceImpl) Run()

Run builds and starts the necessary xweb.Server's

func (*InstanceImpl) Shutdown

func (i *InstanceImpl) Shutdown()

Shutdown stop all running xweb.Server's

func (*InstanceImpl) Start

func (i *InstanceImpl) Start()

Start calls Start() on all Servers that were built by calling Build().

type IsHandledDemuxFactory

type IsHandledDemuxFactory struct {
	DefaultHttpHandlerProviderImpl
}

IsHandledDemuxFactory is a DemuxFactory that routes http.Request requests to a specific ApiHandler by delegating to the ApiHandler's IsHandled function.

func (*IsHandledDemuxFactory) Build

func (factory *IsHandledDemuxFactory) Build(handlers []ApiHandler) (DemuxHandler, error)

Build performs ApiHandler selection based on IsHandled()

type Options

type Options struct {
	TimeoutOptions
	TlsVersionOptions
}

Options is the shared options for a ServerConfig.

func (*Options) Default

func (options *Options) Default()

Default provides defaults for all necessary values

func (*Options) Parse

func (options *Options) Parse(optionsMap map[interface{}]interface{}) error

Parse parses a configuration map

type PathPrefixDemuxFactory

type PathPrefixDemuxFactory struct {
	DefaultHttpHandlerProviderImpl
}

PathPrefixDemuxFactory is a DemuxFactory that routes http.Request requests to a specific ApiHandler from a set of ApiHandler's by URL path prefixes. A http.Handler for NoHandlerFound can be provided to specify behavior to perform when a ApiHandler is not selected. By default an empty response with a http.StatusNotFound (404) will be sent.

func (*PathPrefixDemuxFactory) Build

func (factory *PathPrefixDemuxFactory) Build(handlers []ApiHandler) (DemuxHandler, error)

Build performs ApiHandler selection based on URL path prefixes

type Registry

type Registry interface {
	Add(factory ApiHandlerFactory) error
	Get(binding string) ApiHandlerFactory
}

Registry describes a registry of binding to ApiHandlerFactory registrations

type RegistryMap

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

RegistryMap is a basic Registry implementation backed by a simple mapping of binding (string) to ApiHandlerFactory instances

func NewRegistryMap

func NewRegistryMap() *RegistryMap

NewRegistryMap creates a new RegistryMap

func (RegistryMap) Add

func (registry RegistryMap) Add(factory ApiHandlerFactory) error

Add adds a factory to the registry. Errors if a previous factory with the same binding is registered.

func (RegistryMap) Get

func (registry RegistryMap) Get(binding string) ApiHandlerFactory

Get retrieves a factory based on a binding or nil if no factory for the binding is registered

type Server

type Server struct {
	DefaultHttpHandlerProviderImpl

	Handle         http.Handler
	OnHandlerPanic func(writer http.ResponseWriter, request *http.Request, panicVal interface{})
	ServerConfig   *ServerConfig
	// contains filtered or unexported fields
}

Server represents all the http.Server's and http.Handler's necessary to run a single xweb.ServerConfig

func NewServer

func NewServer(instance Instance, serverConfig *ServerConfig) (*Server, error)

NewServer creates a new Server from a ServerConfig. All necessary http.Handler's will be created from the supplied DemuxFactory and Registry.

func (*Server) Shutdown

func (server *Server) Shutdown(ctx context.Context)

Shutdown stops the server and all underlying http.Server's

func (*Server) Start

func (server *Server) Start() error

Start the server and all underlying http.Server's

type ServerConfig

type ServerConfig struct {
	DefaultHttpHandlerProviderImpl
	Name       string
	APIs       []*ApiConfig
	BindPoints []*BindPointConfig
	Options    Options

	DefaultIdentity identity.Identity
	Identity        identity.Identity
}

ServerConfig is the configuration that will eventually be used to create a xweb.Server (which in turn houses all the components necessary to run multiple http.Server's).

func (*ServerConfig) Parse

func (config *ServerConfig) Parse(configMap map[interface{}]interface{}, pathContext string) error

Parse parses a configuration map to set all relevant ServerConfig values.

func (*ServerConfig) Validate

func (config *ServerConfig) Validate(registry Registry) error

Validate all ServerConfig values

type ServerContext

type ServerContext struct {
	BindPoint    *BindPointConfig
	ServerConfig *ServerConfig
	Config       *InstanceConfig
}

func ServerContextFromRequestContext

func ServerContextFromRequestContext(ctx context.Context) *ServerContext

ServerContextFromRequestContext is a utility function to retrieve a *ServerContext reference from the http.Request that provides access to XWeb configuration like BindPointConfig, ServerConfig, and InstanceConfig values.

type TimeoutOptions

type TimeoutOptions struct {
	ReadTimeout  time.Duration
	IdleTimeout  time.Duration
	WriteTimeout time.Duration
}

TimeoutOptions represents http timeout options

func (*TimeoutOptions) Default

func (timeoutOptions *TimeoutOptions) Default()

Default defaults all HTTP timeout options

func (*TimeoutOptions) Parse

func (timeoutOptions *TimeoutOptions) Parse(config map[interface{}]interface{}) error

Parse parses a config map

func (*TimeoutOptions) Validate

func (timeoutOptions *TimeoutOptions) Validate() error

Validate validates all settings and return nil or an error

type TlsVersionOptions

type TlsVersionOptions struct {
	MinTLSVersion int

	MaxTLSVersion int
	// contains filtered or unexported fields
}

TlsVersionOptions represents TLS version options

func (*TlsVersionOptions) Default

func (tlsVersionOptions *TlsVersionOptions) Default()

Default defaults TLS versions

func (*TlsVersionOptions) Parse

func (tlsVersionOptions *TlsVersionOptions) Parse(config map[interface{}]interface{}) error

Parse parses a config map

func (*TlsVersionOptions) Validate

func (tlsVersionOptions *TlsVersionOptions) Validate() error

Validate validates the configuration values and returns nil or error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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