Skip to content

Instantly share code, notes, and snippets.

@gauravds
Last active March 26, 2025 11:55
Show Gist options
  • Save gauravds/99fe316cfaaa5e5e56136613bd7f90db to your computer and use it in GitHub Desktop.
Save gauravds/99fe316cfaaa5e5e56136613bd7f90db to your computer and use it in GitHub Desktop.
Go proxy server
package main
import (
"bytes"
"encoding/json"
"flag"
"io"
"log"
"net/http"
"os"
"time"
)
type ProxyRequest struct {
Host string `json:"host"`
Method string `json:"method"`
Body string `json:"body"`
Headers map[string]string `json:"headers"`
}
// Allow all CORS
func enableCORS(w http.ResponseWriter) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "*")
}
func proxyHandler(w http.ResponseWriter, r *http.Request) {
enableCORS(w)
// Handle GET /ping request
if r.URL.Path == "/ping" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
now := time.Now()
json.NewEncoder(w).Encode(map[string]int64{
"pong": now.UnixNano() / int64(time.Millisecond),
})
return
}
// Handle preflight CORS request
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
}
if r.Method != http.MethodPost {
http.Error(w, "Only POST supported", http.StatusMethodNotAllowed)
return
}
reqBody, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body: "+err.Error(), http.StatusBadRequest)
return
}
defer r.Body.Close()
var proxyReq ProxyRequest
if err := json.Unmarshal(reqBody, &proxyReq); err != nil {
http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
return
}
if proxyReq.Host == "" {
http.Error(w, "'host' is required", http.StatusBadRequest)
return
}
if proxyReq.Method == "" {
proxyReq.Method = "POST"
}
outReq, err := http.NewRequest(proxyReq.Method, proxyReq.Host, bytes.NewBuffer([]byte(proxyReq.Body)))
if err != nil {
http.Error(w, "Failed to create outbound request: "+err.Error(), http.StatusInternalServerError)
return
}
for key, value := range proxyReq.Headers {
outReq.Header.Set(key, value)
}
log.Printf("🔁 Forwarding %s request to %s\n", proxyReq.Method, proxyReq.Host)
client := &http.Client{}
resp, err := client.Do(outReq)
if err != nil {
http.Error(w, "Request failed: "+err.Error(), http.StatusBadGateway)
return
}
defer resp.Body.Close()
for k, vv := range resp.Header {
for _, v := range vv {
w.Header().Add(k, v)
}
}
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func main() {
defaultPort := "9080"
port := flag.String("port", os.Getenv("PORT"), "Port to run the proxy server on")
flag.Parse()
if *port == "" {
*port = defaultPort
}
http.HandleFunc("/", proxyHandler)
log.Printf("🟢 Proxy server listening on http://localhost:%s\n", *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
// GOOS=windows GOARCH=amd64 go build -o proxy.exe proxy.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment