diff src/channel.c @ 10845:c31782d57569 v8.0.0312

patch 8.0.0312: failure when a channel receives a split json message commit https://github.com/vim/vim/commit/88989cc381c764978f7d7c8e387f3efc21333b4b Author: Bram Moolenaar <Bram@vim.org> Date: Mon Feb 6 21:56:09 2017 +0100 patch 8.0.0312: failure when a channel receives a split json message Problem: When a json message arrives in pieces, the start is dropped and the decoding fails. Solution: Do not drop the start when it is still needed. (Kay Zheng) Add a test. Reset the timeout when something is received.
author Christian Brabandt <cb@256bit.org>
date Mon, 06 Feb 2017 22:00:05 +0100
parents 98ee4f22da6e
children 2f041b367cd9
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -1840,39 +1840,42 @@ channel_save(channel_T *channel, ch_part
     return OK;
 }
 
+/*
+ * Try to fill the buffer of "reader".
+ * Returns FALSE when nothing was added.
+ */
     static int
 channel_fill(js_read_T *reader)
 {
     channel_T	*channel = (channel_T *)reader->js_cookie;
     ch_part_T	part = reader->js_cookie_arg;
     char_u	*next = channel_get(channel, part);
-    int		unused;
-    int		len;
+    int		keeplen;
+    int		addlen;
     char_u	*p;
 
     if (next == NULL)
 	return FALSE;
 
-    unused = reader->js_end - reader->js_buf - reader->js_used;
-    if (unused > 0)
+    keeplen = reader->js_end - reader->js_buf;
+    if (keeplen > 0)
     {
 	/* Prepend unused text. */
-	len = (int)STRLEN(next);
-	p = alloc(unused + len + 1);
+	addlen = (int)STRLEN(next);
+	p = alloc(keeplen + addlen + 1);
 	if (p == NULL)
 	{
 	    vim_free(next);
 	    return FALSE;
 	}
-	mch_memmove(p, reader->js_buf + reader->js_used, unused);
-	mch_memmove(p + unused, next, len + 1);
+	mch_memmove(p, reader->js_buf, keeplen);
+	mch_memmove(p + keeplen, next, addlen + 1);
 	vim_free(next);
 	next = p;
     }
 
     vim_free(reader->js_buf);
     reader->js_buf = next;
-    reader->js_used = 0;
     return TRUE;
 }
 
@@ -1952,16 +1955,20 @@ channel_parse_json(channel_T *channel, c
     }
 
     if (status == OK)
-	chanpart->ch_waiting = FALSE;
+	chanpart->ch_wait_len = 0;
     else if (status == MAYBE)
     {
-	if (!chanpart->ch_waiting)
+	size_t buflen = STRLEN(reader.js_buf);
+
+	if (chanpart->ch_wait_len < buflen)
 	{
-	    /* First time encountering incomplete message, set a deadline of
-	     * 100 msec. */
-	    ch_log(channel, "Incomplete message - wait for more");
+	    /* First time encountering incomplete message or after receiving
+	     * more (but still incomplete): set a deadline of 100 msec. */
+	    ch_logn(channel,
+		    "Incomplete message (%d bytes) - wait 100 msec for more",
+		    buflen);
 	    reader.js_used = 0;
-	    chanpart->ch_waiting = TRUE;
+	    chanpart->ch_wait_len = buflen;
 #ifdef WIN32
 	    chanpart->ch_deadline = GetTickCount() + 100L;
 #else
@@ -1992,7 +1999,8 @@ channel_parse_json(channel_T *channel, c
 	    if (timeout)
 	    {
 		status = FAIL;
-		chanpart->ch_waiting = FALSE;
+		chanpart->ch_wait_len = 0;
+		ch_log(channel, "timed out");
 	    }
 	    else
 	    {
@@ -2006,7 +2014,7 @@ channel_parse_json(channel_T *channel, c
     {
 	ch_error(channel, "Decoding failed - discarding input");
 	ret = FALSE;
-	chanpart->ch_waiting = FALSE;
+	chanpart->ch_wait_len = 0;
     }
     else if (reader.js_buf[reader.js_used] != NUL)
     {
@@ -3369,7 +3377,7 @@ channel_read_json_block(
 	    /* Wait for up to the timeout.  If there was an incomplete message
 	     * use the deadline for that. */
 	    timeout = timeout_arg;
-	    if (chanpart->ch_waiting)
+	    if (chanpart->ch_wait_len > 0)
 	    {
 #ifdef WIN32
 		timeout = chanpart->ch_deadline - GetTickCount() + 1;
@@ -3389,7 +3397,7 @@ channel_read_json_block(
 		{
 		    /* Something went wrong, channel_parse_json() didn't
 		     * discard message.  Cancel waiting. */
-		    chanpart->ch_waiting = FALSE;
+		    chanpart->ch_wait_len = 0;
 		    timeout = timeout_arg;
 		}
 		else if (timeout > timeout_arg)