|
6 | 6 | "io"
|
7 | 7 | "net/http"
|
8 | 8 | "strings"
|
| 9 | + "time" |
9 | 10 |
|
10 | 11 | "github.com/gorilla/websocket"
|
11 | 12 | "github.com/sirupsen/logrus"
|
@@ -34,6 +35,9 @@ type Proxy struct {
|
34 | 35 | tokenCookieName string
|
35 | 36 | requestMutator RequestMutatorFunc
|
36 | 37 | headerForwarder func(header string) bool
|
| 38 | + pingInterval time.Duration |
| 39 | + pingWait time.Duration |
| 40 | + pongWait time.Duration |
37 | 41 | }
|
38 | 42 |
|
39 | 43 | // Logger collects log messages.
|
@@ -97,6 +101,17 @@ func WithLogger(logger Logger) Option {
|
97 | 101 | }
|
98 | 102 | }
|
99 | 103 |
|
| 104 | +// WithPingControl allows specification of ping pong control. The interval |
| 105 | +// parameter specifies the pingInterval between pings. The allowed wait time |
| 106 | +// for a pong response is (pingInterval * 10) / 9. |
| 107 | +func WithPingControl(interval time.Duration) Option { |
| 108 | + return func(proxy *Proxy) { |
| 109 | + proxy.pingInterval = interval |
| 110 | + proxy.pongWait = (interval * 10) / 9 |
| 111 | + proxy.pingWait = proxy.pongWait / 6 |
| 112 | + } |
| 113 | +} |
| 114 | + |
100 | 115 | var defaultHeadersToForward = map[string]bool{
|
101 | 116 | "Origin": true,
|
102 | 117 | "origin": true,
|
@@ -211,6 +226,10 @@ func (p *Proxy) proxy(w http.ResponseWriter, r *http.Request) {
|
211 | 226 |
|
212 | 227 | // read loop -- take messages from websocket and write to http request
|
213 | 228 | go func() {
|
| 229 | + if p.pingInterval > 0 && p.pingWait > 0 && p.pongWait > 0 { |
| 230 | + conn.SetReadDeadline(time.Now().Add(p.pongWait)) |
| 231 | + conn.SetPongHandler(func(string) error { conn.SetReadDeadline(time.Now().Add(p.pongWait)); return nil }) |
| 232 | + } |
214 | 233 | defer func() {
|
215 | 234 | cancelFn()
|
216 | 235 | }()
|
@@ -242,6 +261,28 @@ func (p *Proxy) proxy(w http.ResponseWriter, r *http.Request) {
|
242 | 261 | }
|
243 | 262 | }
|
244 | 263 | }()
|
| 264 | + // ping write loop |
| 265 | + if p.pingInterval > 0 && p.pingWait > 0 && p.pongWait > 0 { |
| 266 | + go func() { |
| 267 | + ticker := time.NewTicker(p.pingInterval) |
| 268 | + defer func() { |
| 269 | + ticker.Stop() |
| 270 | + conn.Close() |
| 271 | + }() |
| 272 | + for { |
| 273 | + select { |
| 274 | + case <-ctx.Done(): |
| 275 | + p.logger.Debugln("ping loop done") |
| 276 | + return |
| 277 | + case <-ticker.C: |
| 278 | + conn.SetWriteDeadline(time.Now().Add(p.pingWait)) |
| 279 | + if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil { |
| 280 | + return |
| 281 | + } |
| 282 | + } |
| 283 | + } |
| 284 | + }() |
| 285 | + } |
245 | 286 | // write loop -- take messages from response and write to websocket
|
246 | 287 | scanner := bufio.NewScanner(responseBodyR)
|
247 | 288 |
|
|
0 commit comments