go-jarvis / rum-gonic

a gin based RESTful web framework, inspired by cobra
MIT License
0 stars 0 forks source link

[bug] rum.Static panic #9

Open tangx opened 2 years ago

tangx commented 2 years ago
    r.Static("/userindex", "./userindex")
runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:221 (0x44a846)
        panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:735 (0x44a816)
        sigpanic: panicmem()
/data/gopath/src/github.com/go-jarvis/rum-gonic/rum/fileserver.go:75 (0x89f919)
        (*StaticFS).Output: f, err := static.fs.Open(file)
/data/gopath/src/github.com/go-jarvis/rum-gonic/rum/group.go:159 (0x8a08c1)
        (*RouterGroup).handlerfunc.func1: ret, err := op.Output(c)
tangx commented 2 years ago

it cause by operator deepcopy function: https://github.com/go-jarvis/rum-gonic/blob/0d721423e8f585e8a64a63f983d59f6ee79c7207/rum/group.go#L145

static fileserver use a different to create

func newStaticFile(method, path, filepath string) *StaticFile {
    return &StaticFile{
        method:   method,
        path:     path,
        filepath: filepath,
    }
}

type StaticFile struct {
    method   string
    path     string
    filepath string
}
tangx commented 2 years ago

actually, here is the key problem: https://github.com/go-jarvis/rum-gonic/blob/0d721423e8f585e8a64a63f983d59f6ee79c7207/rum/operator.go#L39

the below code create a new operator, with zero value in all filed.

func (fact *OperatorFactory) NewOperator() Operator {
    opc := reflect.New(fact.Type).Interface().(Operator)
    return opc
}

when OperatorFactory create a new StaticFile or StaticFS operator , the filepath in Staticfile and fs in StaticFS are empty. so gin handler can not work.

type StaticFile struct {
    method   string
    path     string
    filepath string
}

func (static *StaticFile) Path() string {
    return static.path
}

func (static *StaticFile) Method() string {
    return static.method
}

that's why fs.Open(file) occur the panic.

runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:221 (0x44a846)
        panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:735 (0x44a816)
        sigpanic: panicmem()
/data/gopath/src/github.com/go-jarvis/rum-gonic/rum/fileserver.go:75 (0x89f919)
        (*StaticFS).Output: f, err := static.fs.Open(file)
/data/gopath/src/github.com/go-jarvis/rum-gonic/rum/group.go:159 (0x8a08c1)
        (*RouterGroup).handlerfunc.func1: ret, err := op.Output(c)
tangx commented 2 years ago

reason of why can rum register handler successful

https://github.com/go-jarvis/rum-gonic/blob/0d721423e8f585e8a64a63f983d59f6ee79c7207/rum/group.go#L127

  1. path and method value are both get from the origin operator.
  2. the copy operator function is called in handler generator r.handlerfunc(op) . In this step, handler generator return a valid gin HandlerFunc, but it may occur panic.
    for _, method := range httpx.UnmarshalMethods(mop.Method()) {
        method = strings.TrimSpace(method)
        // 有错就要报,免得找不到
        // if len(method) == 0 {
        //  continue
        // }
        r.ginRG.Handle(method, path, r.handlerfunc(op))
    }
tangx commented 2 years ago

sollution

https://github.com/go-jarvis/rum-gonic/commit/1be6d62ea66409a390d3887249628e3149394d4f

new interface OperatorDeepcopier, call origin Deepcopy method to create new operator

// DeepCopyOperator return a deepcopied operator
func DeepCopyOperator(op Operator) Operator {
    if copier, ok := op.(OperatorDeepcopier); ok {
        return copier.Deepcopy()
    }

    return NewOperatorFactory(op).New()
}

type OperatorDeepcopier interface {
    Deepcopy() Operator
}

func (static *StaticFile) Deepcopy() Operator {
    return &StaticFile{
        method:   static.method,
        path:     static.path,
        filepath: static.filepath,
    }
}