Skip to content

Commit 0c6bb36

Browse files
committed
stream: fix error handling for fake/pipe testcase
1 parent b1b0e09 commit 0c6bb36

File tree

1 file changed

+67
-25
lines changed

1 file changed

+67
-25
lines changed

stream.go

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// SPDX-License-Identifier: BSD-3-Clause
21
// SPDX-FileCopyrightText: Copyright 2018 The Go Language Server Authors
2+
// SPDX-License-Identifier: BSD-3-Clause
33

44
package jsonrpc2
55

@@ -15,9 +15,28 @@ import (
1515
json "github.com/goccy/go-json"
1616
)
1717

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+
1837
// Framer wraps a network connection up into a Stream.
19-
// It is responsible for the framing and encoding of messages into wire form.
2038
//
39+
// It is responsible for the framing and encoding of messages into wire form.
2140
// NewRawStream and NewStream are implementations of a Framer.
2241
type Framer func(conn net.Conn) Stream
2342

@@ -64,35 +83,47 @@ func (s *rawStream) Read(ctx context.Context) (Message, int64, error) {
6483
return nil, 0, ctx.Err()
6584
default:
6685
}
86+
6787
var raw json.RawMessage
6888
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)
7090
}
91+
7192
msg, err := DecodeMessage(raw)
72-
return msg, int64(len(raw)), fmt.Errorf("failed to DecodeMessage: %w", err)
93+
return msg, int64(len(raw)), err
7394
}
7495

7596
// 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) {
7798
select {
7899
case <-ctx.Done():
79100
return 0, ctx.Err()
80101
default:
81102
}
103+
82104
data, err := json.MarshalNoEscape(msg)
83105
if err != nil {
84106
return 0, fmt.Errorf("marshaling message: %w", err)
85107
}
108+
86109
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
89115
}
90116

91117
// Close implements Stream.Close.
92118
func (s *rawStream) Close() error {
93119
return s.conn.Close()
94120
}
95121

122+
type stream struct {
123+
conn net.Conn
124+
in *bufio.Reader
125+
}
126+
96127
// NewStream returns a Stream built on top of a net.Conn.
97128
//
98129
// The messages are sent with HTTP content length and MIME type headers.
@@ -104,78 +135,89 @@ func NewStream(conn net.Conn) Stream {
104135
}
105136
}
106137

107-
type stream struct {
108-
conn net.Conn
109-
in *bufio.Reader
110-
}
111-
112138
// Read implements Stream.Read.
113139
func (s *stream) Read(ctx context.Context) (Message, int64, error) {
114140
select {
115141
case <-ctx.Done():
116142
return nil, 0, ctx.Err()
117143
default:
118144
}
119-
var total, length int64
145+
146+
var total int64
147+
var length int64
120148
// read the header, stop on the first empty line
121149
for {
122150
line, err := s.in.ReadString('\n')
123151
total += int64(len(line))
124152
if err != nil {
125153
return nil, total, fmt.Errorf("failed reading header line: %w", err)
126154
}
155+
127156
line = strings.TrimSpace(line)
128157
// check we have a header line
129158
if line == "" {
130159
break
131160
}
161+
132162
colon := strings.IndexRune(line, ':')
133163
if colon < 0 {
134164
return nil, total, fmt.Errorf("invalid header line %q", line)
135165
}
166+
136167
name, value := line[:colon], strings.TrimSpace(line[colon+1:])
137168
switch name {
138-
case "Content-Length":
169+
case HdrContentLength:
139170
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)
141172
}
142173
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)
144175
}
145176
default:
146177
// ignoring unknown headers
147178
}
148179
}
180+
149181
if length == 0 {
150-
return nil, total, fmt.Errorf("missing Content-Length header")
182+
return nil, total, fmt.Errorf("missing %s header", HdrContentLength)
151183
}
184+
152185
data := make([]byte, length)
153186
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)
155188
}
189+
156190
total += length
157191
msg, err := DecodeMessage(data)
158192
return msg, total, err
159193
}
160194

161195
// 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) {
163197
select {
164198
case <-ctx.Done():
165199
return 0, ctx.Err()
166200
default:
167201
}
202+
168203
data, err := json.MarshalNoEscape(msg)
169204
if err != nil {
170205
return 0, fmt.Errorf("marshaling message: %w", err)
171206
}
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)
177212
}
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
179221
}
180222

181223
// Close implements Stream.Close.

0 commit comments

Comments
 (0)