|
|
@@ -0,0 +1,89 @@ |
|
|
package main |
|
|
|
|
|
import ( |
|
|
"log" |
|
|
"net/http" |
|
|
"net/http/httputil" |
|
|
"net/url" |
|
|
|
|
|
"gopkg.in/gcfg.v1" |
|
|
) |
|
|
|
|
|
/* |
|
|
example config.ini |
|
|
|
|
|
[Proxy] |
|
|
Listen = :8001 |
|
|
RemoteBase = https://some.service.com/protected/path |
|
|
Username = username |
|
|
Password = password |
|
|
*/ |
|
|
type Config struct { |
|
|
Proxy struct { |
|
|
RemoteBase string |
|
|
Username string |
|
|
Password string |
|
|
Listen string |
|
|
} |
|
|
} |
|
|
|
|
|
// like httputil.NewSingleHostReverseProxy but with BasicAuth and Host header rewrite |
|
|
func NewReverseProxy(target *url.URL, user string, pass string) *httputil.ReverseProxy { |
|
|
targetQuery := target.RawQuery |
|
|
director := func(req *http.Request) { |
|
|
req.URL.Scheme = target.Scheme |
|
|
req.URL.Host = target.Host |
|
|
req.URL.Path = req.URL.Path |
|
|
req.URL.RawQuery = targetQuery + req.URL.RawQuery |
|
|
if _, ok := req.Header["User-Agent"]; !ok { |
|
|
req.Header.Set("User-Agent", "") // no default agent |
|
|
} |
|
|
|
|
|
// extensions to NewSingleHostReverseProxy: |
|
|
req.SetBasicAuth(user, pass) |
|
|
req.Host = target.Host |
|
|
} |
|
|
return &httputil.ReverseProxy{Director: director} |
|
|
} |
|
|
|
|
|
func main() { |
|
|
config := &Config{} |
|
|
err := gcfg.ReadFileInto(config, "config.ini") |
|
|
if err != nil { |
|
|
panic(err) |
|
|
} |
|
|
|
|
|
remote, err := url.Parse(config.Proxy.RemoteBase) |
|
|
if err != nil { |
|
|
panic(err) |
|
|
} |
|
|
|
|
|
// turn remote path into our route, must begin and end with a slash to match patterns |
|
|
route := remote.Path |
|
|
remote.Path = "" |
|
|
if route == "" { |
|
|
route = "/" |
|
|
} |
|
|
if route[0] != '/' { |
|
|
route = "/" + route |
|
|
} |
|
|
if route[len(route)-1] != '/' { |
|
|
route = route + "/" |
|
|
} |
|
|
|
|
|
proxy := NewReverseProxy(remote, config.Proxy.Username, config.Proxy.Password) |
|
|
proxy.ModifyResponse = func(r *http.Response) error { |
|
|
if r.StatusCode != http.StatusOK { |
|
|
log.Printf("request for %s got %v", r.Request.URL.String(), r.StatusCode) |
|
|
} |
|
|
return nil |
|
|
} |
|
|
|
|
|
log.Println("proxy for " + route) |
|
|
http.HandleFunc(route, func(w http.ResponseWriter, r *http.Request) { |
|
|
log.Print(r.URL.Path) |
|
|
proxy.ServeHTTP(w, r) |
|
|
}) |
|
|
|
|
|
http.ListenAndServe(config.Proxy.Listen, nil) |
|
|
} |