Skip to content

Instantly share code, notes, and snippets.

@cbluth
Forked from dbrinegar/revproxy.go
Created February 5, 2024 09:34
Show Gist options
  • Save cbluth/f937518c23339a82bbba32acf29e03f5 to your computer and use it in GitHub Desktop.
Save cbluth/f937518c23339a82bbba32acf29e03f5 to your computer and use it in GitHub Desktop.

Revisions

  1. @dbrinegar dbrinegar revised this gist May 25, 2017. 1 changed file with 10 additions and 1 deletion.
    11 changes: 10 additions & 1 deletion revproxy.go
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@ import (
    RemoteBase = https://some.service.com/protected/path
    Username = username
    Password = password
    */
    */
    type Config struct {
    Proxy struct {
    RemoteBase string
    @@ -76,6 +76,11 @@ func main() {
    if r.StatusCode != http.StatusOK {
    log.Printf("request for %s got %v", r.Request.URL.String(), r.StatusCode)
    }
    if location, err := r.Location(); err == nil {
    log.Printf("fetching: %+v", location.String())
    resp, _ := http.DefaultClient.Get(location.String())
    *r = *resp
    }
    return nil
    }

    @@ -85,5 +90,9 @@ func main() {
    proxy.ServeHTTP(w, r)
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    log.Print("unhandled: " + r.URL.Path)
    })

    http.ListenAndServe(config.Proxy.Listen, nil)
    }
  2. @dbrinegar dbrinegar created this gist May 25, 2017.
    89 changes: 89 additions & 0 deletions revproxy.go
    Original file line number Diff line number Diff line change
    @@ -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)
    }