1
- // SPDX-License-Identifier: BSD-3-Clause
2
1
// SPDX-FileCopyrightText: Copyright 2018 The Go Language Server Authors
2
+ // SPDX-License-Identifier: BSD-3-Clause
3
3
4
4
package jsonrpc2
5
5
@@ -15,9 +15,28 @@ import (
15
15
json "github.com/goccy/go-json"
16
16
)
17
17
18
+ const (
19
+ // HdrContentLength is the HTTP header name of the length of the content part in bytes. This header is required.
20
+ // This entity header indicates the size of the entity-body, in bytes, sent to the recipient.
21
+ //
22
+ // RFC 7230, section 3.3.2: Content-Length:
23
+ // https://tools.ietf.org/html/rfc7230#section-3.3.2
24
+ HdrContentLength = "Content-Length"
25
+
26
+ // HeaderContentType is the mime type of the content part. Defaults to "application/vscode-jsonrpc; charset=utf-8".
27
+ // This entity header is used to indicate the media type of the resource.
28
+ //
29
+ // RFC 7231, section 3.1.1.5: Content-Type:
30
+ // https://tools.ietf.org/html/rfc7231#section-3.1.1.5
31
+ HdrContentType = "Content-Type"
32
+
33
+ // HeaderContentSeparator is the header and content part separator.
34
+ HdrContentSeparator = "\r \n \r \n "
35
+ )
36
+
18
37
// Framer wraps a network connection up into a Stream.
19
- // It is responsible for the framing and encoding of messages into wire form.
20
38
//
39
+ // It is responsible for the framing and encoding of messages into wire form.
21
40
// NewRawStream and NewStream are implementations of a Framer.
22
41
type Framer func (conn net.Conn ) Stream
23
42
@@ -64,35 +83,47 @@ func (s *rawStream) Read(ctx context.Context) (Message, int64, error) {
64
83
return nil , 0 , ctx .Err ()
65
84
default :
66
85
}
86
+
67
87
var raw json.RawMessage
68
88
if err := s .in .Decode (& raw ); err != nil {
69
- return nil , 0 , fmt .Errorf ("failed to Decode : %w" , err )
89
+ return nil , 0 , fmt .Errorf ("decoding raw message : %w" , err )
70
90
}
91
+
71
92
msg , err := DecodeMessage (raw )
72
- return msg , int64 (len (raw )), fmt . Errorf ( "failed to DecodeMessage: %w" , err )
93
+ return msg , int64 (len (raw )), err
73
94
}
74
95
75
96
// Write implements Stream.Write.
76
- func (s * rawStream ) Write (ctx context.Context , msg Message ) (total int64 , err error ) {
97
+ func (s * rawStream ) Write (ctx context.Context , msg Message ) (int64 , error ) {
77
98
select {
78
99
case <- ctx .Done ():
79
100
return 0 , ctx .Err ()
80
101
default :
81
102
}
103
+
82
104
data , err := json .MarshalNoEscape (msg )
83
105
if err != nil {
84
106
return 0 , fmt .Errorf ("marshaling message: %w" , err )
85
107
}
108
+
86
109
n , err := s .conn .Write (data )
87
- total = int64 (n )
88
- return
110
+ if err != nil {
111
+ return 0 , fmt .Errorf ("write to stream: %w" , err )
112
+ }
113
+
114
+ return int64 (n ), nil
89
115
}
90
116
91
117
// Close implements Stream.Close.
92
118
func (s * rawStream ) Close () error {
93
119
return s .conn .Close ()
94
120
}
95
121
122
+ type stream struct {
123
+ conn net.Conn
124
+ in * bufio.Reader
125
+ }
126
+
96
127
// NewStream returns a Stream built on top of a net.Conn.
97
128
//
98
129
// The messages are sent with HTTP content length and MIME type headers.
@@ -104,78 +135,89 @@ func NewStream(conn net.Conn) Stream {
104
135
}
105
136
}
106
137
107
- type stream struct {
108
- conn net.Conn
109
- in * bufio.Reader
110
- }
111
-
112
138
// Read implements Stream.Read.
113
139
func (s * stream ) Read (ctx context.Context ) (Message , int64 , error ) {
114
140
select {
115
141
case <- ctx .Done ():
116
142
return nil , 0 , ctx .Err ()
117
143
default :
118
144
}
119
- var total , length int64
145
+
146
+ var total int64
147
+ var length int64
120
148
// read the header, stop on the first empty line
121
149
for {
122
150
line , err := s .in .ReadString ('\n' )
123
151
total += int64 (len (line ))
124
152
if err != nil {
125
153
return nil , total , fmt .Errorf ("failed reading header line: %w" , err )
126
154
}
155
+
127
156
line = strings .TrimSpace (line )
128
157
// check we have a header line
129
158
if line == "" {
130
159
break
131
160
}
161
+
132
162
colon := strings .IndexRune (line , ':' )
133
163
if colon < 0 {
134
164
return nil , total , fmt .Errorf ("invalid header line %q" , line )
135
165
}
166
+
136
167
name , value := line [:colon ], strings .TrimSpace (line [colon + 1 :])
137
168
switch name {
138
- case "Content-Length" :
169
+ case HdrContentLength :
139
170
if length , err = strconv .ParseInt (value , 10 , 32 ); err != nil {
140
- return nil , total , fmt .Errorf ("failed parsing Content-Length : %v" , value )
171
+ return nil , total , fmt .Errorf ("failed parsing %s : %v: %w " , HdrContentLength , value , err )
141
172
}
142
173
if length <= 0 {
143
- return nil , total , fmt .Errorf ("invalid Content-Length : %v" , length )
174
+ return nil , total , fmt .Errorf ("invalid %s : %v" , HdrContentLength , length )
144
175
}
145
176
default :
146
177
// ignoring unknown headers
147
178
}
148
179
}
180
+
149
181
if length == 0 {
150
- return nil , total , fmt .Errorf ("missing Content-Length header" )
182
+ return nil , total , fmt .Errorf ("missing %s header" , HdrContentLength )
151
183
}
184
+
152
185
data := make ([]byte , length )
153
186
if _ , err := io .ReadFull (s .in , data ); err != nil {
154
- return nil , total , fmt .Errorf ("failed to ReadFull : %w" , err )
187
+ return nil , total , fmt .Errorf ("read full of data : %w" , err )
155
188
}
189
+
156
190
total += length
157
191
msg , err := DecodeMessage (data )
158
192
return msg , total , err
159
193
}
160
194
161
195
// Write implements Stream.Write.
162
- func (s * stream ) Write (ctx context.Context , msg Message ) (total int64 , err error ) {
196
+ func (s * stream ) Write (ctx context.Context , msg Message ) (int64 , error ) {
163
197
select {
164
198
case <- ctx .Done ():
165
199
return 0 , ctx .Err ()
166
200
default :
167
201
}
202
+
168
203
data , err := json .MarshalNoEscape (msg )
169
204
if err != nil {
170
205
return 0 , fmt .Errorf ("marshaling message: %w" , err )
171
206
}
172
- n , err := fmt . Fprintf ( s . conn , "Content-Length: %v \r \n \r \n " , len ( data ))
173
- total = int64 ( n )
174
- if err == nil {
175
- n , err = s . conn . Write ( data )
176
- total += int64 ( n )
207
+
208
+ n , err := fmt . Fprintf ( s . conn , "%s: %v%s" , HdrContentLength , len ( data ), HdrContentSeparator )
209
+ total := int64 ( n )
210
+ if err != nil {
211
+ return 0 , fmt . Errorf ( "write data to conn: %w" , err )
177
212
}
178
- return
213
+
214
+ n , err = s .conn .Write (data )
215
+ total += int64 (n )
216
+ if err != nil {
217
+ return 0 , fmt .Errorf ("write data to conn: %w" , err )
218
+ }
219
+
220
+ return total , nil
179
221
}
180
222
181
223
// Close implements Stream.Close.
0 commit comments