Skip to content
This repository
Browse code

Fixed UTF-8 handling (#14).

Some time ago SLIME wire protocol was changed to specify
number of bytes in the header, and here we were still counting
chars which was leading to protocol errors.
  • Loading branch information...
commit b31b86ea03cad2cff4843b73f241840b6478b52f 1 parent 4259fdd
Ivan Shvedunov authored February 22, 2012
16  swank-protocol-tests.js
@@ -44,7 +44,7 @@ var parser = new swp.SwankParser(
44 44
 function feed (text) {
45 45
   for (var i = 1; i < arguments.length; ++i)
46 46
     expected.push(arguments[i]);
47  
-  parser.execute(text);
  47
+  parser.execute(new Buffer(text));
48 48
   assert.equal(0, expected.length);
49 49
 }
50 50
 
@@ -68,9 +68,19 @@ feed(" \"COMMON-LISP-USER\" t 1");
68 68
 feed(")",
69 69
      list(S(":emacs-rex"), list(S("swank:connection-info")),
70 70
           "COMMON-LISP-USER", S("t"), 1));
  71
+feed('000047(:emacs-rex (:listener-eval "\\"\u0439\u0446\u0443\\"") "FIREFOX-9.0" :repl-thread 4)',
  72
+     list(S(":emacs-rex"),
  73
+                        list(S(":listener-eval"),
  74
+                             '"\u0439\u0446\u0443"'),
  75
+                        "FIREFOX-9.0", S(":repl-thread"), 4));
71 76
 
72 77
 assert.equal(
73 78
   "000015(:return (:ok nil) 1)",
74  
-  swp.buildMessage(list(S(":return"), list(S(":ok"), nil), 1)));
  79
+  swp.buildMessage(list(S(":return"), list(S(":ok"), nil), 1)).toString());
75 80
 
76  
-// TBD: check unicode string handling (use \uxxxx notation)
  81
+assert.equal(
  82
+  '000047(:emacs-rex (:listener-eval "\\"\u0439\u0446\u0443\\"") "FIREFOX-9.0" :repl-thread 4)',
  83
+  swp.buildMessage(list(S(":emacs-rex"),
  84
+                        list(S(":listener-eval"),
  85
+                             '"\u0439\u0446\u0443"'),
  86
+                        "FIREFOX-9.0", S(":repl-thread"), 4)).toString());
57  swank-protocol.js
@@ -33,51 +33,52 @@ const DUMMY_HEADER = "000000";
33 33
 const MAX_MESSAGE_SIZE = 10 * 1024 * 1024;
34 34
 
35 35
 function SwankParser (onMessage) {
36  
-  this.needChars = HEADER_LEN;
37  
-  this.handleData = this.handleHeader;
38  
-  this.stash = "";
39 36
   this.onMessage = onMessage;
  37
+  this.resetBuffer();
40 38
 };
41 39
 
42 40
 // FIXME: proper error handling (handle both packet parsing and reader errors)
43 41
 
44  
-SwankParser.prototype.execute = function execute (text) {
  42
+SwankParser.prototype.resetBuffer = function resetBuffer (len, handler) {
  43
+  len = len || HEADER_LEN;
  44
+  this.needChars = len;
  45
+  this.handleData = handler || this.handleHeader;
  46
+  this.stash = new Buffer(len);
  47
+  this.pos = 0;
  48
+};
  49
+
  50
+SwankParser.prototype.execute = function execute (buffer) {
45 51
   var offset = 0;
46  
-  while (offset < text.length)
47  
-    offset += this.handleContent(text, offset);
  52
+  while (offset < buffer.length)
  53
+    offset += this.handleContent(buffer, offset);
48 54
 };
49 55
 
50  
-SwankParser.prototype.handleContent = function handleContent (text, offset) {
51  
-  var stashLen = this.stash.length;
52  
-  var avail = Math.min(this.needChars, text.length + stashLen - offset);
53  
-  var message = this.stash + text.substring(offset, offset + avail - stashLen);
54  
-  if (avail < this.needChars)
55  
-    this.stash = message;
56  
-  else {
57  
-    this.stash = "";
58  
-    this.handleData(message);
59  
-  }
60  
-  return message.length - stashLen;
  56
+SwankParser.prototype.handleContent = function handleContent (buffer, offset) {
  57
+  var newPos = Math.min(this.needChars, this.pos + buffer.length - offset);
  58
+  var bytesToCopy = newPos - this.pos;
  59
+  buffer.copy(this.stash, this.pos, offset, offset + bytesToCopy);
  60
+  this.pos = newPos;
  61
+  if (this.pos == this.needChars)
  62
+    this.handleData();
  63
+  return bytesToCopy; // stashLen + newPos - stashLen
61 64
 };
62 65
 
63  
-SwankParser.prototype.handleHeader = function handleHeader (str) {
64  
-  var count = parseInt(str, 16) || 0;
65  
-  if (count > 0 && count < MAX_MESSAGE_SIZE) {
66  
-    this.needChars = count;
67  
-    this.handleData = this.handleMessage;
68  
-  } else
69  
-    this.needChars = HEADER_LEN; // FIXME: handle errors
  66
+SwankParser.prototype.handleHeader = function handleHeader () {
  67
+  var count = parseInt(this.stash.toString(), 16) || 0;
  68
+  if (count > 0 && count < MAX_MESSAGE_SIZE)
  69
+    this.resetBuffer(count, this.handleMessage);
  70
+  else
  71
+    this.resetBuffer();
70 72
 };
71 73
 
72 74
 SwankParser.prototype.handleMessage = function handleMessage (str) {
73  
-  this.onMessage(readFromString(str)); // FIXME: handle errors
74  
-  this.needChars = HEADER_LEN;
75  
-  this.handleData = this.handleHeader;
  75
+  this.onMessage(readFromString(this.stash.toString())); // FIXME: handle errors
  76
+  this.resetBuffer();
76 77
 };
77 78
 
78 79
 function buildMessage (obj) {
79 80
   var str = obj.toString();
80  
-  var lenStr = "" + str.length.toString(16);
  81
+  var lenStr = "" + Buffer.byteLength(str).toString(16);
81 82
   while (lenStr.length < HEADER_LEN)
82 83
     lenStr = "0" + lenStr;
83 84
   return lenStr + str;
7  swank.js
@@ -43,7 +43,6 @@ var executive = new swh.Executive({ config: cfg });
43 43
 
44 44
 var swankServer = net.createServer(
45 45
   function (stream) {
46  
-    stream.setEncoding("utf-8");
47 46
     var handler = new swh.Handler(executive);
48 47
     var parser = new swp.SwankParser(
49 48
       function onMessage (message) {
@@ -51,9 +50,9 @@ var swankServer = net.createServer(
51 50
       });
52 51
     handler.on(
53 52
       "response", function (response) {
54  
-        var responseText = swp.buildMessage(response);
55  
-        console.log("response: %s", responseText);
56  
-        stream.write(responseText);
  53
+        var responseBuf = swp.buildMessage(response);
  54
+        console.log("response: %s", responseBuf.toString());
  55
+        stream.write(responseBuf);
57 56
       });
58 57
     stream.on(
59 58
       "data", function (data) {

0 notes on commit b31b86e

Please sign in to comment.
Something went wrong with that request. Please try again.