5
5
package jsonrpc2
6
6
7
7
import (
8
+ "bufio"
8
9
"context"
10
+ "fmt"
9
11
"io"
12
+ "strconv"
13
+ "strings"
10
14
"sync"
11
15
12
- "github.com/francoispqt/gojay "
16
+ "golang.org/x/xerrors "
13
17
)
14
18
15
19
// Stream abstracts the transport mechanics from the JSON RPC protocol.
@@ -20,31 +24,65 @@ type Stream interface {
20
24
Write (context.Context , []byte ) error
21
25
}
22
26
27
+ type stream struct {
28
+ in * bufio.Reader
29
+ out io.Writer
30
+ sync.Mutex
31
+ }
32
+
23
33
func NewStream (in io.Reader , out io.Writer ) Stream {
24
34
return & stream {
25
- in : gojay . BorrowDecoder (in ),
35
+ in : bufio . NewReader (in ),
26
36
out : out ,
27
37
}
28
38
}
29
39
30
- type stream struct {
31
- in * gojay.Decoder
32
- sync.Mutex
33
- out io.Writer
34
- }
35
-
36
40
func (s * stream ) Read (ctx context.Context ) ([]byte , error ) {
37
41
select {
38
42
case <- ctx .Done ():
39
43
return nil , ctx .Err ()
40
44
default :
41
45
}
42
46
43
- defer s .in .Release ()
47
+ var length int64
48
+ for {
49
+ line , err := s .in .ReadString ('\n' )
50
+ if err != nil {
51
+ return nil , xerrors .Errorf ("failed reading header line: %w" , err )
52
+ }
44
53
45
- var data []byte
46
- if err := s .in .Decode (& data ); err != nil {
47
- return nil , err
54
+ line = strings .TrimSpace (line )
55
+ if line == "" { // check we have a header line
56
+ break
57
+ }
58
+
59
+ colon := strings .IndexRune (line , ':' )
60
+ if colon < 0 {
61
+ return nil , xerrors .Errorf ("invalid header line: %q" , line )
62
+ }
63
+
64
+ name , value := line [:colon ], strings .TrimSpace (line [colon + 1 :])
65
+ switch name {
66
+ case "Content-Length" :
67
+ if length , err = strconv .ParseInt (value , 10 , 32 ); err != nil {
68
+ return nil , xerrors .Errorf ("failed parsing Content-Length: %v" , value )
69
+ }
70
+
71
+ if length <= 0 {
72
+ return nil , xerrors .Errorf ("invalid Content-Length: %v" , length )
73
+ }
74
+ default :
75
+ // ignoring unknown headers
76
+ }
77
+ }
78
+
79
+ if length == 0 {
80
+ return nil , xerrors .New ("missing Content-Length header" )
81
+ }
82
+
83
+ data := make ([]byte , length )
84
+ if _ , err := io .ReadFull (s .in , data ); err != nil {
85
+ return nil , xerrors .Errorf ("failed reading data: %w" , err )
48
86
}
49
87
50
88
return data , nil
@@ -56,8 +94,12 @@ func (s *stream) Write(ctx context.Context, data []byte) error {
56
94
return ctx .Err ()
57
95
default :
58
96
}
97
+
59
98
s .Lock ()
60
- _ , err := s .out .Write (data )
99
+ _ , err := fmt .Fprintf (s .out , "Content-Length: %v\r \n \r \n " , len (data ))
100
+ if err == nil {
101
+ _ , err = s .out .Write (data )
102
+ }
61
103
s .Unlock ()
62
104
63
105
return err
0 commit comments