From 77ac0b8e5860b69a32655ed4ef60c96d0c1cf933 Mon Sep 17 00:00:00 2001 From: George Grozdev Date: Thu, 14 Oct 2021 09:48:46 +0100 Subject: [PATCH 1/3] Allow processing of HTTP headers at WS creation --- backend/localcommand/factory.go | 4 ++-- backend/localcommand/local_command.go | 14 +++++++++++++- backend/localcommand/local_command_test.go | 4 ++-- server/handlers.go | 6 +++--- server/slave.go | 2 +- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/backend/localcommand/factory.go b/backend/localcommand/factory.go index 9d0c916..be6da37 100644 --- a/backend/localcommand/factory.go +++ b/backend/localcommand/factory.go @@ -37,12 +37,12 @@ func (factory *Factory) Name() string { return "local command" } -func (factory *Factory) New(params map[string][]string) (server.Slave, error) { +func (factory *Factory) New(params map[string][]string, headers map[string][]string) (server.Slave, error) { argv := make([]string, len(factory.argv)) copy(argv, factory.argv) if params["arg"] != nil && len(params["arg"]) > 0 { argv = append(argv, params["arg"]...) } - return New(factory.command, argv, factory.opts...) + return New(factory.command, argv, headers, factory.opts...) } diff --git a/backend/localcommand/local_command.go b/backend/localcommand/local_command.go index 71b6c18..d0e0753 100644 --- a/backend/localcommand/local_command.go +++ b/backend/localcommand/local_command.go @@ -3,6 +3,7 @@ package localcommand import ( "os" "os/exec" + "strings" "syscall" "time" @@ -27,11 +28,22 @@ type LocalCommand struct { ptyClosed chan struct{} } -func New(command string, argv []string, options ...Option) (*LocalCommand, error) { +func New(command string, argv []string, headers map[string][]string, options ...Option) (*LocalCommand, error) { cmd := exec.Command(command, argv...) cmd.Env = append(os.Environ(), "TERM=xterm-256color") + // Combine headers into key=value pairs to set as env vars + // Prefix the headers with "http_" so we don't overwrite any other env vars + // which potentially has the same name and to bring these closer to what + // a (F)CGI server would proxy to a backend service + // Replace hyphen with underscore and make them all upper case + for key, values := range headers { + h := "HTTP_" + strings.Replace(strings.ToUpper(key), "-", "_", -1) + "=" + strings.Join(values, ",") + // log.Printf("Adding header: %s", h) + cmd.Env = append(cmd.Env, h) + } + pty, err := pty.Start(cmd) if err != nil { // todo close cmd? diff --git a/backend/localcommand/local_command_test.go b/backend/localcommand/local_command_test.go index ddda029..220cb73 100644 --- a/backend/localcommand/local_command_test.go +++ b/backend/localcommand/local_command_test.go @@ -23,7 +23,7 @@ func TestNewFactory(t *testing.T) { t.Errorf("factory.options = %v, expected %v", factory.options, &Options{}) } - slave, _ := factory.New(nil) + slave, _ := factory.New(nil, nil) lcmd := slave.(*LocalCommand) if lcmd.closeSignal != 123 { t.Errorf("lcmd.closeSignal = %v, expected %v", lcmd.closeSignal, 123) @@ -40,7 +40,7 @@ func TestFactoryNew(t *testing.T) { return } - slave, err := factory.New(nil) + slave, err := factory.New(nil, nil) if err != nil { t.Errorf("factory.New() returned error") return diff --git a/server/handlers.go b/server/handlers.go index 5347ab6..a0acec1 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -72,7 +72,7 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance } defer conn.Close() - err = server.processWSConn(ctx, conn) + err = server.processWSConn(ctx, conn, r.Header) switch err { case ctx.Err(): @@ -87,7 +87,7 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance } } -func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn) error { +func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn, headers map[string][]string) error { typ, initLine, err := conn.ReadMessage() if err != nil { return errors.Wrapf(err, "failed to authenticate websocket connection") @@ -116,7 +116,7 @@ func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn) e } params := query.Query() var slave Slave - slave, err = server.factory.New(params) + slave, err = server.factory.New(params, headers) if err != nil { return errors.Wrapf(err, "failed to create backend") } diff --git a/server/slave.go b/server/slave.go index 52cd9fe..db9d731 100644 --- a/server/slave.go +++ b/server/slave.go @@ -13,5 +13,5 @@ type Slave interface { type Factory interface { Name() string - New(params map[string][]string) (Slave, error) + New(params map[string][]string, headers map[string][]string) (Slave, error) } From e8f5de568d20ad817cb00dcd83fd9b431af7dbee Mon Sep 17 00:00:00 2001 From: llach Date: Thu, 15 Sep 2022 16:15:54 +0000 Subject: [PATCH 2/3] task: pass headers --- server/handlers.go | 6 +++++- server/options.go | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/server/handlers.go b/server/handlers.go index 1f985fd..3393b22 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -72,7 +72,11 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance } defer conn.Close() - err = server.processWSConn(ctx, conn, r.Header) + if server.options.PassHeaders { + err = server.processWSConn(ctx, conn, r.Header) + } else { + err = server.processWSConn(ctx, conn, nil) + } switch err { case ctx.Err(): diff --git a/server/options.go b/server/options.go index b7dc3d3..b51b03f 100644 --- a/server/options.go +++ b/server/options.go @@ -26,6 +26,7 @@ type Options struct { Once bool `hcl:"once" flagName:"once" flagDescribe:"Accept only one client and exit on disconnection" default:"false"` Timeout int `hcl:"timeout" flagName:"timeout" flagDescribe:"Timeout seconds for waiting a client(0 to disable)" default:"0"` PermitArguments bool `hcl:"permit_arguments" flagName:"permit-arguments" flagDescribe:"Permit clients to send command line arguments in URL (e.g. http://example.com:8080/?arg=AAA&arg=BBB)" default:"false"` + PassHeaders bool `hcl:"pass_headers" flagName:"pass-headers" flagDescribe:"Pass HTTP request headers as environment variables (e.g. Host becomes HTTP_HOST)" default:"false"` Width int `hcl:"width" flagName:"width" flagDescribe:"Static width of the screen, 0(default) means dynamically resize" default:"0"` Height int `hcl:"height" flagName:"height" flagDescribe:"Static height of the screen, 0(default) means dynamically resize" default:"0"` WSOrigin string `hcl:"ws_origin" flagName:"ws-origin" flagDescribe:"A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default" default:""` From d92d17c15d2743cf80bd9182a6df0b4ea4ed4649 Mon Sep 17 00:00:00 2001 From: llach Date: Thu, 15 Sep 2022 16:46:39 +0000 Subject: [PATCH 3/3] task: change exmaple to use Cookie --- server/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/options.go b/server/options.go index b51b03f..b03d78d 100644 --- a/server/options.go +++ b/server/options.go @@ -26,7 +26,7 @@ type Options struct { Once bool `hcl:"once" flagName:"once" flagDescribe:"Accept only one client and exit on disconnection" default:"false"` Timeout int `hcl:"timeout" flagName:"timeout" flagDescribe:"Timeout seconds for waiting a client(0 to disable)" default:"0"` PermitArguments bool `hcl:"permit_arguments" flagName:"permit-arguments" flagDescribe:"Permit clients to send command line arguments in URL (e.g. http://example.com:8080/?arg=AAA&arg=BBB)" default:"false"` - PassHeaders bool `hcl:"pass_headers" flagName:"pass-headers" flagDescribe:"Pass HTTP request headers as environment variables (e.g. Host becomes HTTP_HOST)" default:"false"` + PassHeaders bool `hcl:"pass_headers" flagName:"pass-headers" flagDescribe:"Pass HTTP request headers as environment variables (e.g. Cookie becomes HTTP_COOKIE)" default:"false"` Width int `hcl:"width" flagName:"width" flagDescribe:"Static width of the screen, 0(default) means dynamically resize" default:"0"` Height int `hcl:"height" flagName:"height" flagDescribe:"Static height of the screen, 0(default) means dynamically resize" default:"0"` WSOrigin string `hcl:"ws_origin" flagName:"ws-origin" flagDescribe:"A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default" default:""`