mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 14:59:57 +00:00
TUN-1893: Proxy requests to the origin based on tunnel hostname
This commit is contained in:
49
tunnelhostnamemapper/tunnelhostnamemapper.go
Normal file
49
tunnelhostnamemapper/tunnelhostnamemapper.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package tunnelhostnamemapper
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/originservice"
|
||||
)
|
||||
|
||||
// TunnelHostnameMapper maps TunnelHostname to an OriginService
|
||||
type TunnelHostnameMapper struct {
|
||||
sync.RWMutex
|
||||
tunnelHostnameToOrigin map[h2mux.TunnelHostname]originservice.OriginService
|
||||
}
|
||||
|
||||
func NewTunnelHostnameMapper() *TunnelHostnameMapper {
|
||||
return &TunnelHostnameMapper{
|
||||
tunnelHostnameToOrigin: make(map[h2mux.TunnelHostname]originservice.OriginService),
|
||||
}
|
||||
}
|
||||
|
||||
// Get an OriginService given a TunnelHostname
|
||||
func (om *TunnelHostnameMapper) Get(key h2mux.TunnelHostname) (originservice.OriginService, bool) {
|
||||
om.RLock()
|
||||
defer om.RUnlock()
|
||||
originService, ok := om.tunnelHostnameToOrigin[key]
|
||||
return originService, ok
|
||||
}
|
||||
|
||||
// Add a mapping. If there is already an OriginService with this key, shutdown the old origin service and replace it
|
||||
// with the new one
|
||||
func (om *TunnelHostnameMapper) Add(key h2mux.TunnelHostname, os originservice.OriginService) {
|
||||
om.Lock()
|
||||
defer om.Unlock()
|
||||
if oldOS, ok := om.tunnelHostnameToOrigin[key]; ok {
|
||||
oldOS.Shutdown()
|
||||
}
|
||||
om.tunnelHostnameToOrigin[key] = os
|
||||
}
|
||||
|
||||
// DeleteAll mappings, and shutdown all OriginService
|
||||
func (om *TunnelHostnameMapper) DeleteAll() {
|
||||
om.Lock()
|
||||
defer om.Unlock()
|
||||
for key, os := range om.tunnelHostnameToOrigin {
|
||||
os.Shutdown()
|
||||
delete(om.tunnelHostnameToOrigin, key)
|
||||
}
|
||||
}
|
69
tunnelhostnamemapper/tunnelhostnamemapper_test.go
Normal file
69
tunnelhostnamemapper/tunnelhostnamemapper_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package tunnelhostnamemapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/originservice"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
routines = 1000
|
||||
)
|
||||
|
||||
func TestTunnelHostnameMapperConcurrentAccess(t *testing.T) {
|
||||
thm := NewTunnelHostnameMapper()
|
||||
|
||||
concurrentOps(t, func(i int) {
|
||||
// om is empty
|
||||
os, ok := thm.Get(tunnelHostname(i))
|
||||
assert.False(t, ok)
|
||||
assert.Nil(t, os)
|
||||
})
|
||||
|
||||
httpOS := originservice.NewHTTPService(http.DefaultTransport, "127.0.0.1:8080", false)
|
||||
concurrentOps(t, func(i int) {
|
||||
thm.Add(tunnelHostname(i), httpOS)
|
||||
})
|
||||
|
||||
concurrentOps(t, func(i int) {
|
||||
os, ok := thm.Get(tunnelHostname(i))
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, httpOS, os)
|
||||
})
|
||||
|
||||
secondHTTPOS := originservice.NewHTTPService(http.DefaultTransport, "127.0.0.1:8090", true)
|
||||
concurrentOps(t, func(i int) {
|
||||
// Add should httpOS with secondHTTPOS
|
||||
thm.Add(tunnelHostname(i), secondHTTPOS)
|
||||
})
|
||||
|
||||
concurrentOps(t, func(i int) {
|
||||
os, ok := thm.Get(tunnelHostname(i))
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, secondHTTPOS, os)
|
||||
})
|
||||
|
||||
thm.DeleteAll()
|
||||
assert.Empty(t, thm.tunnelHostnameToOrigin)
|
||||
}
|
||||
|
||||
func concurrentOps(t *testing.T, f func(i int)) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(routines)
|
||||
for i := 0; i < routines; i++ {
|
||||
go func(i int) {
|
||||
f(i)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func tunnelHostname(i int) h2mux.TunnelHostname {
|
||||
return h2mux.TunnelHostname(fmt.Sprintf("%d.cftunnel.com", i))
|
||||
}
|
Reference in New Issue
Block a user