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  }