diff --git a/date_test.go b/date_test.go index 90440021..64e08224 100644 --- a/date_test.go +++ b/date_test.go @@ -64,7 +64,7 @@ func TestEncDate(t *testing.T) { } func testDateFramework(t *testing.T, method string, expected time.Time) { - r, e := decodeJavaResponse(method, "") + r, e := decodeJavaResponse(method, "", false) if e != nil { t.Errorf("%s: decode fail with error %+v", method, e) return diff --git a/decode.go b/decode.go index 859cbd69..4bb782d9 100644 --- a/decode.go +++ b/decode.go @@ -33,6 +33,7 @@ type Decoder struct { // todo: map typeRefs *TypeRefs classInfoList []classInfo + isSkip bool } // Error part @@ -46,6 +47,11 @@ func NewDecoder(b []byte) *Decoder { return &Decoder{reader: bufio.NewReader(bytes.NewReader(b)), typeRefs: &TypeRefs{records: map[string]bool{}}} } +// NewDecoder generate a decoder instance with skip +func NewDecoderWithSkip(b []byte) *Decoder { + return &Decoder{reader: bufio.NewReader(bytes.NewReader(b)), typeRefs: &TypeRefs{records: map[string]bool{}}, isSkip: true} +} + ///////////////////////////////////////// // utilities ///////////////////////////////////////// @@ -232,5 +238,8 @@ func (t *TypeRefs) appendTypeRefs(name string, p reflect.Type) { } func (t *TypeRefs) Get(index int) reflect.Type { + if len(t.typeRefs) <= index { + return nil + } return t.typeRefs[index] } diff --git a/decode_test.go b/decode_test.go index e877b521..1a501c16 100644 --- a/decode_test.go +++ b/decode_test.go @@ -70,9 +70,14 @@ func getJavaReply(method, className string) []byte { return out } -func decodeJavaResponse(method, className string) (interface{}, error) { +func decodeJavaResponse(method, className string, skip bool) (interface{}, error) { b := getJavaReply(method, className) - d := NewDecoder(b) + var d *Decoder + if skip { + d = NewDecoderWithSkip(b) + } else { + d = NewDecoder(b) + } r, e := d.Decode() if e != nil { return nil, e @@ -81,11 +86,15 @@ func decodeJavaResponse(method, className string) (interface{}, error) { } func testDecodeFramework(t *testing.T, method string, expected interface{}) { - testDecodeJavaData(t, method, "", expected) + testDecodeJavaData(t, method, "", false, expected) +} + +func testDecodeFrameworkWithSkip(t *testing.T, method string, expected interface{}) { + testDecodeJavaData(t, method, "", true, expected) } -func testDecodeJavaData(t *testing.T, method, className string, expected interface{}) { - r, e := decodeJavaResponse(method, className) +func testDecodeJavaData(t *testing.T, method, className string, skip bool, expected interface{}) { + r, e := decodeJavaResponse(method, className, skip) if e != nil { t.Errorf("%s: decode fail with error %v", method, e) return @@ -101,7 +110,7 @@ func testDecodeJavaData(t *testing.T, method, className string, expected interfa } func testDecodeFrameworkFunc(t *testing.T, method string, expected func(interface{})) { - r, e := decodeJavaResponse(method, "") + r, e := decodeJavaResponse(method, "", false) if e != nil { t.Errorf("%s: decode fail with error %v", method, e) return diff --git a/hessian.go b/hessian.go index 8fb34aea..759293b5 100644 --- a/hessian.go +++ b/hessian.go @@ -32,6 +32,7 @@ const ( PackageHeartbeat = PackageType(0x08) PackageRequest_TwoWay = PackageType(0x10) PackageResponse_Exception = PackageType(0x20) + PackageType_BitSize = 0x2f ) // PackageType ... @@ -70,6 +71,15 @@ func NewHessianCodec(reader *bufio.Reader) *HessianCodec { } } +// NewHessianCodec generate a new hessian codec instance +func NewHessianCodecCustom(pkgType PackageType, reader *bufio.Reader, bodyLen int) *HessianCodec { + return &HessianCodec{ + pkgType: pkgType, + reader: reader, + bodyLen: bodyLen, + } +} + func (h *HessianCodec) Write(service Service, header DubboHeader, body interface{}) ([]byte, error) { switch header.Type { case PackageHeartbeat: @@ -173,7 +183,7 @@ func (h *HessianCodec) ReadBody(rspObj interface{}) error { return perrors.WithStack(err) } - switch h.pkgType & 0x2f { + switch h.pkgType & PackageType_BitSize { case PackageResponse | PackageHeartbeat | PackageResponse_Exception, PackageResponse | PackageResponse_Exception: decoder := NewDecoder(buf[:]) exception, err := decoder.Decode() @@ -189,13 +199,13 @@ func (h *HessianCodec) ReadBody(rspObj interface{}) error { case PackageRequest | PackageHeartbeat, PackageResponse | PackageHeartbeat: case PackageRequest: if rspObj != nil { - if err = unpackRequestBody(buf, rspObj); err != nil { + if err = unpackRequestBody(NewDecoder(buf[:]), rspObj); err != nil { return perrors.WithStack(err) } } case PackageResponse: if rspObj != nil { - if err = unpackResponseBody(buf, rspObj); err != nil { + if err = unpackResponseBody(NewDecoder(buf[:]), rspObj); err != nil { return perrors.WithStack(err) } } @@ -203,3 +213,35 @@ func (h *HessianCodec) ReadBody(rspObj interface{}) error { return nil } + +// ignore body, but only read attachments +func (h *HessianCodec) ReadAttachments() (map[string]string, error) { + if h.reader.Buffered() < h.bodyLen { + return nil, ErrBodyNotEnough + } + buf, err := h.reader.Peek(h.bodyLen) + if err != nil { + return nil, perrors.WithStack(err) + } + _, err = h.reader.Discard(h.bodyLen) + if err != nil { // this is impossible + return nil, perrors.WithStack(err) + } + + switch h.pkgType & PackageType_BitSize { + case PackageRequest: + rspObj := make([]interface{}, 7) + if err = unpackRequestBody(NewDecoderWithSkip(buf[:]), rspObj); err != nil { + return nil, perrors.WithStack(err) + } + return rspObj[6].(map[string]string), nil + case PackageResponse: + rspObj := &Response{} + if err = unpackResponseBody(NewDecoderWithSkip(buf[:]), rspObj); err != nil { + return nil, perrors.WithStack(err) + } + return rspObj.Attachments, nil + } + + return nil, nil +} diff --git a/object.go b/object.go index 71de3c15..58fe5d8b 100644 --- a/object.go +++ b/object.go @@ -470,6 +470,7 @@ func (d *Decoder) getStructDefByIndex(idx int) (reflect.Type, classInfo, error) ok bool cls classInfo s structInfo + err error ) if len(d.classInfoList) <= idx || idx < 0 { @@ -478,7 +479,10 @@ func (d *Decoder) getStructDefByIndex(idx int) (reflect.Type, classInfo, error) cls = d.classInfoList[idx] s, ok = getStructInfo(cls.javaName) if !ok { - return nil, cls, perrors.Errorf("can not find go type name %s in registry", cls.javaName) + if !d.isSkip { + err = perrors.Errorf("can not find go type name %s in registry", cls.javaName) + } + return nil, cls, err } return s.typ, cls, nil @@ -506,6 +510,15 @@ func (d *Decoder) decEnum(javaName string, flag int32) (JavaEnum, error) { return enumValue, nil } +// skip this object +func (d *Decoder) skip(cls classInfo) error { + if len(cls.fieldNameList) < 1 { + return nil + } + _, err := d.DecodeValue() + return err +} + func (d *Decoder) decObject(flag int32) (interface{}, error) { var ( tag byte @@ -549,6 +562,9 @@ func (d *Decoder) decObject(flag int32) (interface{}, error) { if err != nil { return nil, err } + if typ == nil { + return nil, d.skip(cls) + } if typ.Implements(javaEnumType) { return d.decEnum(cls.javaName, TAG_READ) } @@ -560,6 +576,9 @@ func (d *Decoder) decObject(flag int32) (interface{}, error) { if err != nil { return nil, err } + if typ == nil { + return nil, d.skip(cls) + } if typ.Implements(javaEnumType) { return d.decEnum(cls.javaName, TAG_READ) } diff --git a/object_test.go b/object_test.go index 7e3068ef..ae6a537d 100644 --- a/object_test.go +++ b/object_test.go @@ -417,7 +417,7 @@ func TestDecodeJavaTupleObject(t *testing.T) { RegisterPOJO(tuple) - testDecodeJavaData(t, "getTheTuple", "test.tuple.TupleProviderImpl", tuple) + testDecodeJavaData(t, "getTheTuple", "test.tuple.TupleProviderImpl", false, tuple) } func TestEncodeDecodeTuple(t *testing.T) { @@ -525,3 +525,33 @@ func doTestBasePointer(t *testing.T, base *BasePointer, expected *BasePointer) { t.Errorf("expect: %v, but get: %v", base, decObj) } } + +func TestSkip(t *testing.T) { + // clear pojo + pojoRegistry = POJORegistry{ + j2g: make(map[string]string), + registry: make(map[string]structInfo), + } + testDecodeFrameworkWithSkip(t, "replyObject_0", nil) + testDecodeFrameworkWithSkip(t, "replyObject_1", nil) + testDecodeFrameworkWithSkip(t, "replyObject_16", make([]interface{}, 17)) + testDecodeFrameworkWithSkip(t, "replyObject_2a", make([]interface{}, 2)) + testDecodeFrameworkWithSkip(t, "replyObject_3", nil) + + testDecodeFrameworkWithSkip(t, "replyTypedMap_0", make(map[interface{}]interface{})) + + testDecodeFrameworkWithSkip(t, "replyTypedFixedList_0", make([]string, 0)) + testDecodeFrameworkWithSkip(t, "replyUntypedFixedList_0", []interface{}{}) + + testDecodeFrameworkWithSkip(t, "customReplyTypedFixedListHasNull", make([]Object, 3)) + testDecodeFrameworkWithSkip(t, "customReplyTypedVariableListHasNull", make([]Object, 3)) + testDecodeFrameworkWithSkip(t, "customReplyUntypedFixedListHasNull", make([]interface{}, 3)) + testDecodeFrameworkWithSkip(t, "customReplyUntypedVariableListHasNull", make([]interface{}, 3)) + + testDecodeFrameworkWithSkip(t, "customReplyTypedFixedList_A0", make([]interface{}, 3)) + testDecodeFrameworkWithSkip(t, "customReplyTypedVariableList_A0", make([]interface{}, 3)) + + testDecodeFrameworkWithSkip(t, "customReplyTypedFixedList_Test", nil) + + testDecodeFrameworkWithSkip(t, "customReplyTypedFixedList_Object", make([]Object, 1)) +} diff --git a/ref.go b/ref.go index e9c08d91..a63689ca 100644 --- a/ref.go +++ b/ref.go @@ -165,7 +165,8 @@ func (d *Decoder) decRef(flag int32) (interface{}, error) { } if len(d.refs) <= int(i) { - return nil, ErrIllegalRefIndex + return nil, nil + //return nil, ErrIllegalRefIndex } // return the exact ref object, which maybe a _refHolder return d.refs[i], nil diff --git a/request.go b/request.go index f74a2246..8e0fb26d 100644 --- a/request.go +++ b/request.go @@ -259,7 +259,11 @@ END: } // hessian decode request body -func unpackRequestBody(buf []byte, reqObj interface{}) error { +func unpackRequestBody(decoder *Decoder, reqObj interface{}) error { + + if decoder == nil { + return perrors.Errorf("@decoder is nil") + } req, ok := reqObj.([]interface{}) if !ok { @@ -274,7 +278,6 @@ func unpackRequestBody(buf []byte, reqObj interface{}) error { dubboVersion, target, serviceVersion, method, argsTypes interface{} args []interface{} ) - decoder := NewDecoder(buf[:]) dubboVersion, err = decoder.Decode() if err != nil { diff --git a/response.go b/response.go index bf642d54..17f35280 100644 --- a/response.go +++ b/response.go @@ -153,9 +153,11 @@ func packResponse(header DubboHeader, ret interface{}) ([]byte, error) { } // hessian decode response body -func unpackResponseBody(buf []byte, resp interface{}) error { +func unpackResponseBody(decoder *Decoder, resp interface{}) error { // body - decoder := NewDecoder(buf[:]) + if decoder == nil { + return perrors.Errorf("@decoder is nil") + } rspType, err := decoder.Decode() if err != nil { return perrors.WithStack(err)