-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
115 lines (102 loc) · 2.42 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"errors"
"fmt"
"github.com/docopt/docopt-go"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strconv"
)
func main() {
usage := `ishi.
Usage:
ishi [-l=<port>] [--verbose] <upstream>
ishi -h | --help
ishi --version
Arguments:
upstream Upstream host.
Options:
-h --help Show help.
--version Show version.
-l --listen=<port> Specify port to listen.
--verbose Show debug information.
Examples:
ishi 192.168.10.2
ishi http://192.168.10.2
ishi https://secure.example.com`
arguments, _ := docopt.Parse(usage, nil, true, "1.1.0", false)
upstream := arguments["<upstream>"]
listen := arguments["--listen"]
verbose := arguments["--verbose"].(bool)
var err error
// define port to listen
var port int
if listen == nil {
port, err = findAvailablePort()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
} else {
port, err = strconv.Atoi(listen.(string))
if err != nil {
fmt.Fprintf(os.Stderr, "Invalid listening port\n")
os.Exit(1)
}
}
// define upstream host and scheme
u, err := url.Parse(upstream.(string))
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
var upstreamHost string
if u.Host == "" {
upstreamHost = u.Path
} else {
upstreamHost = u.Host
}
scheme := "http"
if u.Scheme != "" {
scheme = u.Scheme
}
// start reverse proxy server
fmt.Printf("Listening on 0.0.0.0:%d\nFowarding to %s\n", port, upstream)
err = httpfwd(fmt.Sprintf(":%d", port), scheme, upstreamHost, verbose)
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}
func findAvailablePort() (int, error) {
for port := 8000; port < 9000; port++ {
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err == nil {
defer ln.Close()
return port, nil
}
}
return 0, errors.New("There is no available port to listen")
}
func httpfwd(listenAddr, scheme, remoteHost string, verbose bool) error {
http.HandleFunc("/",
func(w http.ResponseWriter, r *http.Request) {
originalHost := r.Host
r.Host = remoteHost
r.Header["X-Forwarded-Host"] = []string{originalHost}
if verbose {
if requestDump, err := httputil.DumpRequest(r, false); err == nil {
fmt.Println(string(requestDump))
}
}
p := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: scheme,
Host: remoteHost,
})
p.ServeHTTP(w, r)
})
return http.ListenAndServe(listenAddr, nil)
}