github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/net/http2/writesched.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http2
     6  
     7  import "fmt"
     8  
     9  // WriteScheduler is the interface implemented by HTTP/2 write schedulers.
    10  // Methods are never called concurrently.
    11  type WriteScheduler interface {
    12  	// OpenStream opens a new stream in the write scheduler.
    13  	// It is illegal to call this with streamID=0 or with a streamID that is
    14  	// already open -- the call may panic.
    15  	OpenStream(streamID uint32, options OpenStreamOptions)
    16  
    17  	// CloseStream closes a stream in the write scheduler. Any frames queued on
    18  	// this stream should be discarded. It is illegal to call this on a stream
    19  	// that is not open -- the call may panic.
    20  	CloseStream(streamID uint32)
    21  
    22  	// AdjustStream adjusts the priority of the given stream. This may be called
    23  	// on a stream that has not yet been opened or has been closed. Note that
    24  	// RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
    25  	// https://tools.ietf.org/html/rfc7540#section-5.1
    26  	AdjustStream(streamID uint32, priority PriorityParam)
    27  
    28  	// Push queues a frame in the scheduler. In most cases, this will not be
    29  	// called with wr.StreamID()!=0 unless that stream is currently open. The one
    30  	// exception is RST_STREAM frames, which may be sent on idle or closed streams.
    31  	Push(wr FrameWriteRequest)
    32  
    33  	// Pop dequeues the next frame to write. Returns false if no frames can
    34  	// be written. Frames with a given wr.StreamID() are Pop'd in the same
    35  	// order they are Push'd, except RST_STREAM frames. No frames should be
    36  	// discarded except by CloseStream.
    37  	Pop() (wr FrameWriteRequest, ok bool)
    38  }
    39  
    40  // OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
    41  type OpenStreamOptions struct {
    42  	// PusherID is zero if the stream was initiated by the client. Otherwise,
    43  	// PusherID names the stream that pushed the newly opened stream.
    44  	PusherID uint32
    45  }
    46  
    47  // FrameWriteRequest is a request to write a frame.
    48  type FrameWriteRequest struct {
    49  	// write is the interface value that does the writing, once the
    50  	// WriteScheduler has selected this frame to write. The write
    51  	// functions are all defined in write.go.
    52  	write writeFramer
    53  
    54  	// stream is the stream on which this frame will be written.
    55  	// nil for non-stream frames like PING and SETTINGS.
    56  	// nil for RST_STREAM streams, which use the StreamError.StreamID field instead.
    57  	stream *stream
    58  
    59  	// done, if non-nil, must be a buffered channel with space for
    60  	// 1 message and is sent the return value from write (or an
    61  	// earlier error) when the frame has been written.
    62  	done chan error
    63  }
    64  
    65  // StreamID returns the id of the stream this frame will be written to.
    66  // 0 is used for non-stream frames such as PING and SETTINGS.
    67  func (wr FrameWriteRequest) StreamID() uint32 {
    68  	if wr.stream == nil {
    69  		if se, ok := wr.write.(StreamError); ok {
    70  			// (*serverConn).resetStream doesn't set
    71  			// stream because it doesn't necessarily have
    72  			// one. So special case this type of write
    73  			// message.
    74  			return se.StreamID
    75  		}
    76  		return 0
    77  	}
    78  	return wr.stream.id
    79  }
    80  
    81  // isControl reports whether wr is a control frame for MaxQueuedControlFrames
    82  // purposes. That includes non-stream frames and RST_STREAM frames.
    83  func (wr FrameWriteRequest) isControl() bool {
    84  	return wr.stream == nil
    85  }
    86  
    87  // DataSize returns the number of flow control bytes that must be consumed
    88  // to write this entire frame. This is 0 for non-DATA frames.
    89  func (wr FrameWriteRequest) DataSize() int {
    90  	if wd, ok := wr.write.(*writeData); ok {
    91  		return len(wd.p)
    92  	}
    93  	return 0
    94  }
    95  
    96  // Consume consumes min(n, available) bytes from this frame, where available
    97  // is the number of flow control bytes available on the stream. Consume returns
    98  // 0, 1, or 2 frames, where the integer return value gives the number of frames
    99  // returned.
   100  //
   101  // If flow control prevents consuming any bytes, this returns (_, _, 0). If
   102  // the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
   103  // returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
   104  // 'rest' contains the remaining bytes. The consumed bytes are deducted from the
   105  // underlying stream's flow control budget.
   106  func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
   107  	var empty FrameWriteRequest
   108  
   109  	// Non-DATA frames are always consumed whole.
   110  	wd, ok := wr.write.(*writeData)
   111  	if !ok || len(wd.p) == 0 {
   112  		return wr, empty, 1
   113  	}
   114  
   115  	// Might need to split after applying limits.
   116  	allowed := wr.stream.flow.available()
   117  	if n < allowed {
   118  		allowed = n
   119  	}
   120  	if wr.stream.sc.maxFrameSize < allowed {
   121  		allowed = wr.stream.sc.maxFrameSize
   122  	}
   123  	if allowed <= 0 {
   124  		return empty, empty, 0
   125  	}
   126  	if len(wd.p) > int(allowed) {
   127  		wr.stream.flow.take(allowed)
   128  		consumed := FrameWriteRequest{
   129  			stream: wr.stream,
   130  			write: &writeData{
   131  				streamID: wd.streamID,
   132  				p:        wd.p[:allowed],
   133  				// Even if the original had endStream set, there
   134  				// are bytes remaining because len(wd.p) > allowed,
   135  				// so we know endStream is false.
   136  				endStream: false,
   137  			},
   138  			// Our caller is blocking on the final DATA frame, not
   139  			// this intermediate frame, so no need to wait.
   140  			done: nil,
   141  		}
   142  		rest := FrameWriteRequest{
   143  			stream: wr.stream,
   144  			write: &writeData{
   145  				streamID:  wd.streamID,
   146  				p:         wd.p[allowed:],
   147  				endStream: wd.endStream,
   148  			},
   149  			done: wr.done,
   150  		}
   151  		return consumed, rest, 2
   152  	}
   153  
   154  	// The frame is consumed whole.
   155  	// NB: This cast cannot overflow because allowed is <= math.MaxInt32.
   156  	wr.stream.flow.take(int32(len(wd.p)))
   157  	return wr, empty, 1
   158  }
   159  
   160  // String is for debugging only.
   161  func (wr FrameWriteRequest) String() string {
   162  	var des string
   163  	if s, ok := wr.write.(fmt.Stringer); ok {
   164  		des = s.String()
   165  	} else {
   166  		des = fmt.Sprintf("%T", wr.write)
   167  	}
   168  	return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
   169  }
   170  
   171  // replyToWriter sends err to wr.done and panics if the send must block
   172  // This does nothing if wr.done is nil.
   173  func (wr *FrameWriteRequest) replyToWriter(err error) {
   174  	if wr.done == nil {
   175  		return
   176  	}
   177  	select {
   178  	case wr.done <- err:
   179  	default:
   180  		panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
   181  	}
   182  	wr.write = nil // prevent use (assume it's tainted after wr.done send)
   183  }
   184  
   185  // writeQueue is used by implementations of WriteScheduler.
   186  type writeQueue struct {
   187  	s          []FrameWriteRequest
   188  	prev, next *writeQueue
   189  }
   190  
   191  func (q *writeQueue) empty() bool { return len(q.s) == 0 }
   192  
   193  func (q *writeQueue) push(wr FrameWriteRequest) {
   194  	q.s = append(q.s, wr)
   195  }
   196  
   197  func (q *writeQueue) shift() FrameWriteRequest {
   198  	if len(q.s) == 0 {
   199  		panic("invalid use of queue")
   200  	}
   201  	wr := q.s[0]
   202  	// TODO: less copy-happy queue.
   203  	copy(q.s, q.s[1:])
   204  	q.s[len(q.s)-1] = FrameWriteRequest{}
   205  	q.s = q.s[:len(q.s)-1]
   206  	return wr
   207  }
   208  
   209  // consume consumes up to n bytes from q.s[0]. If the frame is
   210  // entirely consumed, it is removed from the queue. If the frame
   211  // is partially consumed, the frame is kept with the consumed
   212  // bytes removed. Returns true iff any bytes were consumed.
   213  func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
   214  	if len(q.s) == 0 {
   215  		return FrameWriteRequest{}, false
   216  	}
   217  	consumed, rest, numresult := q.s[0].Consume(n)
   218  	switch numresult {
   219  	case 0:
   220  		return FrameWriteRequest{}, false
   221  	case 1:
   222  		q.shift()
   223  	case 2:
   224  		q.s[0] = rest
   225  	}
   226  	return consumed, true
   227  }
   228  
   229  type writeQueuePool []*writeQueue
   230  
   231  // put inserts an unused writeQueue into the pool.
   232  func (p *writeQueuePool) put(q *writeQueue) {
   233  	for i := range q.s {
   234  		q.s[i] = FrameWriteRequest{}
   235  	}
   236  	q.s = q.s[:0]
   237  	*p = append(*p, q)
   238  }
   239  
   240  // get returns an empty writeQueue.
   241  func (p *writeQueuePool) get() *writeQueue {
   242  	ln := len(*p)
   243  	if ln == 0 {
   244  		return new(writeQueue)
   245  	}
   246  	x := ln - 1
   247  	q := (*p)[x]
   248  	(*p)[x] = nil
   249  	*p = (*p)[:x]
   250  	return q
   251  }