google.golang.org/grpc@v1.72.2/internal/transport/grpchttp2/http2bridge.go (about) 1 /* 2 * 3 * Copyright 2024 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package grpchttp2 20 21 import ( 22 "io" 23 24 "golang.org/x/net/http2" 25 "golang.org/x/net/http2/hpack" 26 "google.golang.org/grpc/mem" 27 ) 28 29 // FramerBridge adapts the net/x/http2 Framer to satisfy the grpchttp2.Framer 30 // interface. 31 // 32 // Note: This allows temporary use of the older framer and will be removed in 33 // a future release after the new framer stabilizes. 34 type FramerBridge struct { 35 framer *http2.Framer // the underlying http2.Framer implementation to perform reads and writes. 36 pool mem.BufferPool // a pool to reuse buffers when reading. 37 } 38 39 // NewFramerBridge creates an adaptor that wraps a http2.Framer in a 40 // grpchttp2.Framer. 41 // 42 // Internally, it creates a http2.Framer that uses the provided io.Reader and 43 // io.Writer, and is configured with a maximum header list size of 44 // maxHeaderListSize. 45 // 46 // Frames returned by a call to the underlying http2.Framer's ReadFrame() method 47 // need to be consumed before the next call to it. To overcome this restriction, 48 // the data in a Frame returned by the http2.Framer's ReadFrame is copied into a 49 // buffer from the given pool. If no pool is provided, a default pool provided 50 // by the mem package is used. 51 func NewFramerBridge(w io.Writer, r io.Reader, maxHeaderListSize uint32, pool mem.BufferPool) *FramerBridge { 52 fr := http2.NewFramer(w, r) 53 fr.SetReuseFrames() 54 fr.MaxHeaderListSize = maxHeaderListSize 55 fr.ReadMetaHeaders = hpack.NewDecoder(initHeaderTableSize, nil) 56 57 if pool == nil { 58 pool = mem.DefaultBufferPool() 59 } 60 61 return &FramerBridge{ 62 framer: fr, 63 pool: pool, 64 } 65 } 66 67 // ReadFrame reads a frame from the underlying http2.Framer and returns a 68 // Frame defined in the grpchttp2 package. This operation copies the data to a 69 // buffer from the pool, making it safe to use even after another call to 70 // ReadFrame. 71 func (fr *FramerBridge) ReadFrame() (Frame, error) { 72 f, err := fr.framer.ReadFrame() 73 if err != nil { 74 return nil, err 75 } 76 77 h := f.Header() 78 hdr := &FrameHeader{ 79 Size: h.Length, 80 Type: FrameType(h.Type), 81 Flags: Flag(h.Flags), 82 StreamID: h.StreamID, 83 } 84 85 switch f := f.(type) { 86 case *http2.DataFrame: 87 buf := fr.pool.Get(int(hdr.Size)) 88 copy(*buf, f.Data()) 89 return &DataFrame{ 90 hdr: hdr, 91 Data: *buf, 92 free: func() { fr.pool.Put(buf) }, 93 }, nil 94 case *http2.RSTStreamFrame: 95 return &RSTStreamFrame{ 96 hdr: hdr, 97 Code: ErrCode(f.ErrCode), 98 }, nil 99 case *http2.SettingsFrame: 100 buf := make([]Setting, 0, f.NumSettings()) 101 f.ForeachSetting(func(s http2.Setting) error { 102 buf = append(buf, Setting{ 103 ID: SettingID(s.ID), 104 Value: s.Val, 105 }) 106 return nil 107 }) 108 return &SettingsFrame{ 109 hdr: hdr, 110 Settings: buf, 111 }, nil 112 case *http2.PingFrame: 113 buf := fr.pool.Get(int(hdr.Size)) 114 copy(*buf, f.Data[:]) 115 return &PingFrame{ 116 hdr: hdr, 117 Data: *buf, 118 free: func() { fr.pool.Put(buf) }, 119 }, nil 120 case *http2.GoAwayFrame: 121 // Size of the frame minus the code and lastStreamID 122 buf := fr.pool.Get(int(hdr.Size) - 8) 123 copy(*buf, f.DebugData()) 124 return &GoAwayFrame{ 125 hdr: hdr, 126 LastStreamID: f.LastStreamID, 127 Code: ErrCode(f.ErrCode), 128 DebugData: *buf, 129 free: func() { fr.pool.Put(buf) }, 130 }, nil 131 case *http2.WindowUpdateFrame: 132 return &WindowUpdateFrame{ 133 hdr: hdr, 134 Inc: f.Increment, 135 }, nil 136 case *http2.MetaHeadersFrame: 137 return &MetaHeadersFrame{ 138 hdr: hdr, 139 Fields: f.Fields, 140 }, nil 141 default: 142 buf := fr.pool.Get(int(hdr.Size)) 143 uf := f.(*http2.UnknownFrame) 144 copy(*buf, uf.Payload()) 145 return &UnknownFrame{ 146 hdr: hdr, 147 Payload: *buf, 148 free: func() { fr.pool.Put(buf) }, 149 }, nil 150 } 151 } 152 153 // WriteData writes a DATA Frame into the underlying writer. 154 func (fr *FramerBridge) WriteData(streamID uint32, endStream bool, data ...[]byte) error { 155 if len(data) == 1 { 156 return fr.framer.WriteData(streamID, endStream, data[0]) 157 } 158 159 tl := 0 160 for _, s := range data { 161 tl += len(s) 162 } 163 164 buf := fr.pool.Get(tl) 165 *buf = (*buf)[:0] 166 defer fr.pool.Put(buf) 167 for _, s := range data { 168 *buf = append(*buf, s...) 169 } 170 171 return fr.framer.WriteData(streamID, endStream, *buf) 172 } 173 174 // WriteHeaders writes a Headers Frame into the underlying writer. 175 func (fr *FramerBridge) WriteHeaders(streamID uint32, endStream, endHeaders bool, headerBlock []byte) error { 176 return fr.framer.WriteHeaders(http2.HeadersFrameParam{ 177 StreamID: streamID, 178 EndStream: endStream, 179 EndHeaders: endHeaders, 180 BlockFragment: headerBlock, 181 }) 182 } 183 184 // WriteRSTStream writes a RSTStream Frame into the underlying writer. 185 func (fr *FramerBridge) WriteRSTStream(streamID uint32, code ErrCode) error { 186 return fr.framer.WriteRSTStream(streamID, http2.ErrCode(code)) 187 } 188 189 // WriteSettings writes a Settings Frame into the underlying writer. 190 func (fr *FramerBridge) WriteSettings(settings ...Setting) error { 191 ss := make([]http2.Setting, 0, len(settings)) 192 for _, s := range settings { 193 ss = append(ss, http2.Setting{ 194 ID: http2.SettingID(s.ID), 195 Val: s.Value, 196 }) 197 } 198 199 return fr.framer.WriteSettings(ss...) 200 } 201 202 // WriteSettingsAck writes a Settings Frame with the Ack flag set. 203 func (fr *FramerBridge) WriteSettingsAck() error { 204 return fr.framer.WriteSettingsAck() 205 } 206 207 // WritePing writes a Ping frame to the underlying writer. 208 func (fr *FramerBridge) WritePing(ack bool, data [8]byte) error { 209 return fr.framer.WritePing(ack, data) 210 } 211 212 // WriteGoAway writes a GoAway Frame to the underlying writer. 213 func (fr *FramerBridge) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error { 214 return fr.framer.WriteGoAway(maxStreamID, http2.ErrCode(code), debugData) 215 } 216 217 // WriteWindowUpdate writes a WindowUpdate Frame into the underlying writer. 218 func (fr *FramerBridge) WriteWindowUpdate(streamID, inc uint32) error { 219 return fr.framer.WriteWindowUpdate(streamID, inc) 220 } 221 222 // WriteContinuation writes a Continuation Frame into the underlying writer. 223 func (fr *FramerBridge) WriteContinuation(streamID uint32, endHeaders bool, headerBlock []byte) error { 224 return fr.framer.WriteContinuation(streamID, endHeaders, headerBlock) 225 }