IOTTMCO

Intuitively Obvious to the Most Casual Observer

Trivial HTTP Proxy in Go

One nice aspect of Go’s standard http library is that the asymmetry between the client and the server is kept to a minimum. For example the same Request object is used for both, with (nearly) identical semantics. This makes writing a simple HTTP proxy a breeze.

package main

import (
	"flag"
	"log"
	"net/http"
	"strings"
	"unicode"
)

var (
	listen = flag.String("listen", "localhost:1080", "listen on address")
	logp = flag.Bool("log", false, "enable logging")
)

func main() {
	flag.Parse()
	proxyHandler := http.HandlerFunc(proxyHandlerFunc)
	log.Fatal(http.ListenAndServe(*listen, proxyHandler))
}

func proxyHandlerFunc(w http.ResponseWriter, r *http.Request) {
	// Log if requested
	if *logp {
		log.Println(r.URL)
	}

	// We'll want to use a new client for every request.
	client := &http.Client{}

	// Tweak the request as appropriate:
	//	RequestURI may not be sent to client
	//	URL.Scheme must be lower-case
	r.RequestURI = ""
	r.URL.Scheme = strings.Map(unicode.ToLower, r.URL.Scheme)

	// And proxy
	resp, err := client.Do(r)
	if err != nil {
		log.Fatal(err)
	}
	resp.Write(w)
}

This proxy isn’t full-featured: most notably, it lacks support for SSL and proxy-specific headers. Nevertheless, it serves as a good demonstration, and perhaps a good starting point for very simple use cases.

Real applications might want to use elazarl/goproxy.