aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-03-25 20:04:45 +0100
committerDimitri Sokolyuk <demon@dim13.org>2016-03-25 20:04:45 +0100
commit57c53df2246eb79d77245e8f2cc9efe03f997c14 (patch)
treef1e1bd2bdcf966324b20e2cb7c66c235f6059e2e
parent80dbf3cbd4a37979f21116f4f03250c025ea41f1 (diff)
Add (working) stub for WebSocket Proxy
-rw-r--r--Makefile5
-rw-r--r--route.go17
-rw-r--r--ws.go68
3 files changed, 88 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 2b63d94..e399de4 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ TAG=registry.moccu/${APP}
build:
docker build --tag ${TAG} --rm --no-cache .
-push:
+push: build
docker push ${TAG}
volume:
@@ -24,3 +24,6 @@ start:
--name ${APP} --net ${APP} --restart unless-stopped ${TAG}
restart: stop start
+
+logs:
+ docker logs -f ${APP}
diff --git a/route.go b/route.go
index 1440546..67b3c88 100644
--- a/route.go
+++ b/route.go
@@ -29,6 +29,15 @@ func (r Route) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error)
return nil, errors.New("no cert for " + h.ServerName)
}
+func NewReverseProxy(target *url.URL) *httputil.ReverseProxy {
+ director := func(req *http.Request) {
+ //log.Println("director", req)
+ req.URL.Scheme = target.Scheme
+ req.URL.Host = target.Host
+ }
+ return &httputil.ReverseProxy{Director: director}
+}
+
// Restore and update routes from in-memory state
func (r Route) Restore() error {
mux := http.NewServeMux()
@@ -48,7 +57,13 @@ func (r Route) Restore() error {
if !strings.HasSuffix(v.ServerName, "/") {
v.ServerName += "/"
}
- mux.Handle(v.ServerName, httputil.NewSingleHostReverseProxy(up))
+ //mux.Handle(v.ServerName, httputil.NewSingleHostReverseProxy(up))
+ switch up.Scheme {
+ case "ws":
+ mux.Handle(v.ServerName, NewWebSocketProxy(up))
+ default:
+ mux.Handle(v.ServerName, NewReverseProxy(up))
+ }
}
server.Handler = mux
return nil
diff --git a/ws.go b/ws.go
new file mode 100644
index 0000000..a8f85b6
--- /dev/null
+++ b/ws.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+type WebSocketProxy struct {
+ Director func(*http.Request)
+}
+
+func (p *WebSocketProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ p.Director(r)
+
+ d, err := net.Dial("tcp", r.URL.Host)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ defer d.Close()
+ hj, ok := w.(http.Hijacker)
+ if !ok {
+ http.Error(w, "Not a hijacker", http.StatusInternalServerError)
+ return
+ }
+ nc, _, err := hj.Hijack()
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ defer nc.Close()
+
+ err = r.Write(d)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+
+ errc := make(chan error, 2)
+ cp := func(dst io.Writer, src io.Reader) {
+ _, err := io.Copy(dst, src)
+ errc <- err
+ }
+ go cp(d, nc)
+ go cp(nc, d)
+ <-errc
+}
+
+func NewWebSocketProxy(target *url.URL) *WebSocketProxy {
+ director := func(req *http.Request) {
+ req.URL.Scheme = target.Scheme
+ req.URL.Host = target.Host
+ }
+ return &WebSocketProxy{Director: director}
+}
+
+func isWebsocket(req *http.Request) bool {
+ conn := req.Header.Get("Connection")
+ if strings.ToLower(conn) == "upgrade" {
+ upgrade := req.Header.Get("Upgrade")
+ return strings.ToLower(upgrade) == "websocket"
+ }
+ return false
+}