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 }