@@ -25,6 +25,17 @@ type User struct {
25
25
Email string
26
26
}
27
27
28
+ type Backend struct {
29
+ Host string
30
+ URL * url.URL
31
+ Strip bool
32
+ StripPath string
33
+ }
34
+
35
+ const (
36
+ BackendHostHeader = "X-Gate-Backend-Host"
37
+ )
38
+
28
39
func NewServer (conf * Conf ) * Server {
29
40
return & Server {conf }
30
41
}
@@ -33,12 +44,19 @@ func (s *Server) Run() error {
33
44
m := martini .Classic ()
34
45
a := NewAuthenticator (s .Conf )
35
46
36
- m .Use (sessions .Sessions ("session" , sessions .NewCookieStore ([]byte (s .Conf .Auth .Session .Key ))))
47
+ cookieStore := sessions .NewCookieStore ([]byte (s .Conf .Auth .Session .Key ))
48
+ if domain := s .Conf .Auth .Session .CookieDomain ; domain != "" {
49
+ cookieStore .Options (sessions.Options {Domain : domain })
50
+ }
51
+ m .Use (sessions .Sessions ("session" , cookieStore ))
37
52
m .Use (a .Handler ())
38
53
39
54
m .Use (loginRequired ())
40
55
m .Use (restrictRequest (s .Conf .Restrictions , a ))
41
56
57
+ backendsFor := make (map [string ][]Backend )
58
+ backendIndex := make ([]string , len (s .Conf .Proxies ))
59
+
42
60
for i := range s .Conf .Proxies {
43
61
p := s .Conf .Proxies [i ]
44
62
@@ -55,15 +73,24 @@ func (s *Server) Run() error {
55
73
if err != nil {
56
74
return err
57
75
}
76
+ backendsFor [p .Path ] = append (backendsFor [p .Path ], Backend {
77
+ Host : p .Host ,
78
+ URL : u ,
79
+ Strip : p .Strip ,
80
+ StripPath : strip_path ,
81
+ })
82
+ backendIndex [i ] = p .Path
83
+ log .Printf ("register proxy host:%s path:%s dest:%s strip_path:%v" , p .Host , strip_path , u .String (), p .Strip )
84
+ }
58
85
59
- proxy := httputil .NewSingleHostReverseProxy (u )
60
- if p .Strip {
61
- m .Any (p .Path , http .StripPrefix (strip_path , proxyHandleWrapper (u , proxy )))
62
- } else {
63
- m .Any (p .Path , proxyHandleWrapper (u , proxy ))
86
+ registered := make (map [string ]bool )
87
+ for _ , path := range backendIndex {
88
+ if registered [path ] {
89
+ continue
64
90
}
65
-
66
- log .Printf ("register proxy path:%s dest:%s" , strip_path , u .String ())
91
+ proxy := newVirtualHostReverseProxy (backendsFor [path ])
92
+ m .Any (path , proxyHandleWrapper (proxy ))
93
+ registered [path ] = true
67
94
}
68
95
69
96
path , err := filepath .Abs (s .Conf .Htdocs )
@@ -84,6 +111,34 @@ func (s *Server) Run() error {
84
111
}
85
112
}
86
113
114
+ func newVirtualHostReverseProxy (backends []Backend ) http.Handler {
115
+ bmap := make (map [string ]Backend )
116
+ for _ , b := range backends {
117
+ bmap [b .Host ] = b
118
+ }
119
+ defaultBackend , ok := bmap ["" ]
120
+ if ! ok {
121
+ defaultBackend = backends [0 ]
122
+ }
123
+
124
+ director := func (req * http.Request ) {
125
+ b , ok := bmap [req .Host ]
126
+ if ! ok {
127
+ b = defaultBackend
128
+ }
129
+ req .URL .Scheme = b .URL .Scheme
130
+ req .URL .Host = b .URL .Host
131
+ if b .Strip {
132
+ if p := strings .TrimPrefix (req .URL .Path , b .StripPath ); len (p ) < len (req .URL .Path ) {
133
+ req .URL .Path = "/" + p
134
+ }
135
+ }
136
+ req .Header .Set (BackendHostHeader , req .URL .Host )
137
+ log .Println ("backend url" , req .URL .String ())
138
+ }
139
+ return & httputil.ReverseProxy {Director : director }
140
+ }
141
+
87
142
func isWebsocket (r * http.Request ) bool {
88
143
if strings .ToLower (r .Header .Get ("Connection" )) == "upgrade" &&
89
144
strings .ToLower (r .Header .Get ("Upgrade" )) == "websocket" {
@@ -93,11 +148,16 @@ func isWebsocket(r *http.Request) bool {
93
148
}
94
149
}
95
150
96
- func proxyHandleWrapper (u * url.URL , handler http.Handler ) http.Handler {
151
+ func proxyHandleWrapper (handler http.Handler ) http.Handler {
152
+ proxy , _ := handler .(* httputil.ReverseProxy )
153
+ director := proxy .Director
154
+
97
155
return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
98
156
// websocket?
99
157
if isWebsocket (r ) {
100
- target := u .Host
158
+ director (r ) // rewrite request headers for backend
159
+ target := r .Header .Get (BackendHostHeader )
160
+
101
161
if strings .HasPrefix (r .URL .Path , "/" ) == false {
102
162
r .URL .Path = "/" + r .URL .Path
103
163
}
0 commit comments