routing

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2024 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package routing provides routers for handling gRPC and HTTP requests in grpcbridge. Currently, two routers are present with pretty different logic in regard to routing:

  1. ServiceRouter, which can route gRPC and HTTP requests according to the path definition in gRPC's PROTOCOL-HTTP2 spec, and only requires information about the target's available service names, not complete method and binding definitions.
  2. PatternRouter, which can route HTTP requests according to the path templates defined in gRPC Transcoding's http.proto, but requires full method and binding definitions for each of a target's services. It is compatible with the routing used in the gRPC-Gateway apart from slight security-related changes.

Both of these routers are used by grpcbridge itself to optimize and perform routing in different use-cases, such as HTTP-to-gRPC transcoding, gRPC proxying, gRPC-Web bridging, etc.

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyWatching = errors.New("target already being watched")

ErrAlreadyWatching is returned by the Watch() method on routers when a watcher already exists for the specified target and a new one should not be created without closing the previous one first.

Functions

This section is empty.

Types

type GRPCRoute

type GRPCRoute struct {
	Target  *bridgedesc.Target
	Service *bridgedesc.Service
	Method  *bridgedesc.Method
}

GRPCRoute contains the matched route information for a single gRPC request, returned by the RouteGRPC method of the routers.

type GRPCRouter

type GRPCRouter interface {
	RouteGRPC(context.Context) (grpcadapter.ClientConn, GRPCRoute, error)
}

GRPCRouter is the interface implemented by routers capable of routing gRPC requests. Unlike HTTPRouter, it doesn't receive a request in its raw form, since no such universal form exists for gRPC in Go, and instead the incoming gRPC request context is passed. The router can use standard gRPC methods such as grpc.Method, metadata.FromIncomingContext, and peer.FromContext to retrieve the necessary information. Errors returned by RouteGRPC should be gRPC status errors which can be returned to the client as-is.

type HTTPRoute

type HTTPRoute struct {
	Target  *bridgedesc.Target
	Service *bridgedesc.Service
	Method  *bridgedesc.Method
	Binding *bridgedesc.Binding
	// Matched, URL-decoded path parameters defined by the binding pattern.
	// See https://github.com/googleapis/googleapis/blob/e0677a395947c2f3f3411d7202a6868a7b069a41/google/api/http.proto#L295
	// for information about how exactly different kinds of parameters are decoded.
	PathParams map[string]string
}

HTTPRoute contains the matched route information for a single specific HTTP request, returned by the RouteHTTP method of the routers.

type HTTPRouter

type HTTPRouter interface {
	RouteHTTP(*http.Request) (grpcadapter.ClientConn, HTTPRoute, error)
}

HTTPRouter is the interface implemented by routers capable of routing HTTP requests. RouteHTTP can use any information available in the request to perform routing and return a connection to the target as well as the matched route information, including any path parameters. Errors returned by RouteHTTP should preferrably be gRPC status errors with HTTP-appropriate codes like NotFound set, but they can additionally implement interface { HTTPStatus() int } to return a custom HTTP status code.

type PatternRouter

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

PatternRouter is a router meant for routing HTTP requests with non-gRPC URLs/contents. It uses pattern-based route matching like the one used in gRPC-Gateway, but additionally supports dynamic routing updates via PatternRouterWatcher, meant to be used with a description resolver such as the one in the github.com/renbou/grpcbridge/reflection package.

Unlike gRPC-Gateway it doesn't support POST->GET fallbacks and X-HTTP-Method-Override, since such features can easily become a source of security issues for an unsuspecting developer. By the same logic, request paths aren't cleaned, i.e. multiple slashes, ./.. elements aren't removed.

func NewPatternRouter

func NewPatternRouter(pool grpcadapter.ClientPool, opts PatternRouterOpts) *PatternRouter

NewPatternRouter initializes a new PatternRouter with the specified connection pool and options.

The connection pool will be used to perform a simple retrieval of the connection to a target by its name. for more complex connection routing this router's PatternRouter.RouteHTTP can be wrapped to return a different connection based on the matched method and HTTP request parameters.

func (*PatternRouter) RouteHTTP

RouteHTTP routes the HTTP request based on its URL path and method using the target descriptions received via updates through PatternRouterWatcher.UpdateDesc.

Errors returned by RouteHTTP are gRPC status.Status errors with the code set accordingly. Currently, the NotFound, InvalidArgument, and Unavailable codes are returned. Additionally, it can return an error implementing interface { HTTPStatus() int } to set a custom status code, but it doesn't currently do so.

Performance-wise it is notable that updates to the routing information don't block RouteHTTP, happening fully in the background.

func (*PatternRouter) Watch

func (pr *PatternRouter) Watch(target string) (*PatternRouterWatcher, error)

Watch starts watching the specified target for description changes. It returns a *PatternRouterWatcher through which new updates for this target can be applied.

It is an error to try Watch()ing the same target multiple times on a single PatternRouter instance, the previous PatternRouterWatcher must be explicitly closed before launching a new one. Instead of trying to synchronize such procedures, however, it's better to have a properly defined lifecycle for each possible target, with clear logic about when it gets added or removed to/from all the components of a bridge.

