Skip to content
Snippets Groups Projects
Commit bfdb77a2 authored by ale's avatar ale
Browse files

Run a simple httputil.ReverseProxy with TLS connections

We can't do low-level splice() since we don't have access to the raw
socket in the TLS case. This should work for clients though (maybe not
for sources).
parent bb7649b3
Branches
Tags
1 merge request!2Add SSL functionality
...@@ -291,8 +291,8 @@ func newHTTPServer(name, addr string, h http.Handler) *httpServer { ...@@ -291,8 +291,8 @@ func newHTTPServer(name, addr string, h http.Handler) *httpServer {
Handler: h, Handler: h,
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
ReadHeaderTimeout: 3 * time.Second, ReadHeaderTimeout: 3 * time.Second,
WriteTimeout: 10 * time.Second, //WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second, IdleTimeout: 30 * time.Second,
}, },
name: name, name: name,
} }
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"log" "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
...@@ -102,6 +103,18 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL, ...@@ -102,6 +103,18 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL,
outreq.Header.Set("X-Forwarded-For", clientIP) outreq.Header.Set("X-Forwarded-For", clientIP)
} }
// SSL requests can't be hijacked, so we just fire up a normal
// httputil.ReverseProxy (not fully functional for sources, but
// meh).
if req.TLS != nil {
log.Printf("TLS connection, switching to dumb reverse proxy mode")
u := *outreq.URL
u.Path = "/"
rp := httputil.NewSingleHostReverseProxy(&u)
rp.ServeHTTP(rw, outreq)
return
}
// Create the upstream connection and write the HTTP request // Create the upstream connection and write the HTTP request
// to it. // to it.
upstream, err := dialer.Dial("tcp", outreq.URL.Host) upstream, err := dialer.Dial("tcp", outreq.URL.Host)
...@@ -147,7 +160,7 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL, ...@@ -147,7 +160,7 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL,
} }
if conn == nil { if conn == nil {
log.Printf("http: proxy error: could not find hijackable connection") log.Printf("http: proxy error: could not find hijackable connection")
rw.WriteHeader(http.StatusInternalServerError) http.Error(rw, "could not find hijackable connection", http.StatusInternalServerError)
return return
} }
defer conn.Close() defer conn.Close()
...@@ -156,21 +169,17 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL, ...@@ -156,21 +169,17 @@ func doIcecastProxy(rw http.ResponseWriter, req *http.Request, target *url.URL,
} }
// Run two-way proxying. // Run two-way proxying.
handleProxy(conn.(*net.TCPConn), upstream.(*net.TCPConn), streamName) handleProxy(conn, upstream, streamName)
} }
// Copy data between two network connections. On recent Go versions // Copy data between two network connections. On recent Go versions
// (>1.11), this is quite fast as io.CopyBuffer uses the splice() // (>1.11), this is quite fast as io.CopyBuffer uses the splice()
// system call internally (in exchange we lose the ability to figure // system call internally (in exchange we lose the ability to figure
// out which end of the connection is the source of the error). // out which end of the connection is the source of the error).
func copyStream(tag string, out, in *net.TCPConn, promCounter prometheus.Counter, cntr *uint64) { func copyStream(tag string, out io.WriteCloser, in io.ReadCloser, promCounter prometheus.Counter, cntr *uint64) {
buf := getBuf() buf := getBuf()
defer releaseBuf(buf) defer releaseBuf(buf)
// We used to do this in order to support half-closed connections.
//defer in.CloseRead() //nolint
//defer out.CloseWrite() //nolint
// Instead we do this and shut down the entire connection on error. // Instead we do this and shut down the entire connection on error.
// We end up calling Close() twice but that's not a huge problem. // We end up calling Close() twice but that's not a huge problem.
defer in.Close() //nolint defer in.Close() //nolint
...@@ -195,7 +204,7 @@ func isCloseError(err error) bool { ...@@ -195,7 +204,7 @@ func isCloseError(err error) bool {
// Simple two-way TCP proxy that copies data in both directions and // Simple two-way TCP proxy that copies data in both directions and
// can shutdown each direction of the connection independently. // can shutdown each direction of the connection independently.
func handleProxy(conn *net.TCPConn, upstream *net.TCPConn, streamName string) { func handleProxy(conn, upstream io.ReadWriteCloser, streamName string) {
l := streamListeners.WithLabelValues(streamName) l := streamListeners.WithLabelValues(streamName)
l.Inc() l.Inc()
var wg sync.WaitGroup var wg sync.WaitGroup
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment