Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ var SERIALIZER_MAP = exports.SERIALIZER_MAP = {};
SERIALIZER_MAP[t] = 'Date';
});

[
'reply'
].forEach(function (t) {
SERIALIZER_MAP[t] = "Reply";
});

// http://www.devthought.com/2011/12/22/a-string-is-not-an-error/
function JavaExceptionError(obj, withType) {
Error.call(this);
Expand Down
52 changes: 50 additions & 2 deletions lib/v1/decoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ proto._readSparseObject = function (withType) {
label = this.byteBuffer.getChar(this.byteBuffer.position());
}
// skip 'z' char
this.byteBuffer.position(this.byteBuffer.position() + 1);
this.byteBuffer.skip(1);

// default type info
if (withType) {
Expand Down Expand Up @@ -461,7 +461,7 @@ proto._readNoLengthArray = function (withType, type) {
label = this.byteBuffer.getChar(this.byteBuffer.position());
}
// skip 'z' char
this.byteBuffer.position(this.byteBuffer.position() + 1);
this.byteBuffer.skip(1);

arr = withType
? { $class: type, $: arr }
Expand Down Expand Up @@ -561,6 +561,54 @@ utils.addByteCodes(BYTE_CODES, [
0x52,
], 'readRef');

/**
* read an call from buffer
*
* v1.0
* ```
* call ::= c(x63) x01 x00 header* m b16 b8 method-string (object)* z
* ```
*
* @return {Object}
* @api public
*/
proto.readCall = function(withType) {
this._checkLabel('readCall', 'c');

if (this.byteBuffer.get() !== 0x01 || this.byteBuffer.get() !== 0x00) {
new TypeError('hessian call error, expect code: 0x01 0x00');
}


var header = {};
var args = [];
var result = {header: header, arguments: args};

while (this.byteBuffer.getChar(this.byteBuffer.position()) === 'H') {
this.byteBuffer.skip(1); //skip 'H' char
var key = this.byteBuffer.readRawString(this.byteBuffer.getUInt16());
header[key] = this.read(withType);
}

this._checkLabel('readCall.method', 'm');
var methodLength = this.byteBuffer.getUInt16();
result.method = this.byteBuffer.readRawString(methodLength);

var label = this.byteBuffer.getChar(this.byteBuffer.position());
while (label !== 'z') {
args.push(this.read(withType));
label = this.byteBuffer.getChar(this.byteBuffer.position());
}
// skip 'z' char
this.byteBuffer.skip(1);

return result;
};

utils.addByteCodes(BYTE_CODES, [
0x63,
], 'readCall');

/**
* read any thing
*
Expand Down
72 changes: 72 additions & 0 deletions lib/v1/encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,4 +512,76 @@ proto.write = function (val) {
return this[method](val);
};

/**
* encode fault
* @param {fault} The defined fields are code, message, and detail. code is one of a short list of strings defined below. message is a user-readable message. detail is an object representing the exception. In Java, detail will be a serialized exception.
* @return {this}
*/
proto._writeFault = function(fault) {
this._assertType('writeFault', 'object', fault);

this._assertType('writeFault', 'string', fault.message);

var code = fault.code || 'ServiceException';

this.byteBuffer.putChar('f');
this.writeString('code');
this.writeString(code);
this.writeString('message');
this.writeString(fault.message);
if (fault.detail) {
this.writeString('detail');
this.writeObject(fault.detail);
}
return this;
};

proto._writeHeader = function(header) {
this._assertType('writeHeader', 'object', header);
this.byteBuffer.putChar('H');

if (SUPPORT_ES6_MAP && header instanceof Map) {
header.forEach(function (value, key) {
this.write(key);
this.write(value);
}, this);
} else {
var keys = Object.keys(header).sort();
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
this.writeString(k);
this.write(header[k]);
}
}
this.byteBuffer.putChar('z');
return this;
};

/**
* encode reply
* v1.0
* ```
* valid-reply ::= r x01 x00 header* object z
* fault-reply ::= r x01 x00 header* fault z
* ```
* @param {reply}
* @return {this}
*/
proto.writeReply = function(reply) {
this.byteBuffer.putChar('r').put(0x01).put(0x00);
if (reply.header) {
this._writeHeader(reply.header);
}

if (reply.fault) {
this._writeFault(reply.fault);
}else {
this.write(reply.value);
}

this.byteBuffer.putChar('z');
return this;
};


module.exports = Encoder;
113 changes: 113 additions & 0 deletions test/call-reply.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*!
* hessian.js - test/call-reply.test.js
*
* Copyright(c) 2016
* MIT Licensed
*
* Authors:
* tangzhi <[email protected]> (http://github.com/tangzhi)
*/

"use strict";

/**
* Module dependencies.
*/

var should = require('should');
var hessian = require('../');
var utils = require('./utils');

describe('call-reply.test.js', function () {
//c x01 x00
// m x00 x04 add2
// I x00 x00 x00 x02
// I x00 x00 x00 x03
// z
var simpleBuffer = Buffer.concat([
new Buffer(['c'.charCodeAt(0), 0x01, 0x00]),
new Buffer(['m'.charCodeAt(0), 0x00, 0x04]), new Buffer('add2'),
new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x00, 0x02]),
new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x00, 0x03]),
new Buffer('z')
]);

