gofiber / websocket

⚠️ Deprecated repository, available within Fiber Contrib.
https://github.com/gofiber/contrib/tree/main/websocket
MIT License
288 stars 25 forks source link

Trying to use session middleware #152

Open idc77 opened 1 year ago

idc77 commented 1 year ago

I'm trying to use the session middleware with websocket

cmd using cobra

package cmd

import (
    "code.local/idc77/socktest/websocket/handler"
    "errors"
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/session"
    "github.com/gofiber/websocket/v2"
    "github.com/spf13/cobra"
    "net"
    "os"
    "strings"
)

const (
    prefixTCP  = "tcp:"
    prefixUNIX = "unix:"
)

var websocketAddr = ""

// websocketCmd represents the websocket command
var websocketCmd = &cobra.Command{
    Use:   "websocket",
    Short: "A brief description of your command",
    RunE: func(cmd *cobra.Command, args []string) error {
        app := fiber.New()
        sconf := session.ConfigDefault
        store := session.New(sconf)
        app.Use("/ws", func(c *fiber.Ctx) error {
            sess, e := store.Get(c)
            if e != nil {
                return e
            }
            // IsWebSocketUpgrade returns true if the client
            // requested upgrade to the WebSocket protocol.
            if websocket.IsWebSocketUpgrade(c) {
                c.Locals("sess", sess)
                return c.Next()
            }
            return fiber.ErrUpgradeRequired
        })
        h := handler.NewHandler()
        ws := app.Group("/ws")
        ws.Get("/test", websocket.New(h.Gate))
        return fiberServe(app)
    },
}

func init() {
    rootCmd.AddCommand(websocketCmd)
    websocketCmd.Flags().StringVar(&websocketAddr, "addr", "tcp:127.0.0.1:3000", "tpc:addr:port or unix:/path/to/socket")
}

func fiberServe(r *fiber.App) error {
    if strings.HasPrefix(websocketAddr, prefixTCP) {
        addr := strings.TrimPrefix(websocketAddr, prefixTCP)
        return r.Listen(addr)
    } else if strings.HasPrefix(websocketAddr, prefixUNIX) {
        addr := strings.TrimPrefix(websocketAddr, prefixUNIX)
        if _, e := os.Stat(addr); errors.Is(e, os.ErrNotExist) {
            l, el := net.Listen("unix", addr)
            if el != nil {
                return el
            }
            return r.Listener(l)
        } else {
            if e := os.Remove(addr); e != nil {
                return e
            } else {
                l, el := net.Listen("unix", addr)
                if el != nil {
                    return el
                }
                return r.Listener(l)
            }
        }
    } else {
        return nil
    }
}

websocket/handler/handler.go

package handler

import (
    "github.com/gofiber/fiber/v2/middleware/session"
    "github.com/gofiber/websocket/v2"
    jsoniter "github.com/json-iterator/go"
    "log"
)

const (
    CommandSet = "SET"
    CommandGet = "GET"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type Handler struct {
}

func NewHandler() *Handler {
    h := new(Handler)
    return h
}

type Message struct {
    Command string `json:"command"`
    Key     string `json:"key,omitempty"`
    Value   string `json:"value,omitempty"`
}

type Response struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}

func (h *Handler) Gate(c *websocket.Conn) {
    sess, ok := c.Locals("sess").(*session.Session)
    if !ok {
        log.Println("sesson not ok")
    }
    for {
        mt, msg, e := c.ReadMessage()
        if e != nil {
            log.Println("read:", e)
            break
        }
        m := new(Message)
        if e := json.Unmarshal(msg, m); e != nil {
            log.Println("marshall", e)
            break
        }
        switch m.Command {
        case CommandSet:
            sess.Set(m.Key, m.Value)
            if e := sess.Save(); e != nil {
                log.Println("session save:", e)
                break
            }
        case CommandGet:
            rsp := new(Response)
            rsp.Key = m.Key
            rsp.Value = sess.Get(m.Key).(string)
            rspb, e := json.Marshal(rsp)
            if e != nil {
                log.Println("unmarshall", e)
            }
            if e := c.WriteMessage(mt, rspb); e != nil {
                log.Println("write:", e)
                break
            }
        default:

        }
        log.Printf("recv: %d, %s", mt, msg)
    }
}

result


panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xaef4c2]

goroutine 11 [running]:
github.com/gofiber/fiber/v2.(*Ctx).Response(...)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/v2@v2.42.0/ctx.go:526
github.com/gofiber/fiber/v2/middleware/session.(*Session).setSession(0xc00027e500)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/v2@v2.42.0/middleware/session/session.go:213 +0x662
github.com/gofiber/fiber/v2/middleware/session.(*Session).Save(0xc00027e500)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/v2@v2.42.0/middleware/session/session.go:150 +0x6a
code.local/idc77/socktest/websocket/handler.(*Handler).Gate(0x400?, 0xc000318570)
        /home/idc77/go/src/code.local/idc77/socktest/websocket/handler/handler.go:55 +0x432
github.com/gofiber/websocket/v2.New.func2.4(0x0?)
        /home/idc77/go/pkg/mod/github.com/gofiber/websocket/v2@v2.1.4/websocket.go:121 +0x75
github.com/fasthttp/websocket.(*FastHTTPUpgrader).Upgrade.func1({0xddc298, 0xc000318660})
        /home/idc77/go/pkg/mod/github.com/fasthttp/websocket@v1.5.1/server_fasthttp.go:201 +0x1ad
github.com/valyala/fasthttp.hijackConnHandler(0x0?, {0xdd2fc0?, 0xc000332000}, {0xddc3f8, 0xc0000156d8}, 0xc0001d1600, 0xc00027e5c0)
        /home/idc77/go/pkg/mod/github.com/valyala/fasthttp@v1.44.0/server.go:2512 +0x68
created by github.com/valyala/fasthttp.(*Server).serveConn
        /home/idc77/go/pkg/mod/github.com/valyala/fasthttp@v1.44.0/server.go:2467 +0x1c5c

Process finished with the exit code 2

On yeah payload, I forgot.

I used https://websocketking.com/ to connect to ws://127.0.0.1:3000/ws/test with the payload

{
  "command": "SET",
  "key": "t1",
  "value": "100"
}
idc77 commented 1 year ago

Well it's clear that once the connection has been upgraded no cookie can be set. So when I remove the session.Save() it doesn't segfault And it's also safe for individual connections. But don't I have to save a session?