Skip to content

Commit 4a180ca

Browse files
committed
finalized the core
1 parent e93d85c commit 4a180ca

File tree

9 files changed

+246
-1
lines changed

9 files changed

+246
-1
lines changed

go.mod

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@ module github.com/alash3al/httpsify
22

33
go 1.13
44

5-
require github.com/labstack/echo/v4 v4.1.11 // indirect
5+
require (
6+
github.com/fsnotify/fsnotify v1.4.7
7+
github.com/labstack/echo v3.3.10+incompatible
8+
github.com/labstack/echo/v4 v4.1.11
9+
github.com/mitchellh/go-homedir v1.1.0
10+
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915
11+
)

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
23
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
4+
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
5+
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
36
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
7+
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
48
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
59
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
610
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
@@ -10,6 +14,8 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
1014
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
1115
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
1216
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
17+
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
18+
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
1319
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1420
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1521
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -20,6 +26,8 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
2026
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2127
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
2228
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
29+
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 h1:aJ0ex187qoXrJHPo8ZasVTASQB7llQP6YeNzgDALPRk=
30+
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
2331
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
2432
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
2533
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

handler.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import "github.com/labstack/echo/v4"
4+
5+
func handler(c echo.Context) error {
6+
req := c.Request()
7+
res := c.Response()
8+
9+
hosts := hosts.Load().(map[string]*echo.Echo)
10+
host := hosts[req.Host]
11+
12+
if host == nil {
13+
return echo.ErrNotFound
14+
}
15+
16+
host.ServeHTTP(res, req)
17+
18+
return nil
19+
}

hosts.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"net/url"
7+
"os"
8+
"strings"
9+
10+
"github.com/fsnotify/fsnotify"
11+
"github.com/labstack/echo/v4"
12+
"github.com/labstack/echo/v4/middleware"
13+
)
14+
15+
func parseHostsFile(filename string) (map[string]*echo.Echo, error) {
16+
fd, err := os.OpenFile(filename, os.O_RDONLY|os.O_CREATE, 0755)
17+
if err != nil {
18+
return nil, err
19+
}
20+
defer fd.Close()
21+
22+
finfo, err := fd.Stat()
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
if finfo.Size() == 0 {
28+
return map[string]*echo.Echo{}, nil
29+
}
30+
31+
var rawdata map[string][]string
32+
33+
if err := json.NewDecoder(fd).Decode(&rawdata); err != nil {
34+
return nil, err
35+
}
36+
37+
compiled := map[string]*echo.Echo{}
38+
39+
for host, upstreams := range rawdata {
40+
if len(upstreams) < 1 {
41+
return nil, errors.New("no upstreams for: " + host)
42+
}
43+
44+
targets := []*middleware.ProxyTarget{}
45+
for _, upstream := range upstreams {
46+
if !strings.HasPrefix(upstream, "http://") || !strings.HasPrefix(upstream, "https://") {
47+
upstream = "http://" + upstream
48+
}
49+
50+
u, err := url.Parse(upstream)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
targets = append(targets, &middleware.ProxyTarget{
56+
URL: u,
57+
})
58+
}
59+
60+
e := echo.New()
61+
e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer(targets)))
62+
63+
compiled[host] = e
64+
}
65+
66+
return compiled, nil
67+
}
68+
69+
func watchHostsChanges(filename string, fn func()) error {
70+
watcher, err := fsnotify.NewWatcher()
71+
if err != nil {
72+
return err
73+
}
74+
defer watcher.Close()
75+
76+
watcher.Add(filename)
77+
78+
for {
79+
select {
80+
case <-watcher.Events:
81+
fn()
82+
}
83+
}
84+
}
85+
86+
func getAvailableHosts() []string {
87+
result := []string{}
88+
89+
for k := range hosts.Load().(map[string]*echo.Echo) {
90+
result = append(result, k)
91+
}
92+
93+
return result
94+
}

hosts.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"test1.store:9091": ["localhost:8002"]
3+
}

init.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"log"
6+
"os"
7+
)
8+
9+
func init() {
10+
flag.Parse()
11+
12+
os.MkdirAll(*flagAutocertCacheDir, 0755)
13+
14+
{
15+
resultedHosts, err := parseHostsFile(*flagHostsFile)
16+
if err != nil {
17+
log.Fatal(err.Error())
18+
}
19+
20+
hosts.Store(resultedHosts)
21+
}
22+
23+
{
24+
go watchHostsChanges(*flagHostsFile, func() {
25+
log.Println("⇨ reloading hosts file ...")
26+
resultedHosts, err := parseHostsFile(*flagHostsFile)
27+
if err != nil {
28+
log.Println("⇨ ", err.Error())
29+
return
30+
}
31+
32+
hosts.Store(resultedHosts)
33+
})
34+
}
35+
36+
{
37+
go preloadCerts()
38+
}
39+
}

main.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
package main
22

3+
import (
4+
"log"
5+
6+
"github.com/labstack/echo/v4"
7+
"github.com/labstack/echo/v4/middleware"
8+
"golang.org/x/crypto/acme/autocert"
9+
)
10+
311
func main() {
12+
e := echo.New()
13+
e.HideBanner = true
14+
e.AutoTLSManager.HostPolicy = autocert.HostWhitelist(getAvailableHosts()...)
15+
e.AutoTLSManager.Cache = autocert.DirCache(*flagAutocertCacheDir)
16+
17+
e.Use(middleware.HTTPSRedirect())
18+
e.Use(middleware.Logger())
19+
e.Use(middleware.Recover())
20+
21+
e.Any("/*", handler)
22+
23+
errChan := make(chan error)
24+
25+
go (func() {
26+
errChan <- e.Start(*flagHTTPAddr)
27+
})()
28+
29+
go (func() {
30+
errChan <- e.StartAutoTLS(*flagHTTPSAddr)
31+
})()
432

33+
log.Fatal(map[string]interface{}{
34+
"message": <-errChan,
35+
})
536
}

preloader.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
7+
"github.com/labstack/echo/v4"
8+
)
9+
10+
func preloadCerts() {
11+
hosts := hosts.Load().(map[string]*echo.Echo)
12+
13+
for k := range hosts {
14+
go (func(h string) {
15+
resp, err := http.Get("http://" + h)
16+
if err != nil {
17+
log.Println(err.Error())
18+
}
19+
defer resp.Body.Close()
20+
log.Printf("=> preloading certs result for %s -> %s\n", h, resp.Status)
21+
})(k)
22+
}
23+
}

vars.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"path"
6+
"sync/atomic"
7+
8+
"github.com/mitchellh/go-homedir"
9+
)
10+
11+
var (
12+
homeDir, _ = homedir.Dir()
13+
hosts = atomic.Value{}
14+
)
15+
16+
var (
17+
flagHTTPSAddr = flag.String("https", ":443", "the port to listen for https requests on, it is recommended to leave it as is")
18+
flagHTTPAddr = flag.String("http", ":80", "the port to listen for http requests on, it is recommended to leave it as is")
19+
flagAutocertCacheDir = flag.String("certs", path.Join(homeDir, ".httpsify/certs"), "the certs directory")
20+
flagHostsFile = flag.String("hosts", path.Join(homeDir, ".httpsify/hosts.json"), "the file containing hosts mappings to upstreams")
21+
flagSendXSecuredBy = flag.Bool("x-secured-by", true, "whether to enable x-secured-by header or not")
22+
)

0 commit comments

Comments
 (0)