github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/api/resolver/subdomain/subdomain.go (about) 1 // Copyright 2020 Asim Aslam 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Original source: github.com/micro/go-micro/v3/api/resolver/subdomain/subdomain.go 16 17 // Package subdomain is a resolver which uses the subdomain to determine the domain to route to. It 18 // offloads the endpoint resolution to a child resolver which is provided in New. 19 package subdomain 20 21 import ( 22 "net" 23 "net/http" 24 "strings" 25 26 "github.com/tickoalcantara12/micro/v3/service/api/resolver" 27 "github.com/tickoalcantara12/micro/v3/service/logger" 28 "golang.org/x/net/publicsuffix" 29 ) 30 31 func NewResolver(parent resolver.Resolver, opts ...resolver.Option) resolver.Resolver { 32 options := resolver.NewOptions(opts...) 33 return &Resolver{options, parent} 34 } 35 36 type Resolver struct { 37 opts resolver.Options 38 resolver.Resolver 39 } 40 41 func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) { 42 if dom := r.Domain(req); len(dom) > 0 { 43 opts = append(opts, resolver.Domain(dom)) 44 } 45 46 return r.Resolver.Resolve(req, opts...) 47 } 48 49 func (r *Resolver) Domain(req *http.Request) string { 50 // determine the host, e.g. foobar.m3o.app 51 host := req.URL.Hostname() 52 if len(host) == 0 { 53 if h, _, err := net.SplitHostPort(req.Host); err == nil { 54 host = h // host does contain a port 55 } else if strings.Contains(err.Error(), "missing port in address") { 56 host = req.Host // host does not contain a port 57 } 58 } 59 60 // check for an ip address 61 if net.ParseIP(host) != nil { 62 return "" 63 } 64 65 // check for dev enviroment 66 if host == "localhost" || host == "127.0.0.1" { 67 return "" 68 } 69 70 // extract the top level domain plus one (e.g. 'myapp.com') 71 domain, err := publicsuffix.EffectiveTLDPlusOne(host) 72 if err != nil { 73 logger.Debugf("Unable to extract domain from %v", host) 74 return "" 75 } 76 77 // there was no subdomain 78 if host == domain { 79 return "" 80 } 81 82 // remove the domain from the host, leaving the subdomain, e.g. "staging.foo.myapp.com" => "staging.foo" 83 subdomain := strings.TrimSuffix(host, "."+domain) 84 85 // ignore the API subdomain 86 if subdomain == "api" { 87 return "" 88 } 89 90 // return the reversed subdomain as the namespace, e.g. "staging.foo" => "foo-staging" 91 comps := strings.Split(subdomain, ".") 92 for i := len(comps)/2 - 1; i >= 0; i-- { 93 opp := len(comps) - 1 - i 94 comps[i], comps[opp] = comps[opp], comps[i] 95 } 96 return strings.Join(comps, "-") 97 } 98 99 func (r *Resolver) String() string { 100 return "subdomain" 101 }