Patch 8.0.0312
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.
Files: src/channel.c, src/testdir/test_channel.vim, src/structs.h,
src/testdir/test_channel_pipe.py
*** ../vim-8.0.0311/src/channel.c 2017-01-14 17:04:33.950973940 +0100
--- src/channel.c 2017-02-06 21:52:01.086150732 +0100
***************
*** 1840,1878 ****
return OK;
}
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;
char_u *p;
if (next == NULL)
return FALSE;
! unused = reader->js_end - reader->js_buf - reader->js_used;
! if (unused > 0)
{
/* Prepend unused text. */
! len = (int)STRLEN(next);
! p = alloc(unused + len + 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);
vim_free(next);
next = p;
}
vim_free(reader->js_buf);
reader->js_buf = next;
- reader->js_used = 0;
return TRUE;
}
--- 1840,1881 ----
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 keeplen;
! int addlen;
char_u *p;
if (next == NULL)
return FALSE;
! keeplen = reader->js_end - reader->js_buf;
! if (keeplen > 0)
{
/* Prepend unused text. */
! addlen = (int)STRLEN(next);
! p = alloc(keeplen + addlen + 1);
if (p == NULL)
{
vim_free(next);
return FALSE;
}
! 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;
return TRUE;
}
***************
*** 1952,1967 ****
}
if (status == OK)
! chanpart->ch_waiting = FALSE;
else if (status == MAYBE)
{
! if (!chanpart->ch_waiting)
{
! /* First time encountering incomplete message, set a deadline of
! * 100 msec. */
! ch_log(channel, "Incomplete message - wait for more");
reader.js_used = 0;
! chanpart->ch_waiting = TRUE;
#ifdef WIN32
chanpart->ch_deadline = GetTickCount() + 100L;
#else
--- 1955,1974 ----
}
if (status == OK)
! chanpart->ch_wait_len = 0;
else if (status == MAYBE)
{
! size_t buflen = STRLEN(reader.js_buf);
!
! if (chanpart->ch_wait_len < buflen)
{
! /* 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_wait_len = buflen;
#ifdef WIN32
chanpart->ch_deadline = GetTickCount() + 100L;
#else
***************
*** 1992,1998 ****
if (timeout)
{
status = FAIL;
! chanpart->ch_waiting = FALSE;
}
else
{
--- 1999,2006 ----
if (timeout)
{
status = FAIL;
! chanpart->ch_wait_len = 0;
! ch_log(channel, "timed out");
}
else
{
***************
*** 2006,2012 ****
{
ch_error(channel, "Decoding failed - discarding input");
ret = FALSE;
! chanpart->ch_waiting = FALSE;
}
else if (reader.js_buf[reader.js_used] != NUL)
{
--- 2014,2020 ----
{
ch_error(channel, "Decoding failed - discarding input");
ret = FALSE;
! chanpart->ch_wait_len = 0;
}
else if (reader.js_buf[reader.js_used] != NUL)
{
***************
*** 3369,3375 ****
/* Wait for up to the timeout. If there was an incomplete message
* use the deadline for that. */
timeout = timeout_arg;
! if (chanpart->ch_waiting)
{
#ifdef WIN32
timeout = chanpart->ch_deadline - GetTickCount() + 1;
--- 3377,3383 ----
/* Wait for up to the timeout. If there was an incomplete message
* use the deadline for that. */
timeout = timeout_arg;
! if (chanpart->ch_wait_len > 0)
{
#ifdef WIN32
timeout = chanpart->ch_deadline - GetTickCount() + 1;
***************
*** 3389,3395 ****
{
/* Something went wrong, channel_parse_json() didn't
* discard message. Cancel waiting. */
! chanpart->ch_waiting = FALSE;
timeout = timeout_arg;
}
else if (timeout > timeout_arg)
--- 3397,3403 ----
{
/* Something went wrong, channel_parse_json() didn't
* discard message. Cancel waiting. */
! chanpart->ch_wait_len = 0;
timeout = timeout_arg;
}
else if (timeout > timeout_arg)
*** ../vim-8.0.0311/src/testdir/test_channel.vim 2017-01-08
13:38:53.028502710 +0100
--- src/testdir/test_channel.vim 2017-02-06 21:55:37.572539457 +0100
***************
*** 1141,1147 ****
let dict = {'thisis': 'dict: '}
func dict.outHandler(chan, msg) dict
! let g:Ch_outmsg = self.thisis . a:msg
endfunc
func dict.errHandler(chan, msg) dict
let g:Ch_errmsg = self.thisis . a:msg
--- 1141,1151 ----
let dict = {'thisis': 'dict: '}
func dict.outHandler(chan, msg) dict
! if type(a:msg) == v:t_string
! let g:Ch_outmsg = self.thisis . a:msg
! else
! let g:Ch_outobj = a:msg
! endif
endfunc
func dict.errHandler(chan, msg) dict
let g:Ch_errmsg = self.thisis . a:msg
***************
*** 1161,1166 ****
--- 1165,1176 ----
call assert_equal("dict: hello", g:Ch_outmsg)
call WaitFor('g:Ch_errmsg != ""')
call assert_equal("dict: there", g:Ch_errmsg)
+
+ " Receive a json object split in pieces
+ unlet! g:Ch_outobj
+ call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\":
3|}]\n")
+ call WaitFor('exists("g:Ch_outobj")')
+ call assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)
finally
call job_stop(job)
endtry
*** ../vim-8.0.0311/src/structs.h 2017-02-02 22:59:22.583226973 +0100
--- src/structs.h 2017-02-06 21:47:04.116363189 +0100
***************
*** 1563,1571 ****
jsonq_T ch_json_head; /* header for circular json read queue */
int ch_block_id; /* ID that channel_read_json_block() is
waiting for */
! /* When ch_waiting is TRUE use ch_deadline to wait for incomplete message
! * to be complete. */
! int ch_waiting;
#ifdef WIN32
DWORD ch_deadline;
#else
--- 1563,1573 ----
jsonq_T ch_json_head; /* header for circular json read queue */
int ch_block_id; /* ID that channel_read_json_block() is
waiting for */
! /* When ch_wait_len is non-zero use ch_deadline to wait for incomplete
! * message to be complete. The value is the length of the incomplete
! * message when the deadline was set. If it gets longer (something was
! * received) the deadline is reset. */
! size_t ch_wait_len;
#ifdef WIN32
DWORD ch_deadline;
#else
*** ../vim-8.0.0311/src/testdir/test_channel_pipe.py 2016-06-05
16:01:21.000000000 +0200
--- src/testdir/test_channel_pipe.py 2017-02-06 21:12:08.116049258 +0100
***************
*** 29,34 ****
--- 29,39 ----
if typed.startswith("echo "):
print(typed[5:-1])
sys.stdout.flush()
+ if typed.startswith("echosplit "):
+ for part in typed[10:-1].split('|'):
+ sys.stdout.write(part)
+ sys.stdout.flush()
+ time.sleep(0.05)
if typed.startswith("double "):
print(typed[7:-1] + "\nAND " + typed[7:-1])
sys.stdout.flush()
*** ../vim-8.0.0311/src/version.c 2017-02-05 21:14:26.743355267 +0100
--- src/version.c 2017-02-06 21:14:41.890894810 +0100
***************
*** 766,767 ****
--- 766,769 ----
{ /* Add new patch number below this line */
+ /**/
+ 312,
/**/
--
If you only have a hammer, you tend to see every problem as a nail.
If you only have MS-Windows, you tend to solve every problem by rebooting.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.