github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/clusters/proxy/proxy.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package proxy 19 20 import ( 21 "bytes" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/commons/bytex" 24 "github.com/aacfactory/fns/commons/signatures" 25 "github.com/aacfactory/fns/context" 26 "github.com/aacfactory/fns/services" 27 "github.com/aacfactory/fns/shareds" 28 "github.com/aacfactory/fns/transports" 29 "github.com/aacfactory/logs" 30 ) 31 32 var ( 33 handlerPathPrefix = []byte("/proxy") 34 contentType = []byte("application/json+proxy") 35 ) 36 37 var ( 38 ErrInvalidPath = errors.Warning("fns: invalid path") 39 ErrInvalidBody = errors.Warning("fns: invalid body") 40 ErrSignatureLost = errors.New(488, "***SIGNATURE LOST***", "X-Fns-Signature was required") 41 ErrSignatureUnverified = errors.New(458, "***SIGNATURE INVALID***", "X-Fns-Signature was invalid") 42 ) 43 44 func NewHandler(signature signatures.Signature, manager services.EndpointsManager, shared shareds.Shared) transports.MuxHandler { 45 return &Handler{ 46 log: nil, 47 signature: signature, 48 shared: NewSharedHandler(shared), 49 manager: NewManagerHandler(manager), 50 } 51 } 52 53 type Handler struct { 54 log logs.Logger 55 signature signatures.Signature 56 shared transports.Handler 57 manager transports.Handler 58 } 59 60 func (handler *Handler) Name() string { 61 return "development" 62 } 63 64 func (handler *Handler) Construct(options transports.MuxHandlerOptions) error { 65 handler.log = options.Log 66 return nil 67 } 68 69 func (handler *Handler) Match(_ context.Context, method []byte, path []byte, header transports.Header) bool { 70 ok := bytes.Equal(method, transports.MethodPost) && 71 bytes.Index(path, handlerPathPrefix) == 0 && 72 len(header.Get(transports.SignatureHeaderName)) != 0 && 73 bytes.Equal(header.Get(transports.ContentTypeHeaderName), contentType) 74 return ok 75 } 76 77 func (handler *Handler) Handle(w transports.ResponseWriter, r transports.Request) { 78 path := r.Path() 79 // sign 80 sign := r.Header().Get(transports.SignatureHeaderName) 81 if len(sign) == 0 { 82 w.Failed(ErrSignatureLost.WithMeta("path", bytex.ToString(path))) 83 return 84 } 85 body, bodyErr := r.Body() 86 if bodyErr != nil { 87 w.Failed(ErrInvalidBody.WithMeta("path", bytex.ToString(path))) 88 return 89 } 90 if !handler.signature.Verify(body, sign) { 91 w.Failed(ErrSignatureUnverified.WithMeta("path", bytex.ToString(path))) 92 return 93 } 94 // match 95 if bytes.Equal(path, managerHandlerPath) { 96 handler.manager.Handle(w, r) 97 } else if bytes.Equal(path, sharedHandlerPath) { 98 handler.shared.Handle(w, r) 99 } else { 100 w.Failed(ErrInvalidPath.WithMeta("path", bytex.ToString(path))) 101 } 102 }