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.

Raspunde prin e-mail lui