github.com/google/martian/v3@v3.3.3/h2/queued_frames.go (about) 1 // Copyright 2021 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package h2 16 17 import ( 18 "bytes" 19 "fmt" 20 21 "golang.org/x/net/http2" 22 ) 23 24 // queuedFrame stores frames that belong to a stream and need to be kept in order. The need for 25 // this stems from flow control needed in the context of gRPC. Since a gRPC message can be split 26 // over multiple DATA frames, the proxy needs to buffer such frames so they can be reassembled 27 // into messages and edited before being forwarded. 28 // 29 // Note that the proxy does man-in-the-middle flow control independently to each endpoint instead 30 // of forwarding endpoint flow-control messages to each other directly. This is necessary because 31 // multiple DATA frames need to be captured before they can be forwarded. While the data frames are 32 // being held in the proxy, the destination of those frames cannot see them to send WINDOW_UPDATE 33 // acknowledgements and the sender will stop sending data. So the proxy must emit its own 34 // WINDOW_UPDATEs. 35 // 36 // Example: While DATA frames are being output-buffered due to pending WINDOW_UPDATE frames from 37 // the destination, it's possible for the source to send subsequent HEADER frames. Those HEADER 38 // frames must be queued after the DATA frames for consistency with HTTP/2's total ordering of 39 // frames within a stream. 40 // 41 // While the example only illustrates the need for HEADER frame buffering, a similar argument 42 // applies to other types of stream frames. WINDOW_UPDATE is a special case that is associated 43 // with a stream but does not require buffering or special ordering. This is because WINDOW_UPDATEs 44 // are basically acknowledgements for messages coming from the peer endpoint. In other words, 45 // WINDOW_UPDATE frames are associated with messages being received instead of messages being sent. 46 // The asynchrony of receiving remote messages should allow reordering freedom. 47 type queuedFrame interface { 48 // StreamID is the stream ID for the frame. 49 StreamID() uint32 50 51 // flowControlSize returns the size of this frame for the purposes of flow control. It is only 52 // non-zero for DATA frames. 53 flowControlSize() int 54 55 // send writes the frame to the provided framer. This is not thread-safe and the caller should be 56 // holding appropriate locks. 57 send(*http2.Framer) error 58 } 59 60 type queuedDataFrame struct { 61 streamID uint32 62 endStream bool 63 data []byte 64 } 65 66 func (f *queuedDataFrame) StreamID() uint32 { 67 return f.streamID 68 } 69 70 func (f *queuedDataFrame) flowControlSize() int { 71 return len(f.data) 72 } 73 74 func (f *queuedDataFrame) send(dest *http2.Framer) error { 75 return dest.WriteData(f.streamID, f.endStream, f.data) 76 } 77 78 func (f *queuedDataFrame) String() string { 79 return fmt.Sprintf("data[id=%d, endStream=%t, len=%d]", f.streamID, f.endStream, len(f.data)) 80 } 81 82 type queuedHeaderFrame struct { 83 streamID uint32 84 endStream bool 85 priority http2.PriorityParam 86 chunks [][]byte 87 } 88 89 func (f *queuedHeaderFrame) StreamID() uint32 { 90 return f.streamID 91 } 92 93 func (*queuedHeaderFrame) flowControlSize() int { 94 return 0 95 } 96 97 func (f *queuedHeaderFrame) send(dest *http2.Framer) error { 98 if err := dest.WriteHeaders(http2.HeadersFrameParam{ 99 StreamID: f.streamID, 100 BlockFragment: f.chunks[0], 101 EndStream: f.endStream, 102 EndHeaders: len(f.chunks) <= 1, 103 PadLength: 0, 104 Priority: f.priority, 105 }); err != nil { 106 return fmt.Errorf("sending header %v: %w", f, err) 107 } 108 for i := 1; i < len(f.chunks); i++ { 109 headersEnded := i == len(f.chunks)-1 110 if err := dest.WriteContinuation(f.streamID, headersEnded, f.chunks[i]); err != nil { 111 return fmt.Errorf("sending header continuations %v: %w", f, err) 112 } 113 } 114 return nil 115 } 116 117 func (f *queuedHeaderFrame) String() string { 118 var buf bytes.Buffer // strings.Builder is not available on App Engine. 119 fmt.Fprintf(&buf, "header[id=%d, endStream=%t", f.streamID, f.endStream) 120 fmt.Fprintf(&buf, ", priority=%v, chunk lengths=[", f.priority) 121 for i, c := range f.chunks { 122 if i > 0 { 123 fmt.Fprintf(&buf, ",") 124 } 125 fmt.Fprintf(&buf, "%d", len(c)) 126 } 127 fmt.Fprintf(&buf, "]]") 128 return buf.String() 129 } 130 131 type queuedPushPromiseFrame struct { 132 streamID uint32 133 promiseID uint32 134 chunks [][]byte 135 } 136 137 func (f *queuedPushPromiseFrame) StreamID() uint32 { 138 return f.streamID 139 } 140 141 func (*queuedPushPromiseFrame) flowControlSize() int { 142 return 0 143 } 144 145 func (f *queuedPushPromiseFrame) send(dest *http2.Framer) error { 146 if err := dest.WritePushPromise(http2.PushPromiseParam{ 147 StreamID: f.streamID, 148 PromiseID: f.promiseID, 149 BlockFragment: f.chunks[0], 150 EndHeaders: len(f.chunks) <= 1, 151 PadLength: 0, 152 }); err != nil { 153 return fmt.Errorf("sending push promise %v: %w", f, err) 154 } 155 for i := 1; i < len(f.chunks); i++ { 156 headersEnded := i == len(f.chunks)-1 157 if err := dest.WriteContinuation(f.streamID, headersEnded, f.chunks[i]); err != nil { 158 return fmt.Errorf("sending push promise continuations %v: %w", f, err) 159 } 160 } 161 return nil 162 } 163 164 func (f *queuedPushPromiseFrame) String() string { 165 var buf bytes.Buffer 166 fmt.Fprintf(&buf, "push promise[streamID=%d, promiseID= %d", f.streamID, f.promiseID) 167 fmt.Fprintf(&buf, ", chunk lengths=[") 168 for i, c := range f.chunks { 169 if i > 0 { 170 fmt.Fprintf(&buf, ",") 171 } 172 fmt.Fprintf(&buf, "%d", len(c)) 173 } 174 fmt.Fprintf(&buf, "]]") 175 return buf.String() 176 } 177 178 type queuedPriorityFrame struct { 179 streamID uint32 180 priority http2.PriorityParam 181 } 182 183 func (f *queuedPriorityFrame) StreamID() uint32 { 184 return f.streamID 185 } 186 187 func (*queuedPriorityFrame) flowControlSize() int { 188 return 0 189 } 190 191 func (f *queuedPriorityFrame) send(dest *http2.Framer) error { 192 if err := dest.WritePriority(f.streamID, f.priority); err != nil { 193 return fmt.Errorf("sending %v: %w", f, err) 194 } 195 return nil 196 } 197 198 func (f *queuedPriorityFrame) String() string { 199 return fmt.Sprintf("priority[id=%d, priority=%v]", f.streamID, f.priority) 200 } 201 202 type queuedRSTStreamFrame struct { 203 streamID uint32 204 errCode http2.ErrCode 205 } 206 207 func (f *queuedRSTStreamFrame) StreamID() uint32 { 208 return f.streamID 209 } 210 211 func (*queuedRSTStreamFrame) flowControlSize() int { 212 return 0 213 } 214 215 func (f *queuedRSTStreamFrame) send(dest *http2.Framer) error { 216 if err := dest.WriteRSTStream(f.streamID, f.errCode); err != nil { 217 return fmt.Errorf("sending %v: %w", f, err) 218 } 219 return nil 220 } 221 222 func (f *queuedRSTStreamFrame) String() string { 223 return fmt.Sprintf("RSTStream[id=%d, errCode=%v]", f.streamID, f.errCode) 224 }