Merge pull request #56 from fangyincheng/master

Imp: add response
diff --git a/hessian.go b/hessian.go
index 2b05bc8..ff39d92 100644
--- a/hessian.go
+++ b/hessian.go
@@ -94,10 +94,10 @@
 
 	var err error
 
-	buf, err := h.reader.Peek(HEADER_LENGTH)
-	if err == bufio.ErrBufferFull {
+	if h.reader.Size() < HEADER_LENGTH {
 		return ErrHeaderNotEnough
 	}
+	buf, err := h.reader.Peek(HEADER_LENGTH)
 	if err != nil { // this is impossible
 		return perrors.WithStack(err)
 	}
@@ -165,10 +165,10 @@
 // ReadBody uses hessian codec to read response body
 func (h *HessianCodec) ReadBody(rspObj interface{}) error {
 
-	buf, err := h.reader.Peek(h.bodyLen)
-	if err == bufio.ErrBufferFull {
-		return ErrBodyNotEnough
+	if h.reader.Buffered() < h.bodyLen {
+		return ErrHeaderNotEnough
 	}
+	buf, err := h.reader.Peek(h.bodyLen)
 	if err != nil {
 		return perrors.WithStack(err)
 	}
@@ -191,7 +191,11 @@
 
 	case PackageResponse:
 		if rspObj != nil {
-			if err = unpackResponseBody(buf, rspObj); err != nil {
+			rsp, ok := rspObj.(*Response)
+			if !ok {
+				break
+			}
+			if err = unpackResponseBody(buf, rsp); err != nil {
 				return perrors.WithStack(err)
 			}
 		}
diff --git a/hessian_test.go b/hessian_test.go
index b68c780..e9d62c0 100644
--- a/hessian_test.go
+++ b/hessian_test.go
@@ -55,7 +55,7 @@
 	return resp, err
 }
 
-func doTestResponse(t *testing.T, packageType PackageType, responseStatus byte, body interface{}, decodedObject interface{}, assertFunc func()) {
+func doTestResponse(t *testing.T, packageType PackageType, responseStatus byte, body interface{}, decodedResponse *Response, assertFunc func()) {
 	resp, err := doTestHessianEncodeHeader(t, packageType, responseStatus, body)
 
 	codecR := NewHessianCodec(bufio.NewReader(bytes.NewReader(resp)))
@@ -74,9 +74,9 @@
 	assert.Equal(t, int64(1), h.ID)
 	assert.Equal(t, responseStatus, h.ResponseStatus)
 
-	err = codecR.ReadBody(decodedObject)
+	err = codecR.ReadBody(decodedResponse)
 	assert.Nil(t, err)
-	t.Log(decodedObject)
+	t.Log(decodedResponse)
 
 	if assertFunc != nil {
 		assertFunc()
@@ -84,38 +84,46 @@
 	}
 
 	in, _ := EnsureInterface(UnpackPtrValue(EnsurePackValue(body)), nil)
-	out, _ := EnsureInterface(UnpackPtrValue(EnsurePackValue(decodedObject)), nil)
+	out, _ := EnsureInterface(UnpackPtrValue(EnsurePackValue(decodedResponse.RspObj)), nil)
 	assert.Equal(t, in, out)
 }
 
 func TestResponse(t *testing.T) {
 	caseObj := Case{A: "a", B: 1}
+	decodedResponse := &Response{}
 
 	arr := []*Case{&caseObj}
 	var arrRes []interface{}
-	doTestResponse(t, PackageResponse, Response_OK, arr, &arrRes, func() {
+	decodedResponse.RspObj = &arrRes
+	doTestResponse(t, PackageResponse, Response_OK, arr, decodedResponse, func() {
 		assert.Equal(t, 1, len(arrRes))
 		assert.Equal(t, &caseObj, arrRes[0])
 	})
 
-	doTestResponse(t, PackageResponse, Response_OK, &Case{A: "a", B: 1}, &Case{}, nil)
+	decodedResponse.RspObj = &Case{}
+	doTestResponse(t, PackageResponse, Response_OK, &Case{A: "a", B: 1}, decodedResponse, nil)
 
 	s := "ok!!!!!"
 	strObj := ""
-	doTestResponse(t, PackageResponse, Response_OK, s, &strObj, nil)
+	decodedResponse.RspObj = &strObj
+	doTestResponse(t, PackageResponse, Response_OK, s, decodedResponse, nil)
 
 	var intObj int64
-	doTestResponse(t, PackageResponse, Response_OK, int64(3), &intObj, nil)
+	decodedResponse.RspObj = &intObj
+	doTestResponse(t, PackageResponse, Response_OK, int64(3), decodedResponse, nil)
 
 	boolObj := false
-	doTestResponse(t, PackageResponse, Response_OK, true, &boolObj, nil)
+	decodedResponse.RspObj = &boolObj
+	doTestResponse(t, PackageResponse, Response_OK, true, decodedResponse, nil)
 
 	strObj = ""
-	doTestResponse(t, PackageResponse, Response_SERVER_ERROR, "error!!!!!", &strObj, nil)
+	decodedResponse.RspObj = &strObj
+	doTestResponse(t, PackageResponse, Response_SERVER_ERROR, "error!!!!!", decodedResponse, nil)
 
 	mapObj := map[string][]*Case{"key": {&caseObj}}
 	mapRes := map[interface{}]interface{}{}
-	doTestResponse(t, PackageResponse, Response_OK, mapObj, &mapRes, func() {
+	decodedResponse.RspObj = &mapRes
+	doTestResponse(t, PackageResponse, Response_OK, mapObj, decodedResponse, func() {
 		c, ok := mapRes["key"]
 		if !ok {
 			assert.FailNow(t, "no key in decoded response map")
diff --git a/response.go b/response.go
index 5e0b0d8..2eb4b20 100644
--- a/response.go
+++ b/response.go
@@ -26,6 +26,12 @@
 	perrors "github.com/pkg/errors"
 )
 
+type Response struct {
+	RspObj    interface{}
+	Exception error
+	//Attachments map[string]string
+}
+
 // dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java
 // v2.7.1 line 256 encodeResponse
 // hessian encode response
@@ -120,7 +126,7 @@
 
 // hessian decode response body
 // todo: need to read attachments
-func unpackResponseBody(buf []byte, rspObj interface{}) error {
+func unpackResponseBody(buf []byte, response *Response) error {
 	// body
 	decoder := NewDecoder(buf[:])
 	rspType, err := decoder.Decode()
@@ -135,19 +141,21 @@
 			return perrors.WithStack(err)
 		}
 		if e, ok := expt.(error); ok {
-			return e
+			response.Exception = e
+			return nil
 		}
-		return perrors.Errorf("got exception: %+v", expt)
+		response.Exception = perrors.Errorf("got exception: %+v", expt)
+		return nil
 
 	case RESPONSE_VALUE, RESPONSE_VALUE_WITH_ATTACHMENTS:
 		rsp, err := decoder.Decode()
 		if err != nil {
 			return perrors.WithStack(err)
 		}
-		return perrors.WithStack(ReflectResponse(rsp, rspObj))
+		return perrors.WithStack(ReflectResponse(rsp, response.RspObj))
 
 	case RESPONSE_NULL_VALUE, RESPONSE_NULL_VALUE_WITH_ATTACHMENTS:
-		return perrors.New("Received null")
+		return nil
 	}
 
 	return nil