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  }