google.golang.org/grpc@v1.72.2/internal/transport/server_stream.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 transport
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"strings"
    25  	"sync"
    26  	"sync/atomic"
    27  
    28  	"google.golang.org/grpc/mem"
    29  	"google.golang.org/grpc/metadata"
    30  	"google.golang.org/grpc/status"
    31  )
    32  
    33  // ServerStream implements streaming functionality for a gRPC server.
    34  type ServerStream struct {
    35  	*Stream // Embed for common stream functionality.
    36  
    37  	st      internalServerTransport
    38  	ctxDone <-chan struct{} // closed at the end of stream.  Cache of ctx.Done() (for performance)
    39  	// cancel is invoked at the end of stream to cancel ctx. It also stops the
    40  	// timer for monitoring the rpc deadline if configured.
    41  	cancel func()
    42  
    43  	// Holds compressor names passed in grpc-accept-encoding metadata from the
    44  	// client.
    45  	clientAdvertisedCompressors string
    46  	headerWireLength            int
    47  
    48  	// hdrMu protects outgoing header and trailer metadata.
    49  	hdrMu      sync.Mutex
    50  	header     metadata.MD // the outgoing header metadata.  Updated by WriteHeader.
    51  	headerSent atomic.Bool // atomically set when the headers are sent out.
    52  }
    53  
    54  // Read reads an n byte message from the input stream.
    55  func (s *ServerStream) Read(n int) (mem.BufferSlice, error) {
    56  	b, err := s.Stream.read(n)
    57  	if err == nil {
    58  		s.st.incrMsgRecv()
    59  	}
    60  	return b, err
    61  }
    62  
    63  // SendHeader sends the header metadata for the given stream.
    64  func (s *ServerStream) SendHeader(md metadata.MD) error {
    65  	return s.st.writeHeader(s, md)
    66  }
    67  
    68  // Write writes the hdr and data bytes to the output stream.
    69  func (s *ServerStream) Write(hdr []byte, data mem.BufferSlice, opts *WriteOptions) error {
    70  	return s.st.write(s, hdr, data, opts)
    71  }
    72  
    73  // WriteStatus sends the status of a stream to the client.  WriteStatus is
    74  // the final call made on a stream and always occurs.
    75  func (s *ServerStream) WriteStatus(st *status.Status) error {
    76  	return s.st.writeStatus(s, st)
    77  }
    78  
    79  // isHeaderSent indicates whether headers have been sent.
    80  func (s *ServerStream) isHeaderSent() bool {
    81  	return s.headerSent.Load()
    82  }
    83  
    84  // updateHeaderSent updates headerSent and returns true
    85  // if it was already set.
    86  func (s *ServerStream) updateHeaderSent() bool {
    87  	return s.headerSent.Swap(true)
    88  }
    89  
    90  // RecvCompress returns the compression algorithm applied to the inbound
    91  // message. It is empty string if there is no compression applied.
    92  func (s *ServerStream) RecvCompress() string {
    93  	return s.recvCompress
    94  }
    95  
    96  // SendCompress returns the send compressor name.
    97  func (s *ServerStream) SendCompress() string {
    98  	return s.sendCompress
    99  }
   100  
   101  // ContentSubtype returns the content-subtype for a request. For example, a
   102  // content-subtype of "proto" will result in a content-type of
   103  // "application/grpc+proto". This will always be lowercase.  See
   104  // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
   105  // more details.
   106  func (s *ServerStream) ContentSubtype() string {
   107  	return s.contentSubtype
   108  }
   109  
   110  // SetSendCompress sets the compression algorithm to the stream.
   111  func (s *ServerStream) SetSendCompress(name string) error {
   112  	if s.isHeaderSent() || s.getState() == streamDone {
   113  		return errors.New("transport: set send compressor called after headers sent or stream done")
   114  	}
   115  
   116  	s.sendCompress = name
   117  	return nil
   118  }
   119  
   120  // SetContext sets the context of the stream. This will be deleted once the
   121  // stats handler callouts all move to gRPC layer.
   122  func (s *ServerStream) SetContext(ctx context.Context) {
   123  	s.ctx = ctx
   124  }
   125  
   126  // ClientAdvertisedCompressors returns the compressor names advertised by the
   127  // client via grpc-accept-encoding header.
   128  func (s *ServerStream) ClientAdvertisedCompressors() []string {
   129  	values := strings.Split(s.clientAdvertisedCompressors, ",")
   130  	for i, v := range values {
   131  		values[i] = strings.TrimSpace(v)
   132  	}
   133  	return values
   134  }
   135  
   136  // Header returns the header metadata of the stream.  It returns the out header
   137  // after t.WriteHeader is called.  It does not block and must not be called
   138  // until after WriteHeader.
   139  func (s *ServerStream) Header() (metadata.MD, error) {
   140  	// Return the header in stream. It will be the out
   141  	// header after t.WriteHeader is called.
   142  	return s.header.Copy(), nil
   143  }
   144  
   145  // HeaderWireLength returns the size of the headers of the stream as received
   146  // from the wire.
   147  func (s *ServerStream) HeaderWireLength() int {
   148  	return s.headerWireLength
   149  }
   150  
   151  // SetHeader sets the header metadata. This can be called multiple times.
   152  // This should not be called in parallel to other data writes.
   153  func (s *ServerStream) SetHeader(md metadata.MD) error {
   154  	if md.Len() == 0 {
   155  		return nil
   156  	}
   157  	if s.isHeaderSent() || s.getState() == streamDone {
   158  		return ErrIllegalHeaderWrite
   159  	}
   160  	s.hdrMu.Lock()
   161  	s.header = metadata.Join(s.header, md)
   162  	s.hdrMu.Unlock()
   163  	return nil
   164  }
   165  
   166  // SetTrailer sets the trailer metadata which will be sent with the RPC status
   167  // by the server. This can be called multiple times.
   168  // This should not be called parallel to other data writes.
   169  func (s *ServerStream) SetTrailer(md metadata.MD) error {
   170  	if md.Len() == 0 {
   171  		return nil
   172  	}
   173  	if s.getState() == streamDone {
   174  		return ErrIllegalHeaderWrite
   175  	}
   176  	s.hdrMu.Lock()
   177  	s.trailer = metadata.Join(s.trailer, md)
   178  	s.hdrMu.Unlock()
   179  	return nil
   180  }