mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-23 00:56:45 +01:00
Added WebSocket middleware
This commit is contained in:
parent
974acbf38c
commit
811c6a986f
3 changed files with 121 additions and 0 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/mholt/caddy/middleware/proxy"
|
"github.com/mholt/caddy/middleware/proxy"
|
||||||
"github.com/mholt/caddy/middleware/redirect"
|
"github.com/mholt/caddy/middleware/redirect"
|
||||||
"github.com/mholt/caddy/middleware/rewrite"
|
"github.com/mholt/caddy/middleware/rewrite"
|
||||||
|
"github.com/mholt/caddy/middleware/websockets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This init function registers middleware. Register middleware
|
// This init function registers middleware. Register middleware
|
||||||
|
@ -24,6 +25,7 @@ func init() {
|
||||||
register("ext", extensionless.New)
|
register("ext", extensionless.New)
|
||||||
register("proxy", proxy.New)
|
register("proxy", proxy.New)
|
||||||
register("fastcgi", fastcgi.New)
|
register("fastcgi", fastcgi.New)
|
||||||
|
register("websocket", websockets.New)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
32
middleware/websockets/websocket.go
Normal file
32
middleware/websockets/websocket.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package websockets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WebSocket represents a web socket server configuration.
|
||||||
|
type WebSocket struct {
|
||||||
|
Path string
|
||||||
|
Command string
|
||||||
|
Arguments []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle handles a WebSocket connection. It launches the
|
||||||
|
// specified command and streams input and output through
|
||||||
|
// the command's stdin and stdout.
|
||||||
|
func (ws WebSocket) Handle(conn *websocket.Conn) {
|
||||||
|
cmd := exec.Command(ws.Command, ws.Arguments...)
|
||||||
|
cmd.Stdin = conn
|
||||||
|
cmd.Stdout = conn
|
||||||
|
|
||||||
|
// TODO: Set environment variables according to CGI 1.1
|
||||||
|
// cf. http://tools.ietf.org/html/rfc3875#section-4.1.4
|
||||||
|
cmd.Env = append(cmd.Env, `GATEWAY_INTERFACE="caddy-CGI/1.1"`)
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
87
middleware/websockets/websockets.go
Normal file
87
middleware/websockets/websockets.go
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Package websockets implements a WebSocket server by executing
|
||||||
|
// a command and piping its input and output through the WebSocket
|
||||||
|
// connection.
|
||||||
|
package websockets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/flynn/go-shlex"
|
||||||
|
"github.com/mholt/caddy/middleware"
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WebSockets is a type which holds configuration
|
||||||
|
// for the websocket middleware collectively.
|
||||||
|
type WebSockets struct {
|
||||||
|
Sockets []WebSocket
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeHTTP more or less converts the HTTP request to a WebSocket connection.
|
||||||
|
func (ws WebSockets) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
for _, socket := range ws.Sockets {
|
||||||
|
if middleware.Path(r.URL.Path).Matches(socket.Path) {
|
||||||
|
websocket.Handler(socket.Handle).ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New constructs and configures a new websockets middleware instance.
|
||||||
|
func New(c middleware.Controller) (middleware.Middleware, error) {
|
||||||
|
var websocks []WebSocket
|
||||||
|
|
||||||
|
var path string
|
||||||
|
var command string
|
||||||
|
|
||||||
|
for c.Next() {
|
||||||
|
var val string
|
||||||
|
|
||||||
|
// Path or command; not sure which yet
|
||||||
|
if !c.NextArg() {
|
||||||
|
return nil, c.ArgErr()
|
||||||
|
}
|
||||||
|
val = c.Val()
|
||||||
|
|
||||||
|
// The rest of the arguments are the command
|
||||||
|
if c.NextArg() {
|
||||||
|
path = val
|
||||||
|
command = c.Val()
|
||||||
|
for c.NextArg() {
|
||||||
|
command += " " + c.Val()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = "/"
|
||||||
|
command = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split command into the actual command and its arguments
|
||||||
|
var cmd string
|
||||||
|
var args []string
|
||||||
|
|
||||||
|
parts, err := shlex.Split(command)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error parsing command for websocket use: " + err.Error())
|
||||||
|
} else if len(parts) == 0 {
|
||||||
|
log.Fatal("No command found for use by websocket.")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = parts[0]
|
||||||
|
if len(parts) > 1 {
|
||||||
|
args = parts[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
websocks = append(websocks, WebSocket{
|
||||||
|
Path: path,
|
||||||
|
Command: cmd,
|
||||||
|
Arguments: args,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
// We don't use next because websockets aren't HTTP,
|
||||||
|
// so we don't invoke other middleware after this.
|
||||||
|
return WebSockets{Sockets: websocks}.ServeHTTP
|
||||||
|
}, nil
|
||||||
|
}
|
Loading…
Reference in a new issue