summaryrefslogtreecommitdiff
path: root/phlox/main.go
blob: 3516374debf9168aa74fc051118944313aa29821 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package main

import (
	"fmt"
	"io"
	"strings"
	"net"
	"net/http"
	"net/url"
	log "github.com/sirupsen/logrus"
)


func main() {
	const addr = "localhost:3333"

	log.Info("configuring reverse proxy...")
	configureEndpoint("/proxy1", "http://localhost:8000")

	log.Infof("serving on %v", addr)
	log.Fatal(http.ListenAndServe(addr, nil))
}


type Endpoint struct {
	Path string
	Origin *url.URL
}


func configureEndpoint(path, address string) {
	log.Infof("proxying endpoint %v to %v", path, address)
	origin, err := url.Parse(address)
	if err != nil {
		log.Fatal(err)
	}

	end := Endpoint{
		Path: path,
		Origin: origin,
	}

	http.HandleFunc(path + "/", func(w http.ResponseWriter, req *http.Request) {
		log.Infof("REQ: %v", req.URL.Path)
		proxy(w, req, end)
	})
}


func proxy(w http.ResponseWriter, req *http.Request, end Endpoint) {
	response := proxyRequest(w, req, end)
	proxyResponse(w, response)
}


func proxyRequest(w http.ResponseWriter, req *http.Request, end Endpoint)  *http.Response {
	// configure host address
	req.Host = end.Origin.Host
	req.URL.Host = end.Origin.Host

	// strip proxy endpoint path from request path
	req.URL.Path = strings.TrimPrefix(req.URL.Path, end.Path)

	// set X-Forwarded-For
	forwardedFor, _, _ := net.SplitHostPort(req.RemoteAddr)
	req.Header.Set("X-Forwarded-For", forwardedFor)

	// misc request cleanups
	req.URL.Scheme = end.Origin.Scheme
	req.RequestURI = ""
	
	// make request
	response, err := http.DefaultClient.Do(req)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "%v", err)
		log.Fatal(err)
	}

	return response
}


func proxyResponse(w http.ResponseWriter, response *http.Response) {
	// copy header
	for key, values := range response.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	// get trailer keys
	trailerKeys := []string{}
	for key := range response.Trailer {
		trailerKeys = append(trailerKeys, key)
	}
	if (len(trailerKeys) > 0) {
		w.Header().Set("Trailer", strings.Join(trailerKeys, ","))
	}

	w.WriteHeader(response.StatusCode)

	// copy body to client
	io.Copy(w, response.Body)

	// write trailers
	for key, values := range response.Trailer {
		for _, value := range values {
			w.Header().Set(key, value)
		}
	}
}