6
6
log = logging .getLogger (__name__ )
7
7
8
8
9
+ class _StreamError (Exception ):
10
+ """Raised on stream errors."""
11
+
12
+
9
13
class JsonRpcStreamReader (object ):
10
14
11
15
def __init__ (self , rfile ):
@@ -21,9 +25,10 @@ def listen(self, message_consumer):
21
25
message_consumer (fn): function that is passed each message as it is read off the socket.
22
26
"""
23
27
while not self ._rfile .closed :
24
- request_str = self ._read_message ()
25
-
26
- if request_str is None :
28
+ try :
29
+ request_str = self ._read_message ()
30
+ except _StreamError :
31
+ log .exception ("Failed to read message." )
27
32
break
28
33
29
34
try :
@@ -36,37 +41,52 @@ def _read_message(self):
36
41
"""Reads the contents of a message.
37
42
38
43
Returns:
39
- body of message if parsable else None
44
+ body of message
45
+
46
+ Raises:
47
+ _StreamError: If message was not parsable.
40
48
"""
41
- line = self ._rfile .readline ()
49
+ # Read the headers
50
+ headers = self ._read_headers ()
42
51
43
- if not line :
44
- return None
52
+ try :
53
+ content_length = int (headers [b"Content-Length" ])
54
+ except (ValueError , KeyError ):
55
+ raise _StreamError ("Invalid or missing Content-Length headers: {}" .format (headers ))
45
56
46
- content_length = self ._content_length (line )
57
+ # Grab the body
58
+ body = self ._rfile .read (content_length )
59
+ if not body :
60
+ raise _StreamError ("Got EOF when reading from stream" )
47
61
48
- # Blindly consume all header lines
49
- while line and line .strip ():
50
- line = self ._rfile .readline ()
62
+ return body
51
63
52
- if not line :
53
- return None
64
+ def _read_headers (self ):
65
+ """Read the headers from a LSP base message.
66
+
67
+ Returns:
68
+ dict: A dict containing the headers and their values.
69
+
70
+ Raises:
71
+ _StreamError: If headers are not parsable.
72
+ """
73
+ headers = {}
74
+ while True :
75
+ line = self ._rfile .readline ()
76
+ if not line :
77
+ raise _StreamError ("Got EOF when reading from stream" )
78
+ if not line .strip ():
79
+ # Finished reading headers break while loop
80
+ break
54
81
55
- # Grab the body
56
- return self ._rfile .read (content_length )
57
-
58
- @staticmethod
59
- def _content_length (line ):
60
- """Extract the content length from an input line."""
61
- if line .startswith (b'Content-Length: ' ):
62
- _ , value = line .split (b'Content-Length: ' )
63
- value = value .strip ()
64
82
try :
65
- return int ( value )
83
+ key , value = line . split ( b":" )
66
84
except ValueError :
67
- raise ValueError ("Invalid Content-Length header: {}" .format (value ))
85
+ raise _StreamError ("Invalid header {}: " .format (line ))
86
+
87
+ headers [key .strip ()] = value .strip ()
68
88
69
- return None
89
+ return headers
70
90
71
91
72
92
class JsonRpcStreamWriter (object ):
0 commit comments