Skip to content

Instantly share code, notes, and snippets.

@njones
Created February 11, 2016 13:19
Show Gist options
  • Save njones/bdcbf96699e021250d0d to your computer and use it in GitHub Desktop.
Save njones/bdcbf96699e021250d0d to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"strconv"
)
const (
maxPort = 65535
)
var (
optPort = flag.String("port", ":57443", "The port to serve from, it must begin with a :")
optURL = flag.String("url", "http://127.0.0.1:5757", "The URL to proxy to. This is setup for CodeKit")
optKey = flag.String("key", "server.key", "The private key")
optPem = flag.String("pem", "server.pem", "The pem file, with a cert chain if necessary")
optTail = flag.Bool("tail", false, "Show the proxied URLs as they are processed")
)
// proxyProxy The object used to handle the proxying
type proxyProxy struct {
target *url.URL
proxy *httputil.ReverseProxy
}
// handle does the actuall proxying
func (p *proxyProxy) handle(w http.ResponseWriter, r *http.Request) {
// if -tail is used then printout each proxied URL as it happens
if *optTail {
log.Println(r.URL.Path)
}
p.proxy.ServeHTTP(w, r)
}
// newProxy returns a new instance of the proxyProxy object with the target URL filled in
func newProxy(target string) *proxyProxy {
url, err := url.Parse(target)
if err != nil {
log.Fatal(err)
}
return &proxyProxy{target: url, proxy: httputil.NewSingleHostReverseProxy(url)}
}
// envWithDefault will check if there is an environment variable and use it.
func envWithDefault(envKey, defaultVal string) (rtn string) {
rtn = os.Getenv(envKey)
if len(rtn) == 0 {
rtn = defaultVal
}
return
}
func main() {
// Handle the Ctl-C interrupt so we can shutdown gracefully.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
log.Println("Shutting Down.")
os.Exit(0)
}()
// Capture all of the commandline options, replacing any enviorment variables.
// the precedent is:
// 3 - Default
// 2 - Commandline options
// 1 - Environment variables
flag.Parse()
pem := envWithDefault("CK_PROXYPROXY_PEM", *optPem)
key := envWithDefault("CK_PROXYPROXY_KEY", *optKey)
// check to see if the port has been defined correctly
optPortCheck := *optPort
if len(optPortCheck) > 0 {
if optPortCheck[0] != ':' {
log.Fatal("The -port option should start with a :")
}
if i, err := strconv.Atoi(optPortCheck[1:]); err != nil {
log.Fatal("The -port option is not an integer.")
} else {
if i < 1 || i > maxPort {
log.Fatal("The -port option must be between 1-", maxPort)
}
}
} else {
log.Fatal("The -port option is empty. It should contain :<port_number>")
}
// check to see if the url has been defined correctly
if len(*optURL) > 0 {
if _, err := url.Parse(*optURL); err != nil {
log.Fatal("The -url option is invalid. ", err)
}
} else {
log.Fatal("The -url option is empty. It should contain a valid URL")
}
log.Printf("Redirecting to: %s on port %s\n", *optURL, *optPort)
log.Println("Running...")
// Handle everything, and serve with a cert and key.
http.HandleFunc("/", newProxy(*optURL).handle)
if err := http.ListenAndServeTLS(*optPort, pem, key, nil); err != nil {
log.Println("Stopped.")
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment