In the internal deployment, we want to talk with composer over a http/https proxy. This proxy adds new composer.proxy field to the worker config that causes the worker to connect to composer and the oauth server using a specified proxy. NB: The proxy is not supported when connection to composer via unix sockets. For testing this, I added a small HTTP proxy implementation, pls don't use this in production, it's just good enough for tests. Signed-off-by: Ondřej Budai <ondrej@budai.cz>
86 lines
2 KiB
Go
86 lines
2 KiB
Go
package worker_test
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// Hop-by-hop headers. These are removed when sent to the backend.
|
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
|
var hopHeaders = []string{
|
|
"Connection",
|
|
"Keep-Alive",
|
|
"Proxy-Authenticate",
|
|
"Proxy-Authorization",
|
|
"Te", // canonicalized version of "TE"
|
|
"Trailers",
|
|
"Transfer-Encoding",
|
|
"Upgrade",
|
|
}
|
|
|
|
func copyHeader(dst, src http.Header) {
|
|
for k, vv := range src {
|
|
for _, v := range vv {
|
|
dst.Add(k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
func delHopHeaders(header http.Header) {
|
|
for _, h := range hopHeaders {
|
|
header.Del(h)
|
|
}
|
|
}
|
|
|
|
func appendHostToXForwardHeader(header http.Header, host string) {
|
|
// If we aren't the first proxy retain prior
|
|
// X-Forwarded-For information as a comma+space
|
|
// separated list and fold multiple headers into one.
|
|
if prior, ok := header["X-Forwarded-For"]; ok {
|
|
host = strings.Join(prior, ", ") + ", " + host
|
|
}
|
|
header.Set("X-Forwarded-For", host)
|
|
}
|
|
|
|
// proxy is a simple http-only proxy implementation.
|
|
// Don't use it in production. Also don't use it for https.
|
|
type proxy struct {
|
|
// number of calls that were made through the proxy
|
|
calls int
|
|
}
|
|
|
|
func (p *proxy) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
|
p.calls++
|
|
|
|
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
|
|
msg := "unsupported protocol scheme " + req.URL.Scheme
|
|
http.Error(wr, msg, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
client := &http.Client{}
|
|
|
|
//http: Request.RequestURI can't be set in client requests.
|
|
//http://golang.org/src/pkg/net/http/client.go
|
|
req.RequestURI = ""
|
|
|
|
delHopHeaders(req.Header)
|
|
|
|
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
|
appendHostToXForwardHeader(req.Header, clientIP)
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
http.Error(wr, "Server Error", http.StatusInternalServerError)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
delHopHeaders(resp.Header)
|
|
|
|
copyHeader(wr.Header(), resp.Header)
|
|
wr.WriteHeader(resp.StatusCode)
|
|
_, _ = io.Copy(wr, resp.Body)
|
|
}
|