Skip to content

Commit

Permalink
Package HTTP Client DNS Mapper:
Browse files Browse the repository at this point in the history
- rework DNS Mapper to be more efficient with pattern search dns
- fix bugs
- add unit test in BDD to validate package
- optimize code
  • Loading branch information
nabbar committed Feb 17, 2024
1 parent ae0a6b6 commit 1d18fbf
Show file tree
Hide file tree
Showing 9 changed files with 1,105 additions and 154 deletions.
50 changes: 44 additions & 6 deletions config/components/httpcli/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@ import (
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)

func (o *componentHttpClient) Add(endpoint string, ip string) {
func (o *componentHttpClient) Add(from string, to string) {
if d := o.getDNSMapper(); d != nil {
d.Add(endpoint, ip)
d.Add(from, to)
o.setDNSMapper(d)
}
}

func (o *componentHttpClient) Get(endpoint string) string {
func (o *componentHttpClient) Get(from string) string {
if d := o.getDNSMapper(); d != nil {
return d.Get(endpoint)
return d.Get(from)
}
return ""
}

func (o *componentHttpClient) Del(endpoint string) {
func (o *componentHttpClient) Del(from string) {
if d := o.getDNSMapper(); d != nil {
d.Del(endpoint)
d.Del(from)
o.setDNSMapper(d)
}
}
Expand Down Expand Up @@ -101,3 +101,41 @@ func (o *componentHttpClient) TimeCleaner(ctx context.Context, dur time.Duration
d.TimeCleaner(ctx, dur)
}
}

func (o *componentHttpClient) Len() int {
if d := o.getDNSMapper(); d != nil {
return d.Len()
}

return 0
}

func (o *componentHttpClient) Walk(f func(from string, to string) bool) {
if d := o.getDNSMapper(); d != nil {
d.Walk(f)
}
}

func (o *componentHttpClient) Clean(endpoint string) (host string, port string, err error) {
if d := o.getDNSMapper(); d != nil {
return d.Clean(endpoint)
}

return "", "", ErrorComponentNotInitialized.Error()
}

func (o *componentHttpClient) Search(endpoint string) (string, error) {
if d := o.getDNSMapper(); d != nil {
return d.Search(endpoint)
}

return "", ErrorComponentNotInitialized.Error()
}

func (o *componentHttpClient) SearchWithCache(endpoint string) (string, error) {
if d := o.getDNSMapper(); d != nil {
return d.SearchWithCache(endpoint)
}

return "", ErrorComponentNotInitialized.Error()
}
46 changes: 46 additions & 0 deletions httpcli/dns-mapper/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/

package dns_mapper

func (o *dmp) CacheHas(endpoint string) bool {
_, l := o.z.Load(endpoint)
return l
}

func (o *dmp) CacheGet(endpoint string) string {
if i, l := o.z.Load(endpoint); !l {
return ""
} else if v, k := i.(string); !k {
return ""
} else {
return v
}
}

func (o *dmp) CacheSet(endpoint, ip string) {
o.z.Store(endpoint, ip)
}
177 changes: 177 additions & 0 deletions httpcli/dns-mapper/collection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/

package dns_mapper

import (
"net"
"strings"
)

func (o *dmp) Len() int {
var i int
o.d.Range(func(key, value any) bool {
i++
return true
})
return i
}

func (o *dmp) Add(from, to string) {
if d := newPart(from); d == nil {
return
} else {
o.d.Store(d, to)
}
}

func (o *dmp) Get(endpoint string) string {
var (
h, p, _ = o.Clean(endpoint)
res string
)

if p != "" {
h = h + ":" + p
}

o.Walk(func(from, to string) bool {
if from == h {
res = to
return false
}

return true
})

return res
}

func (o *dmp) Del(endpoint string) {
var h, p, _ = o.Clean(endpoint)

if p != "" {
h = h + ":" + p
}

o.WalkDP(func(from *dp, to string) bool {
if from.String() == h {
o.d.Delete(from)
return false
}

return true
})
}

func (o *dmp) Walk(fct func(from, to string) bool) {
o.d.Range(func(key, value any) bool {
if d, l := key.(*dp); !l {
return true
} else if t, k := value.(string); !k {
return true
} else {
return fct(d.String(), t)
}
})
}

func (o *dmp) WalkDP(fct func(from *dp, to string) bool) {
o.d.Range(func(key, value any) bool {
if d, l := key.(*dp); !l {
return true
} else if t, k := value.(string); !k {
return true
} else {
return fct(d, t)
}
})
}

func (o *dmp) Clean(endpoint string) (host string, port string, err error) {
host, port, err = net.SplitHostPort(endpoint)

if err != nil {
return strings.TrimSpace(endpoint), "", err
}

return strings.TrimSpace(host), strings.TrimPrefix(strings.TrimSpace(port), "0"), nil
}

func (o *dmp) Search(endpoint string) (string, error) {
var (
h, p, e = o.Clean(endpoint)
src *dp
res string
)

if e != nil {
return "", e
} else if src = newPartDetail(h, p); src == nil {
return endpoint, nil
}

o.WalkDP(func(from *dp, to string) bool {
if from.FQDNMatch(src.FQDNRaw()) {
if from.PortMatch(src.Port()) {
res = to

if _, _, e = net.SplitHostPort(to); e != nil {
res += ":" + src.Port()
}

return false
}
}

return true
})

return res, nil
}

func (o *dmp) SearchWithCache(endpoint string) (string, error) {
var (
e error
d string
)

if o.CacheHas(endpoint) {
if d = o.CacheGet(endpoint); len(d) > 0 {
return d, nil
}
}

if d, e = o.Search(endpoint); e != nil {
return "", e
} else if len(d) > 0 {
o.CacheSet(endpoint, d)
return d, nil
} else {
o.CacheSet(endpoint, endpoint)
return endpoint, nil
}
}
87 changes: 87 additions & 0 deletions httpcli/dns-mapper/dns_mapper_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

package dns_mapper_test

import (
"context"
"errors"
"fmt"
"net/http"
"testing"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

/*
Using https://onsi.github.io/ginkgo/
Running with $> ginkgo -cover .
*/

var srv = &http.Server{
Addr: ":8080",
Handler: Hello(),
}

var (
ctx, cnl = context.WithCancel(context.Background())
)

func TestGolibHttpDNSMapperHelper(t *testing.T) {
defer func() {
cnl()
_ = srv.Shutdown(context.Background())
}()

go func() {
if e := srv.ListenAndServe(); e != nil {
if !errors.Is(e, http.ErrServerClosed) {
panic(e)
}
}
}()

time.Sleep(500 * time.Millisecond)

RegisterFailHandler(Fail)
RunSpecs(t, "HTTP DNS Mapper Helper Suite")
}

var _ = BeforeSuite(func() {
})

var _ = AfterSuite(func() {
})

func Hello() http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
_, _ = fmt.Fprintf(writer, "hello\n")
_, _ = fmt.Fprintf(writer, "Requested Hostname: %s\n", request.Host)
_, _ = fmt.Fprintf(writer, "Requested Uri: %s\n", request.RequestURI)
_, _ = fmt.Fprintf(writer, "Requested: %s\n", request.RemoteAddr)
}
}
Loading

0 comments on commit 1d18fbf

Please sign in to comment.