Bump reva deps (#8412)
* bump dependencies Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * bump reva and add config options Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> --------- Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Vendored
+20
-14
@@ -8,14 +8,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/api/router"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
// The gateway interface provides a way to
|
||||
// create composable API gateways
|
||||
// API interface provides a way to
|
||||
// create composable API gateways.
|
||||
type Api interface {
|
||||
// Initialise options
|
||||
// Initialize options
|
||||
Init(...Option) error
|
||||
// Get the options
|
||||
Options() Options
|
||||
@@ -29,16 +30,20 @@ type Api interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Options are API options.
|
||||
type Options struct {
|
||||
// Address of the server
|
||||
Address string
|
||||
// Router for resolving routes
|
||||
Router router.Router
|
||||
// Client to use for RPC
|
||||
Client client.Client
|
||||
// Address of the server
|
||||
Address string
|
||||
}
|
||||
|
||||
// Option type are API option args.
|
||||
type Option func(*Options) error
|
||||
|
||||
// Endpoint is a mapping between an RPC method and HTTP endpoint
|
||||
// Endpoint is a mapping between an RPC method and HTTP endpoint.
|
||||
type Endpoint struct {
|
||||
// RPC Method e.g. Greeter.Hello
|
||||
Name string
|
||||
@@ -56,7 +61,7 @@ type Endpoint struct {
|
||||
Stream bool
|
||||
}
|
||||
|
||||
// Service represents an API service
|
||||
// Service represents an API service.
|
||||
type Service struct {
|
||||
// Name of service
|
||||
Name string
|
||||
@@ -82,21 +87,22 @@ func slice(s string) []string {
|
||||
return sl
|
||||
}
|
||||
|
||||
// Encode encodes an endpoint to endpoint metadata
|
||||
// Encode encodes an endpoint to endpoint metadata.
|
||||
func Encode(e *Endpoint) map[string]string {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// endpoint map
|
||||
ep := make(map[string]string)
|
||||
em := make(map[string]string)
|
||||
|
||||
// set vals only if they exist
|
||||
set := func(k, v string) {
|
||||
if len(v) == 0 {
|
||||
return
|
||||
}
|
||||
ep[k] = v
|
||||
|
||||
em[k] = v
|
||||
}
|
||||
|
||||
set("endpoint", e.Name)
|
||||
@@ -106,10 +112,10 @@ func Encode(e *Endpoint) map[string]string {
|
||||
set("path", strings.Join(e.Path, ","))
|
||||
set("host", strings.Join(e.Host, ","))
|
||||
|
||||
return ep
|
||||
return em
|
||||
}
|
||||
|
||||
// Decode decodes endpoint metadata into an endpoint
|
||||
// Decode decodes endpoint metadata into an endpoint.
|
||||
func Decode(e map[string]string) *Endpoint {
|
||||
if e == nil {
|
||||
return nil
|
||||
@@ -125,7 +131,7 @@ func Decode(e map[string]string) *Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates an endpoint to guarantee it won't blow up when being served
|
||||
// Validate validates an endpoint to guarantee it won't blow up when being served.
|
||||
func Validate(e *Endpoint) error {
|
||||
if e == nil {
|
||||
return errors.New("endpoint is nil")
|
||||
@@ -172,7 +178,7 @@ func WithEndpoint(e *Endpoint) server.HandlerOption {
|
||||
return server.EndpointMetadata(e.Name, Encode(e))
|
||||
}
|
||||
|
||||
// NewApi returns a new api gateway
|
||||
// NewApi returns a new api gateway.
|
||||
func NewApi(opts ...Option) Api {
|
||||
return newApi(opts...)
|
||||
}
|
||||
|
||||
+3
-4
@@ -45,7 +45,6 @@ func newApi(opts ...Option) Api {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise options
|
||||
func (a *api) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&a.options)
|
||||
@@ -53,17 +52,17 @@ func (a *api) Init(opts ...Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the options
|
||||
// Get the options.
|
||||
func (a *api) Options() Options {
|
||||
return a.options
|
||||
}
|
||||
|
||||
// Register a http handler
|
||||
// Register a http handler.
|
||||
func (a *api) Register(*Endpoint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Register a route
|
||||
// Register a route.
|
||||
func (a *api) Deregister(*Endpoint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Handler represents a HTTP handler that manages a request
|
||||
// Handler represents a HTTP handler that manages a request.
|
||||
type Handler interface {
|
||||
// standard http handler
|
||||
http.Handler
|
||||
|
||||
+12
-8
@@ -7,20 +7,23 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultMaxRecvSize int64 = 1024 * 1024 * 100 // 10Mb
|
||||
// DefaultMaxRecvSize is 10MiB.
|
||||
DefaultMaxRecvSize int64 = 1024 * 1024 * 100
|
||||
)
|
||||
|
||||
// Options is the list of api Options.
|
||||
type Options struct {
|
||||
MaxRecvSize int64
|
||||
Namespace string
|
||||
Router router.Router
|
||||
Client client.Client
|
||||
Logger logger.Logger
|
||||
Namespace string
|
||||
MaxRecvSize int64
|
||||
}
|
||||
|
||||
// Option is a api Option.
|
||||
type Option func(o *Options)
|
||||
|
||||
// NewOptions fills in the blanks
|
||||
// NewOptions fills in the blanks.
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Logger: logger.DefaultLogger,
|
||||
@@ -45,34 +48,35 @@ func NewOptions(opts ...Option) Options {
|
||||
return options
|
||||
}
|
||||
|
||||
// WithNamespace specifies the namespace for the handler
|
||||
// WithNamespace specifies the namespace for the handler.
|
||||
func WithNamespace(s string) Option {
|
||||
return func(o *Options) {
|
||||
o.Namespace = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithRouter specifies a router to be used by the handler
|
||||
// WithRouter specifies a router to be used by the handler.
|
||||
func WithRouter(r router.Router) Option {
|
||||
return func(o *Options) {
|
||||
o.Router = r
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the client for the handler.
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxRecvSize specifies max body size
|
||||
// WithMaxRecvSize specifies max body size.
|
||||
func WithMaxRecvSize(size int64) Option {
|
||||
return func(o *Options) {
|
||||
o.MaxRecvSize = size
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger specifies the logger
|
||||
// WithLogger specifies the logger.
|
||||
func WithLogger(l logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
|
||||
+88
-50
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
"github.com/oxtoacart/bpool"
|
||||
|
||||
"go-micro.dev/v4/api/handler"
|
||||
"go-micro.dev/v4/api/internal/proto"
|
||||
"go-micro.dev/v4/api/router"
|
||||
@@ -29,19 +28,20 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Handler is the name of this handler.
|
||||
Handler = "rpc"
|
||||
packageID = "go.micro.api"
|
||||
)
|
||||
|
||||
var (
|
||||
// supported json codecs
|
||||
// supported json codecs.
|
||||
jsonCodecs = []string{
|
||||
"application/grpc+json",
|
||||
"application/json",
|
||||
"application/json-rpc",
|
||||
}
|
||||
|
||||
// support proto codecs
|
||||
// support proto codecs.
|
||||
protoCodecs = []string{
|
||||
"application/grpc",
|
||||
"application/grpc+proto",
|
||||
@@ -66,7 +66,7 @@ func (b *buffer) Write(_ []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// strategy is a hack for selection
|
||||
// strategy is a hack for selection.
|
||||
func strategy(services []*registry.Service) selector.Strategy {
|
||||
return func(_ []*registry.Service) selector.Next {
|
||||
// ignore input to this function, use services above
|
||||
@@ -77,6 +77,7 @@ func strategy(services []*registry.Service) selector.Strategy {
|
||||
func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
logger := h.opts.Logger
|
||||
bsize := handler.DefaultMaxRecvSize
|
||||
|
||||
if h.opts.MaxRecvSize > 0 {
|
||||
bsize = h.opts.MaxRecvSize
|
||||
}
|
||||
@@ -84,6 +85,7 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, bsize)
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
var service *router.Route
|
||||
|
||||
if h.opts.Router != nil {
|
||||
@@ -94,8 +96,10 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
service = s
|
||||
} else {
|
||||
// we have no way of routing the request
|
||||
@@ -106,18 +110,18 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
ct := r.Header.Get("Content-Type")
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
|
||||
// Strip charset from Content-Type (like `application/json; charset=UTF-8`)
|
||||
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||
ct = ct[:idx]
|
||||
if idx := strings.IndexRune(contentType, ';'); idx >= 0 {
|
||||
contentType = contentType[:idx]
|
||||
}
|
||||
|
||||
// micro client
|
||||
c := h.opts.Client
|
||||
myClient := h.opts.Client
|
||||
|
||||
// create context
|
||||
cx := ctx.FromRequest(r)
|
||||
myContext := ctx.FromRequest(r)
|
||||
// get context from http handler wrappers
|
||||
md, ok := metadata.FromContext(r.Context())
|
||||
if !ok {
|
||||
@@ -133,23 +137,24 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// merge context with overwrite
|
||||
cx = metadata.MergeContext(cx, md, true)
|
||||
myContext = metadata.MergeContext(myContext, md, true)
|
||||
|
||||
// set merged context to request
|
||||
*r = *r.Clone(cx)
|
||||
*r = *r.Clone(myContext)
|
||||
// if stream we currently only support json
|
||||
if isStream(r, service) {
|
||||
// drop older context as it can have timeouts and create new
|
||||
// md, _ := metadata.FromContext(cx)
|
||||
//serveWebsocket(context.TODO(), w, r, service, c)
|
||||
if err := serveWebsocket(cx, w, r, service, c); err != nil {
|
||||
// serveWebsocket(context.TODO(), w, r, service, c)
|
||||
if err := serveWebsocket(myContext, w, r, service, myClient); err != nil {
|
||||
logger.Log(log.ErrorLevel, err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// create strategy
|
||||
so := selector.WithStrategy(strategy(service.Versions))
|
||||
mySelector := selector.WithStrategy(strategy(service.Versions))
|
||||
|
||||
// walk the standard call path
|
||||
// get payload
|
||||
@@ -158,6 +163,7 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if werr := writeError(w, r, err); werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -165,7 +171,7 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch {
|
||||
// proto codecs
|
||||
case hasCodec(ct, protoCodecs):
|
||||
case hasCodec(contentType, protoCodecs):
|
||||
request := &proto.Message{}
|
||||
// if the extracted payload isn't empty lets use it
|
||||
if len(br) > 0 {
|
||||
@@ -175,18 +181,19 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// create request/response
|
||||
response := &proto.Message{}
|
||||
|
||||
req := c.NewRequest(
|
||||
req := myClient.NewRequest(
|
||||
service.Service,
|
||||
service.Endpoint.Name,
|
||||
request,
|
||||
client.WithContentType(ct),
|
||||
client.WithContentType(contentType),
|
||||
)
|
||||
|
||||
// make the call
|
||||
if err := c.Call(cx, req, response, client.WithSelectOption(so)); err != nil {
|
||||
if err := myClient.Call(myContext, req, response, client.WithSelectOption(mySelector)); err != nil {
|
||||
if werr := writeError(w, r, err); werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -196,13 +203,14 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if werr := writeError(w, r, err); werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
// if json codec is not present set to json
|
||||
if !hasCodec(ct, jsonCodecs) {
|
||||
ct = "application/json"
|
||||
if !hasCodec(contentType, jsonCodecs) {
|
||||
contentType = "application/json"
|
||||
}
|
||||
|
||||
// default to trying json
|
||||
@@ -215,17 +223,18 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// create request/response
|
||||
var response json.RawMessage
|
||||
|
||||
req := c.NewRequest(
|
||||
req := myClient.NewRequest(
|
||||
service.Service,
|
||||
service.Endpoint.Name,
|
||||
&request,
|
||||
client.WithContentType(ct),
|
||||
client.WithContentType(contentType),
|
||||
)
|
||||
// make the call
|
||||
if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil {
|
||||
if err := myClient.Call(myContext, req, &response, client.WithSelectOption(mySelector)); err != nil {
|
||||
if werr := writeError(w, r, err); werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -235,6 +244,7 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if werr := writeError(w, r, err); werr != nil {
|
||||
logger.Log(log.ErrorLevel, werr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -245,8 +255,8 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (rh *rpcHandler) String() string {
|
||||
return "rpc"
|
||||
func (h *rpcHandler) String() string {
|
||||
return Handler
|
||||
}
|
||||
|
||||
func hasCodec(ct string, codecs []string) bool {
|
||||
@@ -255,49 +265,57 @@ func hasCodec(ct string, codecs []string) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// requestPayload takes a *http.Request.
|
||||
// If the request is a GET the query string parameters are extracted and marshaled to JSON and the raw bytes are returned.
|
||||
// If the request method is a POST the request body is read and returned
|
||||
// If the request method is a POST the request body is read and returned.
|
||||
func requestPayload(r *http.Request) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
// we have to decode json-rpc and proto-rpc because we suck
|
||||
// well actually because there's no proxy codec right now
|
||||
|
||||
ct := r.Header.Get("Content-Type")
|
||||
myCt := r.Header.Get("Content-Type")
|
||||
|
||||
switch {
|
||||
case strings.Contains(ct, "application/json-rpc"):
|
||||
case strings.Contains(myCt, "application/json-rpc"):
|
||||
msg := codec.Message{
|
||||
Type: codec.Request,
|
||||
Header: make(map[string]string),
|
||||
}
|
||||
|
||||
c := jsonrpc.NewCodec(&buffer{r.Body})
|
||||
if err = c.ReadHeader(&msg, codec.Request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var raw json.RawMessage
|
||||
if err = c.ReadBody(&raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ([]byte)(raw), nil
|
||||
case strings.Contains(ct, "application/proto-rpc"), strings.Contains(ct, "application/octet-stream"):
|
||||
case strings.Contains(myCt, "application/proto-rpc"), strings.Contains(myCt, "application/octet-stream"):
|
||||
msg := codec.Message{
|
||||
Type: codec.Request,
|
||||
Header: make(map[string]string),
|
||||
}
|
||||
|
||||
c := protorpc.NewCodec(&buffer{r.Body})
|
||||
if err = c.ReadHeader(&msg, codec.Request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var raw proto.Message
|
||||
if err = c.ReadBody(&raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return raw.Marshal()
|
||||
case strings.Contains(ct, "application/www-x-form-urlencoded"):
|
||||
case strings.Contains(myCt, "application/www-x-form-urlencoded"), strings.Contains(myCt, "application/x-www-form-urlencoded"):
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -315,6 +333,7 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
|
||||
// otherwise as per usual
|
||||
ctx := r.Context()
|
||||
|
||||
// dont user meadata.FromContext as it mangles names
|
||||
md, ok := metadata.FromContext(ctx)
|
||||
if !ok {
|
||||
@@ -331,9 +350,11 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
// filter own keys
|
||||
if strings.HasPrefix(k, "x-api-field-") {
|
||||
matches[strings.TrimPrefix(k, "x-api-field-")] = v
|
||||
|
||||
delete(md, k)
|
||||
} else if k == "x-api-body" {
|
||||
bodydst = v
|
||||
|
||||
delete(md, k)
|
||||
}
|
||||
}
|
||||
@@ -344,10 +365,12 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
// get fields from url values
|
||||
if len(r.URL.RawQuery) > 0 {
|
||||
umd := make(map[string]interface{})
|
||||
|
||||
err = qson.Unmarshal(&umd, r.URL.RawQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range umd {
|
||||
matches[k] = v
|
||||
}
|
||||
@@ -362,24 +385,29 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
req[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
em := make(map[string]interface{})
|
||||
em[ps[len(ps)-1]] = v
|
||||
|
||||
for i := len(ps) - 2; i > 0; i-- {
|
||||
nm := make(map[string]interface{})
|
||||
nm[ps[i]] = em
|
||||
em = nm
|
||||
}
|
||||
|
||||
if vm, ok := req[ps[0]]; ok {
|
||||
// nested map
|
||||
nm := vm.(map[string]interface{})
|
||||
for vk, vv := range em {
|
||||
nm[vk] = vv
|
||||
}
|
||||
|
||||
req[ps[0]] = nm
|
||||
} else {
|
||||
req[ps[0]] = em
|
||||
}
|
||||
}
|
||||
|
||||
pathbuf := []byte("{}")
|
||||
if len(req) > 0 {
|
||||
pathbuf, err = json.Marshal(req)
|
||||
@@ -389,48 +417,55 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
}
|
||||
|
||||
urlbuf := []byte("{}")
|
||||
|
||||
out, err := jsonpatch.MergeMergePatches(urlbuf, pathbuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
case http.MethodGet:
|
||||
// empty response
|
||||
if strings.Contains(ct, "application/json") && string(out) == "{}" {
|
||||
if strings.Contains(myCt, "application/json") && string(out) == "{}" {
|
||||
return out, nil
|
||||
} else if string(out) == "{}" && !strings.Contains(ct, "application/json") {
|
||||
} else if string(out) == "{}" && !strings.Contains(myCt, "application/json") {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
return out, nil
|
||||
case "PATCH", "POST", "PUT", "DELETE":
|
||||
case http.MethodPatch, http.MethodPost, http.MethodPut, http.MethodDelete:
|
||||
bodybuf := []byte("{}")
|
||||
buf := bufferPool.Get()
|
||||
|
||||
defer bufferPool.Put(buf)
|
||||
if _, err := buf.ReadFrom(r.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b := buf.Bytes(); len(b) > 0 {
|
||||
bodybuf = b
|
||||
}
|
||||
|
||||
if bodydst == "" || bodydst == "*" {
|
||||
if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil {
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
var jsonbody map[string]interface{}
|
||||
if json.Valid(bodybuf) {
|
||||
if err = json.Unmarshal(bodybuf, &jsonbody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
dstmap := make(map[string]interface{})
|
||||
ps := strings.Split(bodydst, ".")
|
||||
if len(ps) == 1 {
|
||||
if jsonbody != nil {
|
||||
dstmap[ps[0]] = jsonbody
|
||||
} else {
|
||||
// old unexpected behaviour
|
||||
// old unexpected behavior
|
||||
dstmap[ps[0]] = bodybuf
|
||||
}
|
||||
} else {
|
||||
@@ -438,7 +473,7 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
if jsonbody != nil {
|
||||
em[ps[len(ps)-1]] = jsonbody
|
||||
} else {
|
||||
// old unexpected behaviour
|
||||
// old unexpected behavior
|
||||
em[ps[len(ps)-1]] = bodybuf
|
||||
}
|
||||
for i := len(ps) - 2; i > 0; i-- {
|
||||
@@ -458,41 +493,41 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
//fallback to previous unknown behaviour
|
||||
return bodybuf, nil
|
||||
|
||||
}
|
||||
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func writeError(w http.ResponseWriter, r *http.Request, err error) error {
|
||||
func writeError(rsp http.ResponseWriter, req *http.Request, err error) error {
|
||||
ce := errors.Parse(err.Error())
|
||||
|
||||
switch ce.Code {
|
||||
case 0:
|
||||
// assuming it's totally screwed
|
||||
ce.Code = 500
|
||||
ce.Code = http.StatusInternalServerError
|
||||
ce.Id = packageID
|
||||
ce.Status = http.StatusText(500)
|
||||
ce.Status = http.StatusText(http.StatusInternalServerError)
|
||||
ce.Detail = "error during request: " + ce.Detail
|
||||
w.WriteHeader(500)
|
||||
|
||||
rsp.WriteHeader(http.StatusInternalServerError)
|
||||
default:
|
||||
w.WriteHeader(int(ce.Code))
|
||||
rsp.WriteHeader(int(ce.Code))
|
||||
}
|
||||
|
||||
// response content type
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
rsp.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// Set trailers
|
||||
if strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
|
||||
w.Header().Set("Trailer", "grpc-status")
|
||||
w.Header().Set("Trailer", "grpc-message")
|
||||
w.Header().Set("grpc-status", "13")
|
||||
w.Header().Set("grpc-message", ce.Detail)
|
||||
if strings.Contains(req.Header.Get("Content-Type"), "application/grpc") {
|
||||
rsp.Header().Set("Trailer", "grpc-status")
|
||||
rsp.Header().Set("Trailer", "grpc-message")
|
||||
rsp.Header().Set("grpc-status", "13")
|
||||
rsp.Header().Set("grpc-message", ce.Detail)
|
||||
}
|
||||
|
||||
_, werr := w.Write([]byte(ce.Error()))
|
||||
_, werr := rsp.Write([]byte(ce.Error()))
|
||||
|
||||
return werr
|
||||
}
|
||||
|
||||
@@ -515,11 +550,14 @@ func writeResponse(w http.ResponseWriter, r *http.Request, rsp []byte) error {
|
||||
|
||||
// write response
|
||||
_, err := w.Write(rsp)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewHandler returns a new RPC handler.
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
options := handler.NewOptions(opts...)
|
||||
|
||||
return &rpcHandler{
|
||||
opts: options,
|
||||
}
|
||||
|
||||
+35
-23
@@ -12,41 +12,41 @@ import (
|
||||
"github.com/gobwas/httphead"
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
|
||||
"go-micro.dev/v4/api/router"
|
||||
"go-micro.dev/v4/client"
|
||||
raw "go-micro.dev/v4/codec/bytes"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
// serveWebsocket will stream rpc back over websockets assuming json
|
||||
// serveWebsocket will stream rpc back over websockets assuming json.
|
||||
func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request, service *router.Route, c client.Client) (err error) {
|
||||
var op ws.OpCode
|
||||
var opCode ws.OpCode
|
||||
|
||||
ct := r.Header.Get("Content-Type")
|
||||
myCt := r.Header.Get("Content-Type")
|
||||
// Strip charset from Content-Type (like `application/json; charset=UTF-8`)
|
||||
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||
ct = ct[:idx]
|
||||
if idx := strings.IndexRune(myCt, ';'); idx >= 0 {
|
||||
myCt = myCt[:idx]
|
||||
}
|
||||
|
||||
// check proto from request
|
||||
switch ct {
|
||||
switch myCt {
|
||||
case "application/json":
|
||||
op = ws.OpText
|
||||
opCode = ws.OpText
|
||||
default:
|
||||
op = ws.OpBinary
|
||||
opCode = ws.OpBinary
|
||||
}
|
||||
|
||||
hdr := make(http.Header)
|
||||
|
||||
if proto, ok := r.Header["Sec-Websocket-Protocol"]; ok {
|
||||
for _, p := range proto {
|
||||
switch p {
|
||||
case "binary":
|
||||
if p == "binary" {
|
||||
hdr["Sec-WebSocket-Protocol"] = []string{"binary"}
|
||||
op = ws.OpBinary
|
||||
opCode = ws.OpBinary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
payload, err := requestPayload(r)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -67,7 +67,7 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
Header: hdr,
|
||||
}
|
||||
|
||||
conn, rw, _, err := upgrader.Upgrade(r, w)
|
||||
conn, uRw, _, err := upgrader.Upgrade(r, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -79,8 +79,9 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
}()
|
||||
|
||||
var request interface{}
|
||||
|
||||
if !bytes.Equal(payload, []byte(`{}`)) {
|
||||
switch ct {
|
||||
switch myCt {
|
||||
case "application/json", "":
|
||||
m := json.RawMessage(payload)
|
||||
request = &m
|
||||
@@ -90,20 +91,25 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
}
|
||||
|
||||
// we always need to set content type for message
|
||||
if ct == "" {
|
||||
ct = "application/json"
|
||||
if myCt == "" {
|
||||
myCt = "application/json"
|
||||
}
|
||||
|
||||
req := c.NewRequest(
|
||||
service.Service,
|
||||
service.Endpoint.Name,
|
||||
request,
|
||||
client.WithContentType(ct),
|
||||
client.WithContentType(myCt),
|
||||
client.StreamingRequest(),
|
||||
)
|
||||
|
||||
cCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
so := selector.WithStrategy(strategy(service.Versions))
|
||||
|
||||
// create a new stream
|
||||
stream, err := c.Stream(ctx, req, client.WithSelectOption(so))
|
||||
stream, err := c.Stream(cCtx, req, client.WithSelectOption(so))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -115,7 +121,7 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if wErr := writeLoop(rw, stream); wErr != nil && err == nil {
|
||||
if wErr := writeLoop(uRw, stream); wErr != nil && err == nil {
|
||||
err = wErr
|
||||
}
|
||||
}()
|
||||
@@ -137,21 +143,23 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
if strings.Contains(err.Error(), "context canceled") {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// write the response
|
||||
if err = wsutil.WriteServerMessage(rw, op, buf); err != nil {
|
||||
if err = wsutil.WriteServerMessage(uRw, opCode, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = rw.Flush(); err != nil {
|
||||
|
||||
if err = uRw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeLoop
|
||||
// writeLoop.
|
||||
func writeLoop(rw io.ReadWriter, stream client.Stream) error {
|
||||
// close stream when done
|
||||
defer stream.Close()
|
||||
@@ -171,10 +179,12 @@ func writeLoop(rw io.ReadWriter, stream client.Stream) error {
|
||||
case ws.StatusNormalClosure, ws.StatusNoStatusRcvd:
|
||||
// this happens when user close ws connection, or we don't get any status
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
switch op {
|
||||
default:
|
||||
// not relevant
|
||||
@@ -211,6 +221,7 @@ func isStream(r *http.Request, srv *router.Route) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -222,6 +233,7 @@ func isWebSocket(r *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -2,6 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/api/router"
|
||||
registry2 "go-micro.dev/v4/api/router/registry"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func NewOptions(opts ...Option) Options {
|
||||
@@ -16,10 +19,19 @@ func NewOptions(opts ...Option) Options {
|
||||
return options
|
||||
}
|
||||
|
||||
// WithRouter sets the router to use e.g static or registry
|
||||
// WithRouter sets the router to use e.g static or registry.
|
||||
func WithRouter(r router.Router) Option {
|
||||
return func(o *Options) error {
|
||||
o.Router = r
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRegistry sets the api's client and router to use registry.
|
||||
func WithRegistry(r registry.Registry) Option {
|
||||
return func(o *Options) error {
|
||||
o.Client = client.NewClient(client.Registry(r))
|
||||
o.Router = registry2.NewRouter(router.WithRegistry(r))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// NewOptions returns new initialised options
|
||||
// NewOptions wires options together.
|
||||
func NewOptions(opts ...Option) Options {
|
||||
var options Options
|
||||
for _, o := range opts {
|
||||
@@ -18,14 +18,14 @@ func NewOptions(opts ...Option) Options {
|
||||
return options
|
||||
}
|
||||
|
||||
// WithHandler sets the handler being used
|
||||
// WithHandler sets the handler being used.
|
||||
func WithHandler(h string) Option {
|
||||
return func(o *Options) {
|
||||
o.Handler = h
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace sets the function which determines the namespace for a request
|
||||
// WithNamespace sets the function which determines the namespace for a request.
|
||||
func WithNamespace(n func(*http.Request) string) Option {
|
||||
return func(o *Options) {
|
||||
o.Namespace = n
|
||||
|
||||
+6
-4
@@ -11,13 +11,13 @@ var (
|
||||
ErrInvalidPath = errors.New("invalid path")
|
||||
)
|
||||
|
||||
// Resolver resolves requests to endpoints
|
||||
// Resolver resolves requests to endpoints.
|
||||
type Resolver interface {
|
||||
Resolve(r *http.Request) (*Endpoint, error)
|
||||
String() string
|
||||
}
|
||||
|
||||
// Endpoint is the endpoint for a http request
|
||||
// Endpoint is the endpoint for a http request.
|
||||
type Endpoint struct {
|
||||
// e.g greeter
|
||||
Name string
|
||||
@@ -29,14 +29,16 @@ type Endpoint struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
// Options is a struct of available options.
|
||||
type Options struct {
|
||||
Handler string
|
||||
Namespace func(*http.Request) string
|
||||
Handler string
|
||||
}
|
||||
|
||||
// Option is a helper for a single option.
|
||||
type Option func(o *Options)
|
||||
|
||||
// StaticNamespace returns the same namespace for each request
|
||||
// StaticNamespace returns the same namespace for each request.
|
||||
func StaticNamespace(ns string) func(*http.Request) string {
|
||||
return func(*http.Request) string {
|
||||
return ns
|
||||
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
// Package vpath resolves using http path and recognised versioned urls
|
||||
// Package vpath resolves using http path and recognized versioned urls
|
||||
package vpath
|
||||
|
||||
import (
|
||||
@@ -10,10 +10,12 @@ import (
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
)
|
||||
|
||||
// NewResolver returns a new vpath resolver.
|
||||
func NewResolver(opts ...resolver.Option) resolver.Resolver {
|
||||
return &Resolver{opts: resolver.NewOptions(opts...)}
|
||||
}
|
||||
|
||||
// Resolver is a vpath resolver.
|
||||
type Resolver struct {
|
||||
opts resolver.Options
|
||||
}
|
||||
@@ -22,6 +24,7 @@ var (
|
||||
re = regexp.MustCompile("^v[0-9]+$")
|
||||
)
|
||||
|
||||
// Resolve resolves a http.Request to an grpc Endpoint.
|
||||
func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
||||
if req.URL.Path == "/" {
|
||||
return nil, errors.New("unknown name")
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ func slice(s string) []string {
|
||||
return sl
|
||||
}
|
||||
|
||||
// Encode encodes an endpoint to endpoint metadata
|
||||
// Encode encodes an endpoint to endpoint metadata.
|
||||
func Encode(e *Endpoint) map[string]string {
|
||||
if e == nil {
|
||||
return nil
|
||||
@@ -49,7 +49,7 @@ func Encode(e *Endpoint) map[string]string {
|
||||
return ep
|
||||
}
|
||||
|
||||
// Decode decodes endpoint metadata into an endpoint
|
||||
// Decode decodes endpoint metadata into an endpoint.
|
||||
func Decode(e map[string]string) *Endpoint {
|
||||
if e == nil {
|
||||
return nil
|
||||
@@ -65,7 +65,7 @@ func Decode(e map[string]string) *Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates an endpoint to guarantee it won't blow up when being served
|
||||
// Validate validates an endpoint to guarantee it won't blow up when being served.
|
||||
func Validate(e *Endpoint) error {
|
||||
if e == nil {
|
||||
return errors.New("endpoint is nil")
|
||||
|
||||
+5
-2
@@ -7,15 +7,18 @@ import (
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
// Options is a struct of options available.
|
||||
type Options struct {
|
||||
Handler string
|
||||
Registry registry.Registry
|
||||
Resolver resolver.Resolver
|
||||
Logger logger.Logger
|
||||
Handler string
|
||||
}
|
||||
|
||||
// Option is a helper for a single options.
|
||||
type Option func(o *Options)
|
||||
|
||||
// NewOptions wires options together.
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Handler: "meta",
|
||||
@@ -54,7 +57,7 @@ func WithResolver(r resolver.Resolver) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger sets the underline logger
|
||||
// WithLogger sets the underline logger.
|
||||
func WithLogger(l logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
|
||||
+62
-21
@@ -18,25 +18,26 @@ import (
|
||||
"go-micro.dev/v4/registry/cache"
|
||||
)
|
||||
|
||||
// endpoint struct, that holds compiled pcre
|
||||
// endpoint struct, that holds compiled pcre.
|
||||
type endpoint struct {
|
||||
hostregs []*regexp.Regexp
|
||||
pathregs []util.Pattern
|
||||
pcreregs []*regexp.Regexp
|
||||
}
|
||||
|
||||
// router is the default router
|
||||
// router is the default router.
|
||||
type registryRouter struct {
|
||||
exit chan bool
|
||||
opts router.Options
|
||||
|
||||
// registry cache
|
||||
rc cache.Cache
|
||||
|
||||
sync.RWMutex
|
||||
eps map[string]*router.Route
|
||||
exit chan bool
|
||||
eps map[string]*router.Route
|
||||
// compiled regexp for host and path
|
||||
ceps map[string]*endpoint
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (r *registryRouter) isStopped() bool {
|
||||
@@ -48,17 +49,20 @@ func (r *registryRouter) isStopped() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// refresh list of api services
|
||||
// refresh list of api services.
|
||||
func (r *registryRouter) refresh() {
|
||||
var attempts int
|
||||
|
||||
logger := r.Options().Logger
|
||||
|
||||
for {
|
||||
services, err := r.opts.Registry.ListServices()
|
||||
if err != nil {
|
||||
attempts++
|
||||
|
||||
logger.Logf(log.ErrorLevel, "unable to list services: %v", err)
|
||||
time.Sleep(time.Duration(attempts) * time.Second)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -71,6 +75,7 @@ func (r *registryRouter) refresh() {
|
||||
logger.Logf(log.ErrorLevel, "unable to get service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
r.store(service)
|
||||
}
|
||||
|
||||
@@ -84,7 +89,7 @@ func (r *registryRouter) refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
// process watch event
|
||||
// process watch event.
|
||||
func (r *registryRouter) process(res *registry.Result) {
|
||||
logger := r.Options().Logger
|
||||
// skip these things
|
||||
@@ -103,7 +108,7 @@ func (r *registryRouter) process(res *registry.Result) {
|
||||
r.store(service)
|
||||
}
|
||||
|
||||
// store local endpoint cache
|
||||
// store local endpoint cache.
|
||||
func (r *registryRouter) store(services []*registry.Service) {
|
||||
logger := r.Options().Logger
|
||||
// endpoints
|
||||
@@ -169,11 +174,13 @@ func (r *registryRouter) store(services []*registry.Service) {
|
||||
if h == "" || h == "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
hostreg, err := regexp.CompilePOSIX(h)
|
||||
if err != nil {
|
||||
logger.Logf(log.TraceLevel, "endpoint have invalid host regexp: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
cep.hostregs = append(cep.hostregs, hostreg)
|
||||
}
|
||||
|
||||
@@ -197,11 +204,13 @@ func (r *registryRouter) store(services []*registry.Service) {
|
||||
}
|
||||
|
||||
tpl := rule.Compile()
|
||||
|
||||
pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "", util.PatternLogger(logger))
|
||||
if err != nil {
|
||||
logger.Logf(log.TraceLevel, "endpoint have invalid path pattern: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
cep.pathregs = append(cep.pathregs, pathreg)
|
||||
}
|
||||
|
||||
@@ -209,9 +218,10 @@ func (r *registryRouter) store(services []*registry.Service) {
|
||||
}
|
||||
}
|
||||
|
||||
// watch for endpoint changes
|
||||
// watch for endpoint changes.
|
||||
func (r *registryRouter) watch() {
|
||||
var attempts int
|
||||
|
||||
logger := r.Options().Logger
|
||||
|
||||
for {
|
||||
@@ -223,8 +233,10 @@ func (r *registryRouter) watch() {
|
||||
w, err := r.opts.Registry.Watch()
|
||||
if err != nil {
|
||||
attempts++
|
||||
|
||||
logger.Logf(log.ErrorLevel, "error watching endpoints: %v", err)
|
||||
time.Sleep(time.Duration(attempts) * time.Second)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -248,8 +260,10 @@ func (r *registryRouter) watch() {
|
||||
if err != nil {
|
||||
logger.Logf(log.ErrorLevel, "error getting next endoint: %v", err)
|
||||
close(ch)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
r.process(res)
|
||||
}
|
||||
}
|
||||
@@ -267,6 +281,7 @@ func (r *registryRouter) Stop() error {
|
||||
close(r.exit)
|
||||
r.rc.Stop()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -280,6 +295,7 @@ func (r *registryRouter) Deregister(ep *router.Route) error {
|
||||
|
||||
func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
logger := r.Options().Logger
|
||||
|
||||
if r.isStopped() {
|
||||
return nil, errors.New("router closed")
|
||||
}
|
||||
@@ -291,16 +307,19 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
if len(req.URL.Path) > 0 && req.URL.Path != "/" {
|
||||
idx = 1
|
||||
}
|
||||
|
||||
path := strings.Split(req.URL.Path[idx:], "/")
|
||||
|
||||
// use the first match
|
||||
// TODO: weighted matching
|
||||
for n, e := range r.eps {
|
||||
for n, endpoint := range r.eps {
|
||||
cep, ok := r.ceps[n]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ep := e.Endpoint
|
||||
|
||||
ep := endpoint.Endpoint
|
||||
|
||||
var mMatch, hMatch, pMatch bool
|
||||
// 1. try method
|
||||
for _, m := range ep.Method {
|
||||
@@ -309,6 +328,7 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !mMatch {
|
||||
continue
|
||||
}
|
||||
@@ -323,14 +343,13 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
if h == "" || h == "*" {
|
||||
hMatch = true
|
||||
break
|
||||
} else {
|
||||
if cep.hostregs[idx].MatchString(req.URL.Host) {
|
||||
hMatch = true
|
||||
break
|
||||
}
|
||||
} else if cep.hostregs[idx].MatchString(req.URL.Host) {
|
||||
hMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hMatch {
|
||||
continue
|
||||
}
|
||||
@@ -344,17 +363,23 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
logger.Logf(log.DebugLevel, "api gpath not match %s != %v", path, pathreg)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Logf(log.DebugLevel, "api gpath match %s = %v", path, pathreg)
|
||||
|
||||
pMatch = true
|
||||
ctx := req.Context()
|
||||
|
||||
md, ok := metadata.FromContext(ctx)
|
||||
if !ok {
|
||||
md = make(metadata.Metadata)
|
||||
}
|
||||
|
||||
for k, v := range matches {
|
||||
md[fmt.Sprintf("x-api-field-%s", k)] = v
|
||||
}
|
||||
|
||||
*req = *req.Clone(metadata.NewContext(ctx, md))
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -365,8 +390,11 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
logger.Logf(log.DebugLevel, "api pcre path not match %s != %v", path, pathreg)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Logf(log.DebugLevel, "api pcre path match %s != %v", path, pathreg)
|
||||
|
||||
pMatch = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -377,7 +405,7 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
|
||||
|
||||
// TODO: Percentage traffic
|
||||
// we got here, so its a match
|
||||
return e, nil
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// no match
|
||||
@@ -400,13 +428,13 @@ func (r *registryRouter) Route(req *http.Request) (*router.Route, error) {
|
||||
// TODO: don't ignore that shit
|
||||
|
||||
// get the service name
|
||||
rp, err := r.opts.Resolver.Resolve(req)
|
||||
rsp, err := r.opts.Resolver.Resolve(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// service name
|
||||
name := rp.Name
|
||||
name := rsp.Name
|
||||
|
||||
// get service
|
||||
services, err := r.rc.GetService(name)
|
||||
@@ -425,11 +453,22 @@ func (r *registryRouter) Route(req *http.Request) (*router.Route, error) {
|
||||
handler = "rpc"
|
||||
}
|
||||
|
||||
// extract endpoint from Path, case-sensitive
|
||||
// just test it in this case, maybe should put the code somewhere else
|
||||
ep_name := rsp.Method
|
||||
comps := strings.Split(rsp.Path, "/")
|
||||
switch len(comps) {
|
||||
case 3:
|
||||
ep_name = comps[1] + "." + comps[2]
|
||||
case 4:
|
||||
ep_name = comps[2] + "." + comps[3]
|
||||
}
|
||||
|
||||
// construct api service
|
||||
return &router.Route{
|
||||
Service: name,
|
||||
Endpoint: &router.Endpoint{
|
||||
Name: rp.Method,
|
||||
Name: ep_name,
|
||||
Handler: handler,
|
||||
},
|
||||
Versions: services,
|
||||
@@ -462,12 +501,14 @@ func newRouter(opts ...router.Option) *registryRouter {
|
||||
eps: make(map[string]*router.Route),
|
||||
ceps: make(map[string]*endpoint),
|
||||
}
|
||||
|
||||
go r.watch()
|
||||
go r.refresh()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// NewRouter returns the default router
|
||||
// NewRouter returns the default router.
|
||||
func NewRouter(opts ...router.Option) router.Router {
|
||||
return newRouter(opts...)
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import (
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
// Router is used to determine an endpoint for a request
|
||||
// Router is used to determine an endpoint for a request.
|
||||
type Router interface {
|
||||
// Returns options
|
||||
Options() Options
|
||||
@@ -30,7 +30,7 @@ type Route struct {
|
||||
Versions []*registry.Service
|
||||
}
|
||||
|
||||
// Endpoint is a mapping between an RPC method and HTTP endpoint
|
||||
// Endpoint is a mapping between an RPC method and HTTP endpoint.
|
||||
type Endpoint struct {
|
||||
// RPC Method e.g. Greeter.Hello
|
||||
Name string
|
||||
|
||||
+16
-9
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/compile.go
|
||||
// download from
|
||||
// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/compile.go
|
||||
|
||||
const (
|
||||
opcodeVersion = 1
|
||||
@@ -8,18 +9,18 @@ const (
|
||||
|
||||
// Template is a compiled representation of path templates.
|
||||
type Template struct {
|
||||
// Version is the version number of the format.
|
||||
Version int
|
||||
// Verb is a VERB part in the template.
|
||||
Verb string
|
||||
// Original template (example: /v1/a_bit_of_everything)
|
||||
Template string
|
||||
// OpCodes is a sequence of operations.
|
||||
OpCodes []int
|
||||
// Pool is a constant pool
|
||||
Pool []string
|
||||
// Verb is a VERB part in the template.
|
||||
Verb string
|
||||
// Fields is a list of field paths bound in this template.
|
||||
Fields []string
|
||||
// Original template (example: /v1/a_bit_of_everything)
|
||||
Template string
|
||||
// Version is the version number of the format.
|
||||
Version int
|
||||
}
|
||||
|
||||
// Compiler compiles utilities representation of path templates into marshallable operations.
|
||||
@@ -29,13 +30,14 @@ type Compiler interface {
|
||||
}
|
||||
|
||||
type op struct {
|
||||
// code is the opcode of the operation
|
||||
code OpCode
|
||||
|
||||
// str is a string operand of the code.
|
||||
// operand is ignored if str is not empty.
|
||||
str string
|
||||
|
||||
// code is the opcode of the operation
|
||||
code OpCode
|
||||
|
||||
// operand is a numeric operand of the code.
|
||||
operand int
|
||||
}
|
||||
@@ -66,6 +68,7 @@ func (v variable) compile() []op {
|
||||
for _, s := range v.segments {
|
||||
ops = append(ops, s.compile()...)
|
||||
}
|
||||
|
||||
ops = append(ops, op{
|
||||
code: OpConcatN,
|
||||
operand: len(v.segments),
|
||||
@@ -88,7 +91,9 @@ func (t template) Compile() Template {
|
||||
pool []string
|
||||
fields []string
|
||||
)
|
||||
|
||||
consts := make(map[string]int)
|
||||
|
||||
for _, op := range rawOps {
|
||||
ops = append(ops, int(op.code))
|
||||
if op.str == "" {
|
||||
@@ -100,10 +105,12 @@ func (t template) Compile() Template {
|
||||
}
|
||||
ops = append(ops, consts[op.str])
|
||||
}
|
||||
|
||||
if op.code == OpCapture {
|
||||
fields = append(fields, op.str)
|
||||
}
|
||||
}
|
||||
|
||||
return Template{
|
||||
Version: opcodeVersion,
|
||||
OpCodes: ops,
|
||||
|
||||
+42
-6
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/parse.go
|
||||
// download from
|
||||
// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/parse.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -19,14 +20,15 @@ func (e InvalidTemplateError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.msg, e.tmpl)
|
||||
}
|
||||
|
||||
// Parse parses the string representation of path template
|
||||
// Parse parses the string representation of path template.
|
||||
func Parse(tmpl string) (Compiler, error) {
|
||||
if !strings.HasPrefix(tmpl, "/") {
|
||||
return template{}, InvalidTemplateError{tmpl: tmpl, msg: "no leading /"}
|
||||
}
|
||||
tokens, verb := tokenize(tmpl[1:])
|
||||
|
||||
tokens, verb := tokenize(tmpl[1:])
|
||||
p := parser{tokens: tokens}
|
||||
|
||||
segs, err := p.topLevelSegments()
|
||||
if err != nil {
|
||||
return template{}, InvalidTemplateError{tmpl: tmpl, msg: err.Error()}
|
||||
@@ -52,8 +54,10 @@ func tokenize(path string) (tokens []string, verb string) {
|
||||
var (
|
||||
st = init
|
||||
)
|
||||
|
||||
for path != "" {
|
||||
var idx int
|
||||
|
||||
switch st {
|
||||
case init:
|
||||
idx = strings.IndexAny(path, "/{")
|
||||
@@ -62,10 +66,12 @@ func tokenize(path string) (tokens []string, verb string) {
|
||||
case nested:
|
||||
idx = strings.IndexAny(path, "/}")
|
||||
}
|
||||
|
||||
if idx < 0 {
|
||||
tokens = append(tokens, path)
|
||||
break
|
||||
}
|
||||
|
||||
switch r := path[idx]; r {
|
||||
case '/', '.':
|
||||
case '{':
|
||||
@@ -75,30 +81,35 @@ func tokenize(path string) (tokens []string, verb string) {
|
||||
case '}':
|
||||
st = init
|
||||
}
|
||||
|
||||
if idx == 0 {
|
||||
tokens = append(tokens, path[idx:idx+1])
|
||||
} else {
|
||||
tokens = append(tokens, path[:idx], path[idx:idx+1])
|
||||
}
|
||||
|
||||
path = path[idx+1:]
|
||||
}
|
||||
|
||||
l := len(tokens)
|
||||
t := tokens[l-1]
|
||||
|
||||
if idx := strings.LastIndex(t, ":"); idx == 0 {
|
||||
tokens, verb = tokens[:l-1], t[1:]
|
||||
} else if idx > 0 {
|
||||
tokens[l-1], verb = t[:idx], t[idx+1:]
|
||||
}
|
||||
|
||||
tokens = append(tokens, eof)
|
||||
|
||||
return tokens, verb
|
||||
}
|
||||
|
||||
// parser is a parser of the template syntax defined in github.com/googleapis/googleapis/google/api/http.proto.
|
||||
type parser struct {
|
||||
logger log.Logger
|
||||
tokens []string
|
||||
accepted []string
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// topLevelSegments is the target of this parser.
|
||||
@@ -111,17 +122,22 @@ func (p *parser) topLevelSegments() ([]segment, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Logf(log.DebugLevel, "accept segments: %q; %q", p.accepted, p.tokens)
|
||||
|
||||
if _, err := p.accept(typeEOF); err != nil {
|
||||
return nil, fmt.Errorf("unexpected token %q after segments %q", p.tokens[0], strings.Join(p.accepted, ""))
|
||||
}
|
||||
|
||||
logger.Logf(log.DebugLevel, "accept eof: %q; %q", p.accepted, p.tokens)
|
||||
|
||||
return segs, nil
|
||||
}
|
||||
|
||||
func (p *parser) segments() ([]segment, error) {
|
||||
logger := log.LoggerOrDefault(p.logger)
|
||||
s, err := p.segment()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -133,11 +149,14 @@ func (p *parser) segments() ([]segment, error) {
|
||||
if _, err := p.accept("/"); err != nil {
|
||||
return segs, nil
|
||||
}
|
||||
|
||||
s, err := p.segment()
|
||||
if err != nil {
|
||||
return segs, err
|
||||
}
|
||||
|
||||
segs = append(segs, s)
|
||||
|
||||
logger.Logf(log.DebugLevel, "accept segment: %q; %q", p.accepted, p.tokens)
|
||||
}
|
||||
}
|
||||
@@ -146,17 +165,20 @@ func (p *parser) segment() (segment, error) {
|
||||
if _, err := p.accept("*"); err == nil {
|
||||
return wildcard{}, nil
|
||||
}
|
||||
|
||||
if _, err := p.accept("**"); err == nil {
|
||||
return deepWildcard{}, nil
|
||||
}
|
||||
|
||||
if l, err := p.literal(); err == nil {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
v, err := p.variable()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("segment neither wildcards, literal or variable: %v", err)
|
||||
return nil, fmt.Errorf("segment neither wildcards, literal or variable: %w", err)
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
@@ -165,6 +187,7 @@ func (p *parser) literal() (segment, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return literal(lit), nil
|
||||
}
|
||||
|
||||
@@ -182,7 +205,7 @@ func (p *parser) variable() (segment, error) {
|
||||
if _, err := p.accept("="); err == nil {
|
||||
segs, err = p.segments()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid segment in variable %q: %v", path, err)
|
||||
return nil, fmt.Errorf("invalid segment in variable %q: %w", path, err)
|
||||
}
|
||||
} else {
|
||||
segs = []segment{wildcard{}}
|
||||
@@ -191,6 +214,7 @@ func (p *parser) variable() (segment, error) {
|
||||
if _, err := p.accept("}"); err != nil {
|
||||
return nil, fmt.Errorf("unterminated variable segment: %s", path)
|
||||
}
|
||||
|
||||
return variable{
|
||||
path: path,
|
||||
segments: segs,
|
||||
@@ -202,7 +226,9 @@ func (p *parser) fieldPath() (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
components := []string{c}
|
||||
|
||||
for {
|
||||
if _, err = p.accept("."); err != nil {
|
||||
return strings.Join(components, "."), nil
|
||||
@@ -238,6 +264,7 @@ const (
|
||||
// If it doesn't match, the function does not consume any tokens and return an error.
|
||||
func (p *parser) accept(term termType) (string, error) {
|
||||
t := p.tokens[0]
|
||||
|
||||
switch term {
|
||||
case "/", "*", "**", ".", "=", "{", "}":
|
||||
if t != string(term) && t != "/" {
|
||||
@@ -258,8 +285,10 @@ func (p *parser) accept(term termType) (string, error) {
|
||||
default:
|
||||
return "", fmt.Errorf("unknown termType %q", term)
|
||||
}
|
||||
|
||||
p.tokens = p.tokens[1:]
|
||||
p.accepted = append(p.accepted, t)
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
@@ -278,6 +307,7 @@ func expectPChars(t string) error {
|
||||
pct1
|
||||
pct2
|
||||
)
|
||||
|
||||
st := init
|
||||
for _, r := range t {
|
||||
if st != init {
|
||||
@@ -316,9 +346,11 @@ func expectPChars(t string) error {
|
||||
return fmt.Errorf("invalid character in path segment: %q(%U)", r, r)
|
||||
}
|
||||
}
|
||||
|
||||
if st != init {
|
||||
return fmt.Errorf("invalid percent-encoding in %q", t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -327,12 +359,14 @@ func expectIdent(ident string) error {
|
||||
if ident == "" {
|
||||
return fmt.Errorf("empty identifier")
|
||||
}
|
||||
|
||||
for pos, r := range ident {
|
||||
switch {
|
||||
case '0' <= r && r <= '9':
|
||||
if pos == 0 {
|
||||
return fmt.Errorf("identifier starting with digit: %s", ident)
|
||||
}
|
||||
|
||||
continue
|
||||
case 'A' <= r && r <= 'Z':
|
||||
continue
|
||||
@@ -344,6 +378,7 @@ func expectIdent(ident string) error {
|
||||
return fmt.Errorf("invalid character %q(%U) in identifier: %s", r, r, ident)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -356,5 +391,6 @@ func isHexDigit(r rune) bool {
|
||||
case 'a' <= r && r <= 'f':
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,17 +7,17 @@ type OpCode int
|
||||
|
||||
// These constants are the valid values of OpCode.
|
||||
const (
|
||||
// OpNop does nothing
|
||||
// OpNop does nothing.
|
||||
OpNop = OpCode(iota)
|
||||
// OpPush pushes a component to stack
|
||||
// OpPush pushes a component to stack.
|
||||
OpPush
|
||||
// OpLitPush pushes a component to stack if it matches to the literal
|
||||
// OpLitPush pushes a component to stack if it matches to the literal.
|
||||
OpLitPush
|
||||
// OpPushM concatenates the remaining components and pushes it to stack
|
||||
// OpPushM concatenates the remaining components and pushes it to stack.
|
||||
OpPushM
|
||||
// OpConcatN pops N items from stack, concatenates them and pushes it back to stack
|
||||
// OpConcatN pops N items from stack, concatenates them and pushes it back to stack.
|
||||
OpConcatN
|
||||
// OpCapture pops an item and binds it to the variable
|
||||
// OpCapture pops an item and binds it to the variable.
|
||||
OpCapture
|
||||
// OpEnd is the least positive invalid opcode.
|
||||
OpEnd
|
||||
|
||||
+13
-4
@@ -24,6 +24,8 @@ type rop struct {
|
||||
|
||||
// Pattern is a template pattern of http request paths defined in github.com/googleapis/googleapis/google/api/http.proto.
|
||||
type Pattern struct {
|
||||
// verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part.
|
||||
verb string
|
||||
// ops is a list of operations
|
||||
ops []rop
|
||||
// pool is a constant pool indexed by the operands or vars.
|
||||
@@ -34,22 +36,20 @@ type Pattern struct {
|
||||
stacksize int
|
||||
// tailLen is the length of the fixed-size segments after a deep wildcard
|
||||
tailLen int
|
||||
// verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part.
|
||||
verb string
|
||||
// assumeColonVerb indicates whether a path suffix after a final
|
||||
// colon may only be interpreted as a verb.
|
||||
assumeColonVerb bool
|
||||
}
|
||||
|
||||
type patternOptions struct {
|
||||
assumeColonVerb bool
|
||||
logger log.Logger
|
||||
assumeColonVerb bool
|
||||
}
|
||||
|
||||
// PatternOpt is an option for creating Patterns.
|
||||
type PatternOpt func(*patternOptions)
|
||||
|
||||
// Logger sets the logger
|
||||
// PatternLogger sets the logger.
|
||||
func PatternLogger(l log.Logger) PatternOpt {
|
||||
return func(po *patternOptions) {
|
||||
po.logger = l
|
||||
@@ -89,8 +89,10 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
pushMSeen bool
|
||||
vars []string
|
||||
)
|
||||
|
||||
for i := 0; i < l; i += 2 {
|
||||
op := rop{code: OpCode(ops[i]), operand: ops[i+1]}
|
||||
|
||||
switch op.code {
|
||||
case OpNop:
|
||||
continue
|
||||
@@ -104,6 +106,7 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
logger.Logf(log.DebugLevel, "pushM appears twice")
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
pushMSeen = true
|
||||
stack++
|
||||
case OpLitPush:
|
||||
@@ -111,6 +114,7 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
logger.Logf(log.DebugLevel, "negative literal index: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
if pushMSeen {
|
||||
tailLen++
|
||||
}
|
||||
@@ -120,6 +124,7 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
logger.Logf(log.DebugLevel, "negative concat size: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
stack -= op.operand
|
||||
if stack < 0 {
|
||||
logger.Logf(log.DebugLevel, "stack underflow")
|
||||
@@ -131,10 +136,12 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
logger.Logf(log.DebugLevel, "variable name index out of bound: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
v := pool[op.operand]
|
||||
op.operand = len(vars)
|
||||
vars = append(vars, v)
|
||||
stack--
|
||||
|
||||
if stack < 0 {
|
||||
logger.Logf(log.DebugLevel, "stack underflow")
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
@@ -147,8 +154,10 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
|
||||
if maxstack < stack {
|
||||
maxstack = stack
|
||||
}
|
||||
|
||||
typedOps = append(typedOps, op)
|
||||
}
|
||||
|
||||
return Pattern{
|
||||
ops: typedOps,
|
||||
pool: pool,
|
||||
|
||||
+6
-2
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/types.go
|
||||
// download from
|
||||
// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/types.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -8,9 +9,9 @@ import (
|
||||
)
|
||||
|
||||
type template struct {
|
||||
segments []segment
|
||||
verb string
|
||||
template string
|
||||
segments []segment
|
||||
}
|
||||
|
||||
type segment interface {
|
||||
@@ -46,6 +47,7 @@ func (v variable) String() string {
|
||||
for _, s := range v.segments {
|
||||
segs = append(segs, s.String())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("{%s=%s}", v.path, strings.Join(segs, "/"))
|
||||
}
|
||||
|
||||
@@ -54,9 +56,11 @@ func (t template) String() string {
|
||||
for _, s := range t.segments {
|
||||
segs = append(segs, s.String())
|
||||
}
|
||||
|
||||
str := strings.Join(segs, "/")
|
||||
if t.verb != "" {
|
||||
str = fmt.Sprintf("%s:%s", str, t.verb)
|
||||
}
|
||||
|
||||
return "/" + str
|
||||
}
|
||||
|
||||
+3
-3
@@ -9,11 +9,11 @@ import (
|
||||
|
||||
var (
|
||||
// ErrProviderNotImplemented can be returned when attempting to
|
||||
// instantiate an unimplemented provider
|
||||
// instantiate an unimplemented provider.
|
||||
ErrProviderNotImplemented = errors.New("Provider not implemented")
|
||||
)
|
||||
|
||||
// Provider is a ACME provider interface
|
||||
// Provider is a ACME provider interface.
|
||||
type Provider interface {
|
||||
// Listen returns a new listener
|
||||
Listen(...string) (net.Listener, error)
|
||||
@@ -21,7 +21,7 @@ type Provider interface {
|
||||
TLSConfig(...string) (*tls.Config, error)
|
||||
}
|
||||
|
||||
// The Let's Encrypt ACME endpoints
|
||||
// The Let's Encrypt ACME endpoints.
|
||||
const (
|
||||
LetsEncryptStagingCA = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
LetsEncryptProductionCA = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
|
||||
+14
-15
@@ -2,26 +2,17 @@ package acme
|
||||
|
||||
import (
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
// Option (or Options) are passed to New() to configure providers
|
||||
// Option (or Options) are passed to New() to configure providers.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options represents various options you can present to ACME providers
|
||||
// Options represents various options you can present to ACME providers.
|
||||
type Options struct {
|
||||
// AcceptTLS must be set to true to indicate that you have read your
|
||||
// provider's terms of service.
|
||||
AcceptToS bool
|
||||
// CA is the CA to use
|
||||
CA string
|
||||
// ChallengeProvider is a go-acme/lego challenge provider. Set this if you
|
||||
// want to use DNS Challenges. Otherwise, tls-alpn-01 will be used
|
||||
ChallengeProvider challenge.Provider
|
||||
// Issue certificates for domains on demand. Otherwise, certs will be
|
||||
// retrieved / issued on start-up.
|
||||
OnDemand bool
|
||||
// Cache is a storage interface. Most ACME libraries have an cache, but
|
||||
// there's no defined interface, so if you consume this option
|
||||
// sanity check it before using.
|
||||
@@ -29,16 +20,24 @@ type Options struct {
|
||||
|
||||
// Logger is the underling logging framework
|
||||
Logger logger.Logger
|
||||
// CA is the CA to use
|
||||
CA string
|
||||
// AcceptTLS must be set to true to indicate that you have read your
|
||||
// provider's terms of service.
|
||||
AcceptToS bool
|
||||
// Issue certificates for domains on demand. Otherwise, certs will be
|
||||
// retrieved / issued on start-up.
|
||||
OnDemand bool
|
||||
}
|
||||
|
||||
// AcceptToS indicates whether you accept your CA's terms of service
|
||||
// AcceptToS indicates whether you accept your CA's terms of service.
|
||||
func AcceptToS(b bool) Option {
|
||||
return func(o *Options) {
|
||||
o.AcceptToS = b
|
||||
}
|
||||
}
|
||||
|
||||
// CA sets the CA of an acme.Options
|
||||
// CA sets the CA of an acme.Options.
|
||||
func CA(CA string) Option {
|
||||
return func(o *Options) {
|
||||
o.CA = CA
|
||||
@@ -63,14 +62,14 @@ func OnDemand(b bool) Option {
|
||||
|
||||
// Cache provides a cache / storage interface to the underlying ACME library
|
||||
// as there is no standard, this needs to be validated by the underlying
|
||||
// implentation.
|
||||
// implementation.
|
||||
func Cache(c interface{}) Option {
|
||||
return func(o *Options) {
|
||||
o.Cache = c
|
||||
}
|
||||
}
|
||||
|
||||
// Logger sets the underline logger
|
||||
// Logger sets the underline logger.
|
||||
func Logger(l logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
|
||||
+4
-4
@@ -6,12 +6,12 @@ import (
|
||||
|
||||
type Config struct {
|
||||
AllowOrigin string
|
||||
AllowCredentials bool
|
||||
AllowMethods string
|
||||
AllowHeaders string
|
||||
AllowCredentials bool
|
||||
}
|
||||
|
||||
// CombinedCORSHandler wraps a server and provides CORS headers
|
||||
// CombinedCORSHandler wraps a server and provides CORS headers.
|
||||
func CombinedCORSHandler(h http.Handler, config *Config) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if config != nil {
|
||||
@@ -25,7 +25,7 @@ func CombinedCORSHandler(h http.Handler, config *Config) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// SetHeaders sets the CORS headers
|
||||
// SetHeaders sets the CORS headers.
|
||||
func SetHeaders(w http.ResponseWriter, _ *http.Request, config *Config) {
|
||||
set := func(w http.ResponseWriter, k, v string) {
|
||||
if v := w.Header().Get(k); len(v) > 0 {
|
||||
@@ -33,7 +33,7 @@ func SetHeaders(w http.ResponseWriter, _ *http.Request, config *Config) {
|
||||
}
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
//For forward-compatible code, default values may not be provided in the future
|
||||
// For forward-compatible code, default values may not be provided in the future
|
||||
if config.AllowCredentials {
|
||||
set(w, "Access-Control-Allow-Credentials", "true")
|
||||
} else {
|
||||
|
||||
+5
-5
@@ -9,19 +9,19 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
|
||||
"go-micro.dev/v4/api/server"
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
log "go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
mux *http.ServeMux
|
||||
opts server.Options
|
||||
|
||||
mtx sync.RWMutex
|
||||
address string
|
||||
mux *http.ServeMux
|
||||
exit chan chan error
|
||||
address string
|
||||
|
||||
mtx sync.RWMutex
|
||||
}
|
||||
|
||||
func NewServer(address string, opts ...server.Option) server.Server {
|
||||
@@ -94,7 +94,7 @@ func (s *httpServer) Start() error {
|
||||
go func() {
|
||||
if err := http.Serve(l, s.mux); err != nil {
|
||||
// temporary fix
|
||||
//logger.Log(log.FatalLevel, err)
|
||||
// logger.Log(log.FatalLevel, err)
|
||||
logger.Log(log.ErrorLevel, err)
|
||||
}
|
||||
}()
|
||||
|
||||
+10
-11
@@ -4,26 +4,25 @@ import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
"go-micro.dev/v4/logger"
|
||||
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
"go-micro.dev/v4/api/server/acme"
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
type Options struct {
|
||||
ACMEProvider acme.Provider
|
||||
Resolver resolver.Resolver
|
||||
Logger logger.Logger
|
||||
CORSConfig *cors.Config
|
||||
TLSConfig *tls.Config
|
||||
ACMEHosts []string
|
||||
Wrappers []Wrapper
|
||||
EnableACME bool
|
||||
EnableCORS bool
|
||||
CORSConfig *cors.Config
|
||||
ACMEProvider acme.Provider
|
||||
EnableTLS bool
|
||||
ACMEHosts []string
|
||||
TLSConfig *tls.Config
|
||||
Resolver resolver.Resolver
|
||||
Wrappers []Wrapper
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
type Wrapper func(h http.Handler) http.Handler
|
||||
@@ -94,7 +93,7 @@ func Resolver(r resolver.Resolver) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Logger sets the underline logging framework
|
||||
// Logger sets the underline logging framework.
|
||||
func Logger(l logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Server serves api requests
|
||||
// Server serves api requests.
|
||||
type Server interface {
|
||||
Address() string
|
||||
Init(opts ...Option) error
|
||||
|
||||
Reference in New Issue
Block a user