mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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)
			
			
This commit is contained in:
		
				
					committed by
					
						 Bram Moolenaar
						Bram Moolenaar
					
				
			
			
				
	
			
			
			
						parent
						
							9bd3ce22e3
						
					
				
				
					commit
					bac9a9e5c2
				
			| @@ -2031,6 +2031,8 @@ channel_consume(channel_T *channel, ch_part_T part, int len) | |||||||
|  * Collapses the first and second buffer for "channel"/"part". |  * Collapses the first and second buffer for "channel"/"part". | ||||||
|  * Returns FAIL if that is not possible. |  * Returns FAIL if that is not possible. | ||||||
|  * When "want_nl" is TRUE collapse more buffers until a NL is found. |  * When "want_nl" is TRUE collapse more buffers until a NL is found. | ||||||
|  |  * When the channel part mode is "lsp", collapse all the buffers as the http | ||||||
|  |  * header and the JSON content can be present in multiple buffers. | ||||||
|  */ |  */ | ||||||
|     int |     int | ||||||
| channel_collapse(channel_T *channel, ch_part_T part, int want_nl) | channel_collapse(channel_T *channel, ch_part_T part, int want_nl) | ||||||
|   | |||||||
| @@ -2466,7 +2466,7 @@ func LspOtCb(chan, msg) | |||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
| func LspTests(port) | func LspTests(port) | ||||||
|   " call ch_logfile('Xlsprpc.log', 'w') |   " call ch_logfile('Xlspclient.log', 'w') | ||||||
|   let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'}) |   let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'}) | ||||||
|   if ch_status(ch) == "fail" |   if ch_status(ch) == "fail" | ||||||
|     call assert_report("Can't open the lsp channel") |     call assert_report("Can't open the lsp channel") | ||||||
| @@ -2620,6 +2620,16 @@ func LspTests(port) | |||||||
|   " send a ping to make sure communication still works |   " send a ping to make sure communication still works | ||||||
|   call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result) |   call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result) | ||||||
|  |  | ||||||
|  |   " Test for a large payload | ||||||
|  |   let content = repeat('abcdef', 11000) | ||||||
|  |   let resp = ch_evalexpr(ch, #{method: 'large-payload', | ||||||
|  |         \ params: #{text: content}}) | ||||||
|  |   call assert_equal(#{jsonrpc: '2.0', id: 26, result: | ||||||
|  |         \ #{method: 'large-payload', jsonrpc: '2.0', id: 26, | ||||||
|  |         \ params: #{text: content}}}, resp) | ||||||
|  |   " send a ping to make sure communication still works | ||||||
|  |   call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result) | ||||||
|  |  | ||||||
|   " Test for invoking an unsupported method |   " Test for invoking an unsupported method | ||||||
|   let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200}) |   let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200}) | ||||||
|   call assert_equal({}, resp) |   call assert_equal({}, resp) | ||||||
|   | |||||||
| @@ -24,6 +24,11 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|     def setup(self): |     def setup(self): | ||||||
|         self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) |         self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) | ||||||
|  |  | ||||||
|  |     def debuglog(self, msg): | ||||||
|  |         if self.debug: | ||||||
|  |             with open("Xlspserver.log", "a") as myfile: | ||||||
|  |                 myfile.write(msg) | ||||||
|  |  | ||||||
|     def send_lsp_msg(self, msgid, resp_dict): |     def send_lsp_msg(self, msgid, resp_dict): | ||||||
|         v = {'jsonrpc': '2.0', 'result': resp_dict} |         v = {'jsonrpc': '2.0', 'result': resp_dict} | ||||||
|         if msgid != -1: |         if msgid != -1: | ||||||
| @@ -34,8 +39,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|         resp += "\r\n" |         resp += "\r\n" | ||||||
|         resp += s |         resp += s | ||||||
|         if self.debug: |         if self.debug: | ||||||
|             with open("Xlspdebug.log", "a") as myfile: |             self.debuglog("SEND: ({0} bytes) '{1}'\n".format(len(resp), resp)) | ||||||
|                 myfile.write("\n=> send\n" + resp) |  | ||||||
|         self.request.sendall(resp.encode('utf-8')) |         self.request.sendall(resp.encode('utf-8')) | ||||||
|  |  | ||||||
|     def send_wrong_payload(self): |     def send_wrong_payload(self): | ||||||
| @@ -136,6 +140,10 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|         time.sleep(0.2) |         time.sleep(0.2) | ||||||
|         self.send_lsp_msg(-1, 'wrong-payload') |         self.send_lsp_msg(-1, 'wrong-payload') | ||||||
|  |  | ||||||
|  |     def do_large_payload(self, payload): | ||||||
|  |         # test for sending a large (> 64K) payload | ||||||
|  |         self.send_lsp_msg(payload['id'], payload) | ||||||
|  |  | ||||||
|     def do_rpc_resp_incorrect_id(self, payload): |     def do_rpc_resp_incorrect_id(self, payload): | ||||||
|         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1') |         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1') | ||||||
|         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2') |         self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2') | ||||||
| @@ -185,8 +193,6 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|     def process_msg(self, msg): |     def process_msg(self, msg): | ||||||
|         try: |         try: | ||||||
|             decoded = json.loads(msg) |             decoded = json.loads(msg) | ||||||
|             print("Decoded:") |  | ||||||
|             print(str(decoded)) |  | ||||||
|             if 'method' in decoded: |             if 'method' in decoded: | ||||||
|                 test_map = { |                 test_map = { | ||||||
|                         'ping': self.do_ping, |                         'ping': self.do_ping, | ||||||
| @@ -194,6 +200,7 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|                         'simple-rpc': self.do_simple_rpc, |                         'simple-rpc': self.do_simple_rpc, | ||||||
|                         'rpc-with-notif': self.do_rpc_with_notif, |                         'rpc-with-notif': self.do_rpc_with_notif, | ||||||
|                         'wrong-payload': self.do_wrong_payload, |                         'wrong-payload': self.do_wrong_payload, | ||||||
|  |                         'large-payload': self.do_large_payload, | ||||||
|                         'rpc-resp-incorrect-id': self.do_rpc_resp_incorrect_id, |                         'rpc-resp-incorrect-id': self.do_rpc_resp_incorrect_id, | ||||||
|                         'simple-notif': self.do_simple_notif, |                         'simple-notif': self.do_simple_notif, | ||||||
|                         'multi-notif': self.do_multi_notif, |                         'multi-notif': self.do_multi_notif, | ||||||
| @@ -211,28 +218,40 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|                 if decoded['method'] in test_map: |                 if decoded['method'] in test_map: | ||||||
|                     test_map[decoded['method']](decoded) |                     test_map[decoded['method']](decoded) | ||||||
|                 else: |                 else: | ||||||
|                     print("Error: Unsupported method: " + decoded['method']) |                     self.debuglog("Error: Unsupported method - " + decoded['method'] + "\n") | ||||||
|             else: |             else: | ||||||
|                 print("Error: 'method' field is not found") |                 self.debuglog("Error: 'method' field is not found\n") | ||||||
|  |  | ||||||
|         except ValueError: |         except ValueError: | ||||||
|             print("json decoding failed") |             self.debuglog("Error: json decoding failed\n") | ||||||
|  |  | ||||||
|     def process_msgs(self, msgbuf): |     def process_msgs(self, msgbuf): | ||||||
|         while True: |         while True: | ||||||
|             sidx = msgbuf.find('Content-Length: ') |             sidx = msgbuf.find('Content-Length: ') | ||||||
|             if sidx == -1: |             if sidx == -1: | ||||||
|  |                 # partial message received | ||||||
|                 return msgbuf |                 return msgbuf | ||||||
|             sidx += 16 |             sidx += 16 | ||||||
|             eidx = msgbuf.find('\r\n') |             eidx = msgbuf.find('\r\n') | ||||||
|             if eidx == -1: |             if eidx == -1: | ||||||
|  |                 # partial message received | ||||||
|                 return msgbuf |                 return msgbuf | ||||||
|             msglen = int(msgbuf[sidx:eidx]) |             msglen = int(msgbuf[sidx:eidx]) | ||||||
|  |  | ||||||
|             hdrend = msgbuf.find('\r\n\r\n') |             hdrend = msgbuf.find('\r\n\r\n') | ||||||
|             if hdrend == -1: |             if hdrend == -1: | ||||||
|  |                 # partial message received | ||||||
|                 return msgbuf |                 return msgbuf | ||||||
|  |  | ||||||
|  |             if msglen > len(msgbuf[hdrend + 4:]): | ||||||
|  |                 if self.debug: | ||||||
|  |                     self.debuglog("Partial message ({0} bytes)\n".format(len(msgbuf))) | ||||||
|  |                 # partial message received | ||||||
|  |                 return msgbuf | ||||||
|  |  | ||||||
|  |             if self.debug: | ||||||
|  |                 self.debuglog("Complete message ({0} bytes) received\n".format(msglen)) | ||||||
|  |  | ||||||
|             # Remove the header |             # Remove the header | ||||||
|             msgbuf = msgbuf[hdrend + 4:] |             msgbuf = msgbuf[hdrend + 4:] | ||||||
|             payload = msgbuf[:msglen] |             payload = msgbuf[:msglen] | ||||||
| @@ -243,27 +262,25 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): | |||||||
|             msgbuf = msgbuf[msglen:] |             msgbuf = msgbuf[msglen:] | ||||||
|  |  | ||||||
|     def handle(self): |     def handle(self): | ||||||
|         print("=== socket opened ===") |  | ||||||
|         self.debug = False |         self.debug = False | ||||||
|  |         self.debuglog("=== socket opened ===\n") | ||||||
|         msgbuf = '' |         msgbuf = '' | ||||||
|         while True: |         while True: | ||||||
|             try: |             try: | ||||||
|                 received = self.request.recv(4096).decode('utf-8') |                 received = self.request.recv(4096).decode('utf-8') | ||||||
|             except socket.error: |             except socket.error: | ||||||
|                 print("=== socket error ===") |                 self.debuglog("=== socket error ===\n") | ||||||
|                 break |                 break | ||||||
|             except IOError: |             except IOError: | ||||||
|                 print("=== socket closed ===") |                 self.debuglog("=== socket closed ===\n") | ||||||
|                 break |                 break | ||||||
|             if received == '': |             if received == '': | ||||||
|                 print("=== socket closed ===") |                 self.debuglog("=== socket closed ===\n") | ||||||
|                 break |                 break | ||||||
|             print("\nReceived:\n{0}".format(received)) |  | ||||||
|  |  | ||||||
|             # Write the received lines into the file for debugging |             # Write the received lines into the file for debugging | ||||||
|             if self.debug: |             if self.debug: | ||||||
|                 with open("Xlspdebug.log", "a") as myfile: |                 self.debuglog("RECV: ({0} bytes) '{1}'\n".format(len(received), received)) | ||||||
|                     myfile.write("\n<= recv\n" + received) |  | ||||||
|  |  | ||||||
|             # Can receive more than one line in a response or a partial line. |             # Can receive more than one line in a response or a partial line. | ||||||
|             # Accumulate all the received characters and process one line at |             # Accumulate all the received characters and process one line at | ||||||
| @@ -287,8 +304,6 @@ def main(host, port, server_class=ThreadedTCPServer): | |||||||
|     if len(sys.argv) >= 2 and sys.argv[1] == 'delay': |     if len(sys.argv) >= 2 and sys.argv[1] == 'delay': | ||||||
|         port = 13684 |         port = 13684 | ||||||
|         writePortInFile(port) |         writePortInFile(port) | ||||||
|  |  | ||||||
|         print("Wait for it...") |  | ||||||
|         time.sleep(0.5) |         time.sleep(0.5) | ||||||
|  |  | ||||||
|     server = server_class((host, port), ThreadedTCPRequestHandler) |     server = server_class((host, port), ThreadedTCPRequestHandler) | ||||||
| @@ -301,8 +316,6 @@ def main(host, port, server_class=ThreadedTCPServer): | |||||||
|  |  | ||||||
|     writePortInFile(port) |     writePortInFile(port) | ||||||
|  |  | ||||||
|     print("Listening on port {0}".format(port)) |  | ||||||
|  |  | ||||||
|     # Main thread terminates, but the server continues running |     # Main thread terminates, but the server continues running | ||||||
|     # until server.shutdown() is called. |     # until server.shutdown() is called. | ||||||
|     try: |     try: | ||||||
|   | |||||||
| @@ -746,6 +746,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     4788, | ||||||
| /**/ | /**/ | ||||||
|     4787, |     4787, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user