Created
May 1, 2018 10:57
-
-
Save corehello/6f50472d9b4f9a5624c49312c17d3e99 to your computer and use it in GitHub Desktop.
golang simple http proxy @ https://medium.com/@mlowicki/http-s-proxy-in-golang-in-less-than-100-lines-of-code-6a51c2f2c38c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"flag" | |
"io" | |
"log" | |
"net" | |
"net/http" | |
"time" | |
) | |
func handleTunneling(w http.ResponseWriter, r *http.Request) { | |
dest_conn, err := net.DialTimeout("tcp", r.Host, 10*time.Second) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusServiceUnavailable) | |
return | |
} | |
w.WriteHeader(http.StatusOK) | |
hijacker, ok := w.(http.Hijacker) | |
if !ok { | |
http.Error(w, "Hijacking not supported", http.StatusInternalServerError) | |
return | |
} | |
client_conn, _, err := hijacker.Hijack() | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusServiceUnavailable) | |
} | |
go transfer(dest_conn, client_conn) | |
go transfer(client_conn, dest_conn) | |
} | |
func transfer(destination io.WriteCloser, source io.ReadCloser) { | |
defer destination.Close() | |
defer source.Close() | |
io.Copy(destination, source) | |
} | |
func handleHTTP(w http.ResponseWriter, req *http.Request) { | |
resp, err := http.DefaultTransport.RoundTrip(req) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusServiceUnavailable) | |
return | |
} | |
defer resp.Body.Close() | |
copyHeader(w.Header(), resp.Header) | |
w.WriteHeader(resp.StatusCode) | |
io.Copy(w, resp.Body) | |
} | |
func copyHeader(dst, src http.Header) { | |
for k, vv := range src { | |
for _, v := range vv { | |
dst.Add(k, v) | |
} | |
} | |
} | |
func main() { | |
var pemPath string | |
flag.StringVar(&pemPath, "pem", "server.pem", "path to pem file") | |
var keyPath string | |
flag.StringVar(&keyPath, "key", "server.key", "path to key file") | |
var proto string | |
flag.StringVar(&proto, "proto", "https", "Proxy protocol (http or https)") | |
flag.Parse() | |
if proto != "http" && proto != "https" { | |
log.Fatal("Protocol must be either http or https") | |
} | |
server := &http.Server{ | |
Addr: ":8888", | |
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
log.Println(r) | |
if r.Method == http.MethodConnect { | |
handleTunneling(w, r) | |
} else { | |
handleHTTP(w, r) | |
} | |
}), | |
// Disable HTTP/2. | |
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)), | |
} | |
if proto == "http" { | |
log.Println("Serving on port 8888 with http protocol") | |
log.Fatal(server.ListenAndServe()) | |
} else { | |
log.Println("Serving on port 8888 with https protocol") | |
log.Fatal(server.ListenAndServeTLS(pemPath, keyPath)) | |
} | |
} |
Also need to check if the file descriptors are enough to accept many requests:
$ ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) unlimited
-m: resident set size (kbytes) unlimited
-u: processes 31157
-n: file descriptors 1024
-l: locked-in-memory size (kbytes) 64
-v: address space (kbytes) unlimited
-x: file locks unlimited
-i: pending signals 31157
-q: bytes in POSIX msg queues 819200
-e: max nice 0
-r: max rt priority 0
-N 15: unlimited
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Big zan!