github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/proxy/definition.go (about)

     1  package proxy
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/asaskevich/govalidator"
    10  	"go.mongodb.org/mongo-driver/bson"
    11  	"go.mongodb.org/mongo-driver/bson/bsontype"
    12  
    13  	"github.com/hellofresh/janus/pkg/proxy/balancer"
    14  	"github.com/hellofresh/janus/pkg/router"
    15  )
    16  
    17  // Definition defines proxy rules for a route
    18  type Definition struct {
    19  	PreserveHost       bool               `bson:"preserve_host" json:"preserve_host" mapstructure:"preserve_host"`
    20  	ListenPath         string             `bson:"listen_path" json:"listen_path" mapstructure:"listen_path" valid:"required~proxy.listen_path is required,urlpath"`
    21  	Upstreams          *Upstreams         `bson:"upstreams" json:"upstreams" mapstructure:"upstreams"`
    22  	InsecureSkipVerify bool               `bson:"insecure_skip_verify" json:"insecure_skip_verify" mapstructure:"insecure_skip_verify"`
    23  	StripPath          bool               `bson:"strip_path" json:"strip_path" mapstructure:"strip_path"`
    24  	AppendPath         bool               `bson:"append_path" json:"append_path" mapstructure:"append_path"`
    25  	Methods            []string           `bson:"methods" json:"methods"`
    26  	Hosts              []string           `bson:"hosts" json:"hosts"`
    27  	ForwardingTimeouts ForwardingTimeouts `bson:"forwarding_timeouts" json:"forwarding_timeouts" mapstructure:"forwarding_timeouts"`
    28  }
    29  
    30  // RouterDefinition represents an API that you want to proxy with internal router routines
    31  type RouterDefinition struct {
    32  	*Definition
    33  	middleware []router.Constructor
    34  }
    35  
    36  // Upstreams represents a collection of targets where the requests will go to
    37  type Upstreams struct {
    38  	Balancing string  `bson:"balancing" json:"balancing"`
    39  	Targets   Targets `bson:"targets" json:"targets"`
    40  }
    41  
    42  // Target is an ip address/hostname with a port that identifies an instance of a backend service
    43  type Target struct {
    44  	Target string `bson:"target" json:"target" valid:"url,required"`
    45  	Weight int    `bson:"weight" json:"weight"`
    46  }
    47  
    48  // Targets is a set of target
    49  type Targets []*Target
    50  
    51  // Duration is the time.Duration that can be unmarshalled from JSON
    52  type Duration time.Duration
    53  
    54  // MarshalJSON implements marshalling from JSON
    55  func (d *Duration) MarshalJSON() ([]byte, error) {
    56  	s := (*time.Duration)(d).String()
    57  	s = strconv.Quote(s)
    58  
    59  	return []byte(s), nil
    60  }
    61  
    62  // UnmarshalJSON implements unmarshalling from JSON
    63  func (d *Duration) UnmarshalJSON(data []byte) (err error) {
    64  	s := string(data)
    65  	if s == "null" {
    66  		return
    67  	}
    68  
    69  	// if Unquote returns error - assume that string is not quoted at all
    70  	if sUnquoted, err := strconv.Unquote(s); err == nil {
    71  		s = sUnquoted
    72  	}
    73  
    74  	t, err := time.ParseDuration(s)
    75  	if err != nil {
    76  		return
    77  	}
    78  
    79  	*d = Duration(t)
    80  	return
    81  }
    82  
    83  // GetBSON implements marshalling to BSON
    84  func (d Duration) GetBSON() (interface{}, error) {
    85  	return time.Duration(d).String(), nil
    86  }
    87  
    88  // SetBSON implements unmarshalling from BSON
    89  func (d *Duration) SetBSON(raw bson.RawValue) error {
    90  	// took BSON string parsing logic from BSON decoder
    91  	if raw.Type != bsontype.String {
    92  		return fmt.Errorf("expected %q type, but got %q", bsontype.String.String(), raw.Type.String())
    93  	}
    94  
    95  	// l := d.readInt32()
    96  	b := raw.Value[0:4]
    97  	l := int32((uint32(b[0]) << 0) |
    98  		(uint32(b[1]) << 8) |
    99  		(uint32(b[2]) << 16) |
   100  		(uint32(b[3]) << 24))
   101  
   102  	// b := d.readBytes(l - 1)
   103  	b = raw.Value[4 : 4+l-1]
   104  
   105  	return d.UnmarshalJSON(b)
   106  }
   107  
   108  // ForwardingTimeouts contains timeout configurations for forwarding requests to the backend servers.
   109  type ForwardingTimeouts struct {
   110  	DialTimeout           Duration `bson:"dial_timeout" json:"dial_timeout"`
   111  	ResponseHeaderTimeout Duration `bson:"response_header_timeout" json:"response_header_timeout"`
   112  }
   113  
   114  // NewDefinition creates a new Proxy Definition with default values
   115  func NewDefinition() *Definition {
   116  	return &Definition{
   117  		Methods: []string{"GET"},
   118  		Hosts:   make([]string, 0),
   119  		Upstreams: &Upstreams{
   120  			Targets: make([]*Target, 0),
   121  		},
   122  	}
   123  }
   124  
   125  // NewRouterDefinition creates a new Proxy RouterDefinition from Proxy Definition
   126  func NewRouterDefinition(def *Definition) *RouterDefinition {
   127  	return &RouterDefinition{Definition: def}
   128  }
   129  
   130  // Middleware returns s.middleware (useful for tests).
   131  func (d *RouterDefinition) Middleware() []router.Constructor {
   132  	return d.middleware
   133  }
   134  
   135  // AddMiddleware adds a middleware to a site's middleware stack.
   136  func (d *RouterDefinition) AddMiddleware(m router.Constructor) {
   137  	d.middleware = append(d.middleware, m)
   138  }
   139  
   140  // Validate validates proxy data
   141  func (d *Definition) Validate() (bool, error) {
   142  	return govalidator.ValidateStruct(d)
   143  }
   144  
   145  // IsBalancerDefined checks if load balancer is defined
   146  func (d *Definition) IsBalancerDefined() bool {
   147  	return d.Upstreams != nil && d.Upstreams.Targets != nil && len(d.Upstreams.Targets) > 0
   148  }
   149  
   150  // ToBalancerTargets returns the balancer expected type
   151  func (t Targets) ToBalancerTargets() []*balancer.Target {
   152  	var balancerTargets []*balancer.Target
   153  	for _, t := range t {
   154  		balancerTargets = append(balancerTargets, &balancer.Target{
   155  			Target: t.Target,
   156  			Weight: t.Weight,
   157  		})
   158  	}
   159  
   160  	return balancerTargets
   161  }
   162  func init() {
   163  	// initializes custom validators
   164  	govalidator.CustomTypeTagMap.Set("urlpath", func(i interface{}, o interface{}) bool {
   165  		s, ok := i.(string)
   166  		if !ok {
   167  			return false
   168  		}
   169  
   170  		return strings.Index(s, "/") == 0
   171  	})
   172  }