-
Notifications
You must be signed in to change notification settings - Fork 22
/
framereader.go
109 lines (92 loc) · 2.39 KB
/
framereader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package framereader
import (
"errors"
"fmt"
"io"
"sync"
"github.com/rmedvedev/grpcdump/internal/app/grpc"
"github.com/rmedvedev/grpcdump/internal/app/models"
"golang.org/x/net/http2"
)
//FrameReader ...
type FrameReader struct {
framer *http2.Framer
Streams *Streams
paths *sync.Map
}
//New creates FrameReader
func New(framer *http2.Framer, paths *sync.Map) *FrameReader {
return &FrameReader{framer, NewStreams(), paths}
}
//Read ...
func (frameReader *FrameReader) Read(packet *models.Packet) (models.RenderModel, error) {
//trying to read http2 frame
frame, err := frameReader.framer.ReadFrame()
if err == io.EOF {
return nil, nil
}
if err != nil {
return nil, errors.New(fmt.Sprint("Error reading frame: ", err))
}
connKey := packet.GetConnectionKey()
streamID := frame.Header().StreamID
var stream *models.Stream
switch frame := frame.(type) {
case *http2.MetaHeadersFrame:
metaHeaders := make(map[string]string)
isTrailer := false
for _, hf := range frame.Fields {
metaHeaders[hf.Name] = hf.Value
if hf.Name == ":path" {
stream = &models.Stream{
ID: streamID,
Path: hf.Value,
Type: models.RequestType,
}
frameReader.Streams.Add(
connKey,
stream,
)
frameReader.paths.Store(packet.GetConnectionKey(), hf.Value)
} else if hf.Name == ":status" {
stream = &models.Stream{
ID: streamID,
Type: models.ResponseType,
}
if path, ok := frameReader.paths.Load(packet.GetRevConnectionKey()); ok {
stream.Path = path.(string)
}
frameReader.Streams.Add(
connKey,
stream,
)
} else if hf.Name == "grpc-status" {
stream, _ = frameReader.Streams.Get(connKey, streamID)
isTrailer = true
}
}
if stream != nil {
if isTrailer {
for key, value := range metaHeaders {
stream.MetaHeaders[key] = value
}
return models.NewHttp2Response(packet, stream, stream.ResponseGrpcMessage), nil
} else {
stream.MetaHeaders = metaHeaders
}
}
case *http2.DataFrame:
stream, _ := frameReader.Streams.Get(connKey, streamID)
grpcMessage, err := grpc.Decode(stream.Path, frame, stream.Type, &stream.GrpcState)
if err != nil {
return nil, err
}
switch stream.Type {
case models.RequestType:
return models.NewHttp2Request(packet, stream, grpcMessage), nil
case models.ResponseType:
stream.ResponseGrpcMessage = grpcMessage
}
}
return nil, nil
}