it('should read call [add2(2,3)]', function () {
hessian.decode(simpleBuffer).should.eql({
method: 'add2',
header: {},
arguments: [2,3]
});
});

it('should write reply 5', function() {
var buf = hessian.encode({$class:"reply", $:{value: 5}});
buf.should.be.a.Buffer;
// r x01 x00
// I x00 x00 x00 x05
// z
buf.should.eql(Buffer.concat([
new Buffer(['r'.charCodeAt(0), 0x01, 0x00]),
new Buffer(['I'.charCodeAt(0), 0x00, 0x00, 0x00, 0x05]),
new Buffer('z')
]));
});

it('should write reply fault', function() {
var fault = {
message: 'time out'
};
var buf = hessian.encode({$class:"reply", $:{fault: fault}});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只有 encode,decode 的测试用例呢?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我添加的代码不是双向的,我是按需添加的。
在decode里,我只实现了call;在encode里,我只实现了reply。
修改后的代码,测试了下和我现有环境能对接上,就没再完善了...

buf.should.be.a.Buffer;
// r x01 x00
// f
// S x00 x04 code
// S x00 x10 ServiceException
// S x00 x07 message
// S x00 x08 time out
// z
buf.should.eql(Buffer.concat([
new Buffer(['r'.charCodeAt(0), 0x01, 0x00]),
new Buffer('f'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x04]), new Buffer('code'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x10]), new Buffer('ServiceException'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x07]), new Buffer('message'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x08]), new Buffer('time out'),
new Buffer('z')
]));
});

it('should write reply fault with detail', function() {
var fault = {
message : 'time out',
detail : {
$class : 'java.io.FileNotFoundException',
$: {}
}
};
var buf = hessian.encode({$class:"reply", $:{fault: fault}});
buf.should.be.a.Buffer;
// r x01 x00
// f
// S x00 x04 code
// S x00 x10 ServiceException
// S x00 x07 message
// S x00 x08 time out
// S x00 x06 detail
// M t x00 x1d java.io.FileNotFoundException
// z
// z
buf.should.eql(Buffer.concat([
new Buffer(['r'.charCodeAt(0), 0x01, 0x00]),
new Buffer('f'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x04]), new Buffer('code'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x10]), new Buffer('ServiceException'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x07]), new Buffer('message'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x08]), new Buffer('time out'),
new Buffer(['S'.charCodeAt(0), 0x00, 0x06]), new Buffer('detail'),
new Buffer(['M'.charCodeAt(0), 't'.charCodeAt(0), 0x00, 0x1d]), new Buffer('java.io.FileNotFoundException'),
new Buffer('zz')
]));
});

});