blob: 370ec41c7795ffe113e026c843e7a8a3f185c722 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package model
import (
stdHttp "net/http"
"regexp"
)
import (
"github.com/pkg/errors"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/common/router/trie"
"github.com/apache/dubbo-go-pixiu/pkg/common/util/stringutil"
)
// Router struct
type (
Router struct {
ID string `yaml:"id" json:"id" mapstructure:"id"`
Match RouterMatch `yaml:"match" json:"match" mapstructure:"match"`
Route RouteAction `yaml:"route" json:"route" mapstructure:"route"`
}
// RouterMatch
RouterMatch struct {
Prefix string `yaml:"prefix" json:"prefix" mapstructure:"prefix"`
Path string `yaml:"path" json:"path" mapstructure:"path"`
// Regex string `yaml:"regex" json:"regex" mapstructure:"regex"` TODO: next version
Methods []string `yaml:"methods" json:"methods" mapstructure:"methods"`
// Headers []HeaderMatcher `yaml:"headers" json:"headers" mapstructure:"headers"`
// pathRE *regexp.Regexp
}
// RouteAction match route should do
RouteAction struct {
Cluster string `yaml:"cluster" json:"cluster" mapstructure:"cluster"`
ClusterNotFoundResponseCode int `yaml:"cluster_not_found_response_code" json:"cluster_not_found_response_code" mapstructure:"cluster_not_found_response_code"`
}
// RouteConfiguration
RouteConfiguration struct {
RouteTrie trie.Trie `yaml:"-" json:"-" mapstructure:"-"`
Routes []*Router `yaml:"routes" json:"routes" mapstructure:"routes"`
Dynamic bool `yaml:"dynamic" json:"dynamic" mapstructure:"dynamic"`
}
// Name header key, Value header value, Regex header value is regex
HeaderMatcher struct {
Name string `yaml:"name" json:"name" mapstructure:"name"`
Values []string `yaml:"values" json:"values" mapstructure:"values"`
Regex bool `yaml:"regex" json:"regex" mapstructure:"regex"`
valueRE *regexp.Regexp
}
)
func NewRouterMatchPrefix(name string) RouterMatch {
return RouterMatch{Prefix: "/" + name + "/"}
}
func (rc *RouteConfiguration) RouteByPathAndMethod(path, method string) (*RouteAction, error) {
if rc.RouteTrie.IsEmpty() {
return nil, errors.Errorf("router configuration is empty")
}
node, _, _ := rc.RouteTrie.Match(stringutil.GetTrieKey(method, path))
if node == nil {
return nil, errors.Errorf("route failed for %s,no rules matched.", stringutil.GetTrieKey(method, path))
}
if node.GetBizInfo() == nil {
return nil, errors.Errorf("info is nil.please check your configuration.")
}
ret := (node.GetBizInfo()).(RouteAction)
return &ret, nil
}
func (rc *RouteConfiguration) Route(req *stdHttp.Request) (*RouteAction, error) {
return rc.RouteByPathAndMethod(req.URL.Path, req.Method)
}