Mercurial > vim
comparison 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 |
comparison
equal
deleted
inserted
replaced
10844:1f16beccae3d | 10845:c31782d57569 |
---|---|
1838 fprintf(log_fd, "'\n"); | 1838 fprintf(log_fd, "'\n"); |
1839 } | 1839 } |
1840 return OK; | 1840 return OK; |
1841 } | 1841 } |
1842 | 1842 |
1843 /* | |
1844 * Try to fill the buffer of "reader". | |
1845 * Returns FALSE when nothing was added. | |
1846 */ | |
1843 static int | 1847 static int |
1844 channel_fill(js_read_T *reader) | 1848 channel_fill(js_read_T *reader) |
1845 { | 1849 { |
1846 channel_T *channel = (channel_T *)reader->js_cookie; | 1850 channel_T *channel = (channel_T *)reader->js_cookie; |
1847 ch_part_T part = reader->js_cookie_arg; | 1851 ch_part_T part = reader->js_cookie_arg; |
1848 char_u *next = channel_get(channel, part); | 1852 char_u *next = channel_get(channel, part); |
1849 int unused; | 1853 int keeplen; |
1850 int len; | 1854 int addlen; |
1851 char_u *p; | 1855 char_u *p; |
1852 | 1856 |
1853 if (next == NULL) | 1857 if (next == NULL) |
1854 return FALSE; | 1858 return FALSE; |
1855 | 1859 |
1856 unused = reader->js_end - reader->js_buf - reader->js_used; | 1860 keeplen = reader->js_end - reader->js_buf; |
1857 if (unused > 0) | 1861 if (keeplen > 0) |
1858 { | 1862 { |
1859 /* Prepend unused text. */ | 1863 /* Prepend unused text. */ |
1860 len = (int)STRLEN(next); | 1864 addlen = (int)STRLEN(next); |
1861 p = alloc(unused + len + 1); | 1865 p = alloc(keeplen + addlen + 1); |
1862 if (p == NULL) | 1866 if (p == NULL) |
1863 { | 1867 { |
1864 vim_free(next); | 1868 vim_free(next); |
1865 return FALSE; | 1869 return FALSE; |
1866 } | 1870 } |
1867 mch_memmove(p, reader->js_buf + reader->js_used, unused); | 1871 mch_memmove(p, reader->js_buf, keeplen); |
1868 mch_memmove(p + unused, next, len + 1); | 1872 mch_memmove(p + keeplen, next, addlen + 1); |
1869 vim_free(next); | 1873 vim_free(next); |
1870 next = p; | 1874 next = p; |
1871 } | 1875 } |
1872 | 1876 |
1873 vim_free(reader->js_buf); | 1877 vim_free(reader->js_buf); |
1874 reader->js_buf = next; | 1878 reader->js_buf = next; |
1875 reader->js_used = 0; | |
1876 return TRUE; | 1879 return TRUE; |
1877 } | 1880 } |
1878 | 1881 |
1879 /* | 1882 /* |
1880 * Use the read buffer of "channel"/"part" and parse a JSON message that is | 1883 * Use the read buffer of "channel"/"part" and parse a JSON message that is |
1950 } | 1953 } |
1951 } | 1954 } |
1952 } | 1955 } |
1953 | 1956 |
1954 if (status == OK) | 1957 if (status == OK) |
1955 chanpart->ch_waiting = FALSE; | 1958 chanpart->ch_wait_len = 0; |
1956 else if (status == MAYBE) | 1959 else if (status == MAYBE) |
1957 { | 1960 { |
1958 if (!chanpart->ch_waiting) | 1961 size_t buflen = STRLEN(reader.js_buf); |
1959 { | 1962 |
1960 /* First time encountering incomplete message, set a deadline of | 1963 if (chanpart->ch_wait_len < buflen) |
1961 * 100 msec. */ | 1964 { |
1962 ch_log(channel, "Incomplete message - wait for more"); | 1965 /* First time encountering incomplete message or after receiving |
1966 * more (but still incomplete): set a deadline of 100 msec. */ | |
1967 ch_logn(channel, | |
1968 "Incomplete message (%d bytes) - wait 100 msec for more", | |
1969 buflen); | |
1963 reader.js_used = 0; | 1970 reader.js_used = 0; |
1964 chanpart->ch_waiting = TRUE; | 1971 chanpart->ch_wait_len = buflen; |
1965 #ifdef WIN32 | 1972 #ifdef WIN32 |
1966 chanpart->ch_deadline = GetTickCount() + 100L; | 1973 chanpart->ch_deadline = GetTickCount() + 100L; |
1967 #else | 1974 #else |
1968 gettimeofday(&chanpart->ch_deadline, NULL); | 1975 gettimeofday(&chanpart->ch_deadline, NULL); |
1969 chanpart->ch_deadline.tv_usec += 100 * 1000; | 1976 chanpart->ch_deadline.tv_usec += 100 * 1000; |
1990 } | 1997 } |
1991 #endif | 1998 #endif |
1992 if (timeout) | 1999 if (timeout) |
1993 { | 2000 { |
1994 status = FAIL; | 2001 status = FAIL; |
1995 chanpart->ch_waiting = FALSE; | 2002 chanpart->ch_wait_len = 0; |
2003 ch_log(channel, "timed out"); | |
1996 } | 2004 } |
1997 else | 2005 else |
1998 { | 2006 { |
1999 reader.js_used = 0; | 2007 reader.js_used = 0; |
2000 ch_log(channel, "still waiting on incomplete message"); | 2008 ch_log(channel, "still waiting on incomplete message"); |
2004 | 2012 |
2005 if (status == FAIL) | 2013 if (status == FAIL) |
2006 { | 2014 { |
2007 ch_error(channel, "Decoding failed - discarding input"); | 2015 ch_error(channel, "Decoding failed - discarding input"); |
2008 ret = FALSE; | 2016 ret = FALSE; |
2009 chanpart->ch_waiting = FALSE; | 2017 chanpart->ch_wait_len = 0; |
2010 } | 2018 } |
2011 else if (reader.js_buf[reader.js_used] != NUL) | 2019 else if (reader.js_buf[reader.js_used] != NUL) |
2012 { | 2020 { |
2013 /* Put the unread part back into the channel. */ | 2021 /* Put the unread part back into the channel. */ |
2014 channel_save(channel, part, reader.js_buf + reader.js_used, | 2022 channel_save(channel, part, reader.js_buf + reader.js_used, |
3367 continue; | 3375 continue; |
3368 | 3376 |
3369 /* Wait for up to the timeout. If there was an incomplete message | 3377 /* Wait for up to the timeout. If there was an incomplete message |
3370 * use the deadline for that. */ | 3378 * use the deadline for that. */ |
3371 timeout = timeout_arg; | 3379 timeout = timeout_arg; |
3372 if (chanpart->ch_waiting) | 3380 if (chanpart->ch_wait_len > 0) |
3373 { | 3381 { |
3374 #ifdef WIN32 | 3382 #ifdef WIN32 |
3375 timeout = chanpart->ch_deadline - GetTickCount() + 1; | 3383 timeout = chanpart->ch_deadline - GetTickCount() + 1; |
3376 #else | 3384 #else |
3377 { | 3385 { |
3387 #endif | 3395 #endif |
3388 if (timeout < 0) | 3396 if (timeout < 0) |
3389 { | 3397 { |
3390 /* Something went wrong, channel_parse_json() didn't | 3398 /* Something went wrong, channel_parse_json() didn't |
3391 * discard message. Cancel waiting. */ | 3399 * discard message. Cancel waiting. */ |
3392 chanpart->ch_waiting = FALSE; | 3400 chanpart->ch_wait_len = 0; |
3393 timeout = timeout_arg; | 3401 timeout = timeout_arg; |
3394 } | 3402 } |
3395 else if (timeout > timeout_arg) | 3403 else if (timeout > timeout_arg) |
3396 timeout = timeout_arg; | 3404 timeout = timeout_arg; |
3397 } | 3405 } |