Skip to content

Commit bac9a9e

Browse files
yegappanbrammool
authored andcommitted
patch 8.2.4788: large payload for LSP message not tested
Problem: Large payload for LSP message not tested. Solution: Add a test with a large LSP payload. (Yegappan Lakshmanan, closes #10223)
1 parent 9bd3ce2 commit bac9a9e

4 files changed

Lines changed: 46 additions & 19 deletions

File tree

src/channel.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,6 +2031,8 @@ channel_consume(channel_T *channel, ch_part_T part, int len)
20312031
* Collapses the first and second buffer for "channel"/"part".
20322032
* Returns FAIL if that is not possible.
20332033
* When "want_nl" is TRUE collapse more buffers until a NL is found.
2034+
* When the channel part mode is "lsp", collapse all the buffers as the http
2035+
* header and the JSON content can be present in multiple buffers.
20342036
*/
20352037
int
20362038
channel_collapse(channel_T *channel, ch_part_T part, int want_nl)

src/testdir/test_channel.vim

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2466,7 +2466,7 @@ func LspOtCb(chan, msg)
24662466
endfunc
24672467

24682468
func LspTests(port)
2469-
" call ch_logfile('Xlsprpc.log', 'w')
2469+
" call ch_logfile('Xlspclient.log', 'w')
24702470
let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'})
24712471
if ch_status(ch) == "fail"
24722472
call assert_report("Can't open the lsp channel")
@@ -2620,6 +2620,16 @@ func LspTests(port)
26202620
" send a ping to make sure communication still works
26212621
call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
26222622

2623+
" Test for a large payload
2624+
let content = repeat('abcdef', 11000)
2625+
let resp = ch_evalexpr(ch, #{method: 'large-payload',
2626+
\ params: #{text: content}})
2627+
call assert_equal(#{jsonrpc: '2.0', id: 26, result:
2628+
\ #{method: 'large-payload', jsonrpc: '2.0', id: 26,
2629+
\ params: #{text: content}}}, resp)
2630+
" send a ping to make sure communication still works
2631+
call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
2632+
26232633
" Test for invoking an unsupported method
26242634
let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200})
26252635
call assert_equal({}, resp)

src/testdir/test_channel_lsp.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
2424
def setup(self):
2525
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
2626

27+
def debuglog(self, msg):
28+
if self.debug:
29+
with open("Xlspserver.log", "a") as myfile:
30+
myfile.write(msg)
31+
2732
def send_lsp_msg(self, msgid, resp_dict):
2833
v = {'jsonrpc': '2.0', 'result': resp_dict}
2934
if msgid != -1:
@@ -34,8 +39,7 @@ def send_lsp_msg(self, msgid, resp_dict):
3439
resp += "\r\n"
3540
resp += s
3641
if self.debug:
37-
with open("Xlspdebug.log", "a") as myfile:
38-
myfile.write("\n=> send\n" + resp)
42+
self.debuglog("SEND: ({0} bytes) '{1}'\n".format(len(resp), resp))
3943
self.request.sendall(resp.encode('utf-8'))
4044

4145
def send_wrong_payload(self):
@@ -136,6 +140,10 @@ def do_wrong_payload(self, payload):
136140
time.sleep(0.2)
137141
self.send_lsp_msg(-1, 'wrong-payload')
138142

143+
def do_large_payload(self, payload):
144+
# test for sending a large (> 64K) payload
145+
self.send_lsp_msg(payload['id'], payload)
146+
139147
def do_rpc_resp_incorrect_id(self, payload):
140148
self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1')
141149
self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2')
@@ -185,15 +193,14 @@ def do_empty_payload(self, payload):
185193
def process_msg(self, msg):
186194
try:
187195
decoded = json.loads(msg)
188-
print("Decoded:")
189-
print(str(decoded))
190196
if 'method' in decoded:
191197
test_map = {
192198
'ping': self.do_ping,
193199
'echo': self.do_echo,
194200
'simple-rpc': self.do_simple_rpc,
195201
'rpc-with-notif': self.do_rpc_with_notif,
196202
'wrong-payload': self.do_wrong_payload,
203+
'large-payload': self.do_large_payload,
197204
'rpc-resp-incorrect-id': self.do_rpc_resp_incorrect_id,
198205
'simple-notif': self.do_simple_notif,
199206
'multi-notif': self.do_multi_notif,
@@ -211,28 +218,40 @@ def process_msg(self, msg):
211218
if decoded['method'] in test_map:
212219
test_map[decoded['method']](decoded)
213220
else:
214-
print("Error: Unsupported method: " + decoded['method'])
221+
self.debuglog("Error: Unsupported method - " + decoded['method'] + "\n")
215222
else:
216-
print("Error: 'method' field is not found")
223+
self.debuglog("Error: 'method' field is not found\n")
217224

218225
except ValueError:
219-
print("json decoding failed")
226+
self.debuglog("Error: json decoding failed\n")
220227

221228
def process_msgs(self, msgbuf):
222229
while True:
223230
sidx = msgbuf.find('Content-Length: ')
224231
if sidx == -1:
232+
# partial message received
225233
return msgbuf
226234
sidx += 16
227235
eidx = msgbuf.find('\r\n')
228236
if eidx == -1:
237+
# partial message received
229238
return msgbuf
230239
msglen = int(msgbuf[sidx:eidx])
231240

232241
hdrend = msgbuf.find('\r\n\r\n')
233242
if hdrend == -1:
243+
# partial message received
244+
return msgbuf
245+
246+
if msglen > len(msgbuf[hdrend + 4:]):
247+
if self.debug:
248+
self.debuglog("Partial message ({0} bytes)\n".format(len(msgbuf)))
249+
# partial message received
234250
return msgbuf
235251

252+
if self.debug:
253+
self.debuglog("Complete message ({0} bytes) received\n".format(msglen))
254+
236255
# Remove the header
237256
msgbuf = msgbuf[hdrend + 4:]
238257
payload = msgbuf[:msglen]
@@ -243,27 +262,25 @@ def process_msgs(self, msgbuf):
243262
msgbuf = msgbuf[msglen:]
244263

245264
def handle(self):
246-
print("=== socket opened ===")
247265
self.debug = False
266+
self.debuglog("=== socket opened ===\n")
248267
msgbuf = ''
249268
while True:
250269
try:
251270
received = self.request.recv(4096).decode('utf-8')
252271
except socket.error:
253-
print("=== socket error ===")
272+
self.debuglog("=== socket error ===\n")
254273
break
255274
except IOError:
256-
print("=== socket closed ===")
275+
self.debuglog("=== socket closed ===\n")
257276
break
258277
if received == '':
259-
print("=== socket closed ===")
278+
self.debuglog("=== socket closed ===\n")
260279
break
261-
print("\nReceived:\n{0}".format(received))
262280

263281
# Write the received lines into the file for debugging
264282
if self.debug:
265-
with open("Xlspdebug.log", "a") as myfile:
266-
myfile.write("\n<= recv\n" + received)
283+
self.debuglog("RECV: ({0} bytes) '{1}'\n".format(len(received), received))
267284

268285
# Can receive more than one line in a response or a partial line.
269286
# Accumulate all the received characters and process one line at
@@ -287,8 +304,6 @@ def main(host, port, server_class=ThreadedTCPServer):
287304
if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
288305
port = 13684
289306
writePortInFile(port)
290-
291-
print("Wait for it...")
292307
time.sleep(0.5)
293308

294309
server = server_class((host, port), ThreadedTCPRequestHandler)
@@ -301,8 +316,6 @@ def main(host, port, server_class=ThreadedTCPServer):
301316

302317
writePortInFile(port)
303318

304-
print("Listening on port {0}".format(port))
305-
306319
# Main thread terminates, but the server continues running
307320
# until server.shutdown() is called.
308321
try:

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ static char *(features[]) =
746746

747747
static int included_patches[] =
748748
{ /* Add new patch number below this line */
749+
/**/
750+
4788,
749751
/**/
750752
4787,
751753
/**/

0 commit comments

Comments
 (0)