type PatternRouterOpts

type PatternRouterOpts struct {
	// Logs are discarded by default.
	Logger bridgelog.Logger
}

PatternRouterOpts define all the optional settings which can be set for PatternRouter.

type PatternRouterWatcher

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

PatternRouterWatcher is a description update watcher created for a specific target in the context of a PatternRouter instance. New PatternRouterWatchers are created through PatternRouter.Watch.

func (*PatternRouterWatcher) Close

func (prw *PatternRouterWatcher) Close()

Close closes the watcher, preventing further updates from being applied to the router through it. It is an error to call Close() multiple times on the same watcher, and doing so will result in a panic.

func (*PatternRouterWatcher) ReportError

func (prw *PatternRouterWatcher) ReportError(error)

ReportError is currently a no-op, present simply to implement the Watcher interface of the grpcbridge description resolvers, such as the one in github.com/renbou/grpcbridge/reflection.

func (*PatternRouterWatcher) UpdateDesc

func (prw *PatternRouterWatcher) UpdateDesc(desc *bridgedesc.Target)

UpdateDesc updates the description of the target this watcher is watching. After the watcher is Close()d, UpdateDesc becomes a no-op, to avoid writing meaningless updates to the router. Note that desc.Name must match the target this watcher was created for, otherwise the update will be ignored.

Updates to the routing information are made without any locking, instead replacing the currently present info with the updated one using an atomic pointer.

UpdateDesc returns only when the routing state has been completely updated on the router, which should be used to synchronize the target description update polling/watching logic.

type ServiceRouter

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

ServiceRouter is a router meant for routing HTTP or gRPC requests with the standard gRPC method format of the form "/package.Service/Method". It relies on all targets having unique gRPC service names, and it doesn't even take the method name into account, which allows it to run solely based on the knowledge of a target's service names. This is useful as it allows description resolvers to be greatly simplified or optimized. For example, the reflection resolver in github.com/renbou/grpcbridge/reflection has an OnlyServices option for this specific case.

func NewServiceRouter

func NewServiceRouter(pool grpcadapter.ClientPool, opts ServiceRouterOpts) *ServiceRouter

NewServiceRouter initializes a new ServiceRouter with the specified connection pool and options.

The connection pool will be used to perform a simple retrieval of the connection to a target by its name. for more complex connection routing this router's methods can be wrapped to return a different connection based on the matched method and HTTP/GRPC request information.

func (*ServiceRouter) RouteGRPC

RouteGRPC routes the gRPC request based on its method, which is retrieved using grpc.Method. The context is expected to be a stream/request context from a valid gRPC request, however all the necessary information can be added to it manually for routing some custom requests using grpc.NewContextWithServerTransportStream.

Errors returned by RouteGRPC are gRPC status.Status errors with the code set accordingly. Currently, the Internal, Unimplemented, and Unavailable codes are returned.

Performance-wise it is notable that updates to the routing information don't block RouteGRPC, happening fully in the background.

func (*ServiceRouter) RouteHTTP

RouteHTTP implements routing for POST HTTP requests, using the request path as the method name. It simulates pattern-based routing with default bindings, but is much more efficient than PatternRouter.RouteHTTP because it relies solely on the service name part of the request path and doesn't have to perform any pattern-matching.

See ServiceRouter.RouteGRPC for more details, as this method is very similar, with the only notable differences being the different status codes returned, which are more suitable for HTTP. Additionally, an error implementing interface { HTTPStatus() int } can be returned, which should be used to set a custom status code.

func (*ServiceRouter) Watch

func (sr *ServiceRouter) Watch(target string) (*ServiceRouterWatcher, error)

Watch starts watching the specified target for description changes. It returns a *ServiceRouterWatcher through which new updates for this target can be applied.

It is an error to try Watch()ing the same target multiple times on a single ServiceRouter instance, See the comment for PatternRouter.Watch for some extra detail regarding this API mechanic.

type ServiceRouterOpts

type ServiceRouterOpts struct {
	// Logs are discarded by default.
	Logger bridgelog.Logger
}

ServiceRouterOpts define all the optional settings which can be set for ServiceRouter.

type ServiceRouterWatcher

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

ServiceRouterWatcher is a description update watcher created for a specific target in the context of a ServiceRouter instance. New ServiceRouterWatchers are created through ServiceRouter.Watch.

func (*ServiceRouterWatcher) Close

func (srw *ServiceRouterWatcher) Close()

Close closes the watcher, preventing further updates from being applied to the router through it. It is an error to call Close() multiple times on the same watcher, and doing so will result in a panic.

func (*ServiceRouterWatcher) ReportError

func (srw *ServiceRouterWatcher) ReportError(error)

ReportError is currently a no-op, present simply to implement the Watcher interface of the grpcbridge description resolvers, such as the one in github.com/renbou/grpcbridge/reflection.

func (*ServiceRouterWatcher) UpdateDesc

func (srw *ServiceRouterWatcher) UpdateDesc(desc *bridgedesc.Target)

UpdateDesc updates the description of the target this watcher is watching. It follows the same semantics as PatternRouterWatcher.UpdateDesc, the documentation for which goes into more detail.

Jump to

Keyboard shortcuts

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