debian-forge-composer/internal/worker/proxy_test.go
Ondřej Budai 6fce34a5ea worker: add proxy support to composer and oauth calls
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>
2022-05-03 06:19:31 +01:00

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)
}