package orbit import ( "bytes" "encoding/json" "io" "strconv" "unicode/utf8" "github.com/coder/websocket" ) func parseWorkerFrame(kind websocket.MessageType, raw []byte) (workerFrame, error) { var f workerFrame if kind != websocket.MessageText || len(raw) > 512<<10 || validateWorkerJSON(raw) != nil { return f, ErrWorkerProtocol } // Envelope 字段严格区分大小写,防止 encoding/json 的大小写别名覆盖控制字段。 var fields map[string]json.RawMessage if json.Unmarshal(raw, &fields) != nil || fields == nil { return f, ErrWorkerProtocol } for k := range fields { switch k { case "protocol_version", "type", "message_id", "reply_to", "session_id", "body", "error": default: return f, ErrWorkerProtocol } } if json.Unmarshal(raw, &f) != nil || f.Version != "1" || !validID(f.MessageID) || f.ReplyTo != "" && !validID(f.ReplyTo) || f.SessionID != "" && !validID(f.SessionID) { return f, ErrWorkerProtocol } if f.Type == "error" { if f.Error == nil || !workerName(f.Error.Code, 64) || len(f.Error.Message) > 1024 || len(f.Body) > 0 { return f, ErrWorkerProtocol } } else if f.Error != nil || len(f.Body) == 0 || bytes.Equal(f.Body, []byte("null")) { return f, ErrWorkerProtocol } return f, nil } // validateWorkerJSON 拒绝重复键、过深嵌套及非法 Unicode,保留数字原文。 // 数值的业务范围仍由服务端规范化器最终验证;SDK 不经由 float64 重编码。 func validateWorkerJSON(raw []byte) error { if len(raw) == 0 || !utf8.Valid(raw) || !json.Valid(raw) || !workerUnicode(raw) { return ErrWorkerProtocol } d := json.NewDecoder(bytes.NewReader(raw)) d.UseNumber() var value func(int) error value = func(depth int) error { if depth > 32 { return ErrWorkerProtocol } t, err := d.Token() if err != nil { return err } switch t { case json.Delim('{'): keys := map[string]bool{} for d.More() { k, err := d.Token() if err != nil { return err } s, ok := k.(string) if !ok || keys[s] { return ErrWorkerProtocol } keys[s] = true if err := value(depth + 1); err != nil { return err } } _, err = d.Token() return err case json.Delim('['): for d.More() { if err := value(depth + 1); err != nil { return err } } _, err = d.Token() return err } return nil } if err := value(0); err != nil { return err } if _, err := d.Token(); err != io.EOF { return ErrWorkerProtocol } return nil } // JSON 的未配对 UTF-16 转义不能被静默替换为 U+FFFD。 func workerUnicode(raw []byte) bool { inside := false for i := 0; i < len(raw); i++ { if raw[i] == '"' { inside = !inside continue } if !inside || raw[i] != '\\' { continue } i++ if i >= len(raw) { return false } if raw[i] != 'u' { continue } if i+4 >= len(raw) { return false } n, err := strconv.ParseUint(string(raw[i+1:i+5]), 16, 16) if err != nil { return false } i += 4 if n < 0xd800 || n > 0xdfff { continue } if n > 0xdbff || i+6 >= len(raw) || raw[i+1] != '\\' || raw[i+2] != 'u' { return false } low, err := strconv.ParseUint(string(raw[i+3:i+7]), 16, 16) if err != nil || low < 0xdc00 || low > 0xdfff { return false } i += 6 } return !inside }