(s *ServerStream, st *status.Status)
| 226 | } |
| 227 | |
| 228 | func (ht *serverHandlerTransport) writeStatus(s *ServerStream, st *status.Status) error { |
| 229 | ht.writeStatusMu.Lock() |
| 230 | defer ht.writeStatusMu.Unlock() |
| 231 | |
| 232 | headersWritten := s.updateHeaderSent() |
| 233 | err := ht.do(func() { |
| 234 | if !headersWritten { |
| 235 | ht.writePendingHeaders(s) |
| 236 | } |
| 237 | |
| 238 | // And flush, in case no header or body has been sent yet. |
| 239 | // This forces a separation of headers and trailers if this is the |
| 240 | // first call (for example, in end2end tests's TestNoService). |
| 241 | ht.rw.(http.Flusher).Flush() |
| 242 | |
| 243 | h := ht.rw.Header() |
| 244 | h.Set("Grpc-Status", fmt.Sprintf("%d", st.Code())) |
| 245 | if m := st.Message(); m != "" { |
| 246 | h.Set("Grpc-Message", encodeGrpcMessage(m)) |
| 247 | } |
| 248 | |
| 249 | s.hdrMu.Lock() |
| 250 | defer s.hdrMu.Unlock() |
| 251 | if p := st.Proto(); p != nil && len(p.Details) > 0 { |
| 252 | delete(s.trailer, grpcStatusDetailsBinHeader) |
| 253 | stBytes, err := proto.Marshal(p) |
| 254 | if err != nil { |
| 255 | // TODO: return error instead, when callers are able to handle it. |
| 256 | panic(err) |
| 257 | } |
| 258 | |
| 259 | h.Set(grpcStatusDetailsBinHeader, encodeBinHeader(stBytes)) |
| 260 | } |
| 261 | |
| 262 | if len(s.trailer) > 0 { |
| 263 | for k, vv := range s.trailer { |
| 264 | // Clients don't tolerate reading restricted headers after some non restricted ones were sent. |
| 265 | if isReservedHeader(k) { |
| 266 | continue |
| 267 | } |
| 268 | for _, v := range vv { |
| 269 | // http2 ResponseWriter mechanism to send undeclared Trailers after |
| 270 | // the headers have possibly been written. |
| 271 | h.Add(http2.TrailerPrefix+k, encodeMetadataHeader(k, v)) |
| 272 | } |
| 273 | } |
| 274 | } |
| 275 | }) |
| 276 | |
| 277 | if err == nil && ht.stats != nil { // transport has not been closed |
| 278 | // Note: The trailer fields are compressed with hpack after this call returns. |
| 279 | // No WireLength field is set here. |
| 280 | s.hdrMu.Lock() |
| 281 | ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{ |
| 282 | Trailer: s.trailer.Copy(), |
| 283 | }) |
| 284 | s.hdrMu.Unlock() |
| 285 | } |
nothing calls this directly
no test coverage detected