github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/meta_api.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package nphttp2 18 19 import ( 20 "context" 21 "net" 22 23 "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/codes" 24 "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/metadata" 25 "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status" 26 "github.com/cloudwego/kitex/pkg/streaming" 27 ) 28 29 // SetHeader sets the header metadata to be sent from the server to the client. 30 // The context provided must be the context passed to the server's handler. 31 // 32 // Streaming RPCs should prefer the SetHeader method of the ServerStream. 33 // 34 // When called multiple times, all the provided metadata will be merged. All 35 // the metadata will be sent out when one of the following happens: 36 // 37 // - grpc.SendHeader is called, or for streaming handlers, stream.SendHeader. 38 // - The first response message is sent. For unary handlers, this occurs when 39 // the handler returns; for streaming handlers, this can happen when stream's 40 // SendMsg method is called. 41 // - An RPC status is sent out (error or success). This occurs when the handler 42 // returns. 43 // 44 // SetHeader will fail if called after any of the events above. 45 // 46 // The error returned is compatible with the status package. However, the 47 // status code will often not match the RPC status as seen by the client 48 // application, and therefore, should not be relied upon for this purpose. 49 func SetHeader(ctx context.Context, md metadata.MD) error { 50 if md.Len() == 0 { 51 return nil 52 } 53 stream := serverTransportStreamFromContext(ctx) 54 if stream == nil { 55 return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) 56 } 57 return stream.SetHeader(md) 58 } 59 60 // SendHeader sends header metadata. It may be called at most once, and may not 61 // be called after any event that causes headers to be sent (see SetHeader for 62 // a complete list). The provided md and headers set by SetHeader() will be 63 // sent. 64 // 65 // The error returned is compatible with the status package. However, the 66 // status code will often not match the RPC status as seen by the client 67 // application, and therefore, should not be relied upon for this purpose. 68 func SendHeader(ctx context.Context, md metadata.MD) error { 69 stream := serverTransportStreamFromContext(ctx) 70 if stream == nil { 71 return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) 72 } 73 if err := stream.SendHeader(md); err != nil { 74 return err 75 } 76 return nil 77 } 78 79 // SetTrailer sets the trailer metadata that will be sent when an RPC returns. 80 // When called more than once, all the provided metadata will be merged. 81 // 82 // The error returned is compatible with the status package. However, the 83 // status code will often not match the RPC status as seen by the client 84 // application, and therefore, should not be relied upon for this purpose. 85 func SetTrailer(ctx context.Context, md metadata.MD) error { 86 if md.Len() == 0 { 87 return nil 88 } 89 stream := serverTransportStreamFromContext(ctx) 90 if stream == nil { 91 return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) 92 } 93 stream.SetTrailer(md) 94 return nil 95 } 96 97 func serverTransportStreamFromContext(ctx context.Context) streaming.Stream { 98 return streaming.GetStream(ctx) 99 } 100 101 type ( 102 headerKey struct{} 103 trailerKey struct{} 104 ) 105 106 // GRPCHeader is used for unary call client to get header from response. 107 func GRPCHeader(ctx context.Context, md *metadata.MD) context.Context { 108 return context.WithValue(ctx, headerKey{}, md) 109 } 110 111 // GRPCTrailer is used for unary call client to get taiiler from response. 112 func GRPCTrailer(ctx context.Context, md *metadata.MD) context.Context { 113 return context.WithValue(ctx, trailerKey{}, md) 114 } 115 116 // GetHeaderMetadataFromCtx is used to get the metadata of stream Header from ctx. 117 func GetHeaderMetadataFromCtx(ctx context.Context) *metadata.MD { 118 header := ctx.Value(headerKey{}) 119 if header != nil { 120 return header.(*metadata.MD) 121 } 122 return nil 123 } 124 125 // set header and trailer to the ctx by default. 126 func receiveHeaderAndTrailer(ctx context.Context, conn net.Conn) context.Context { 127 if md, err := conn.(hasHeader).Header(); err == nil { 128 if h := ctx.Value(headerKey{}); h != nil { 129 // If using GRPCHeader(), set the value directly 130 hd := h.(*metadata.MD) 131 *hd = md 132 } else { 133 ctx = context.WithValue(ctx, headerKey{}, &md) 134 } 135 } 136 if md := conn.(hasTrailer).Trailer(); md != nil { 137 if t := ctx.Value(trailerKey{}); t != nil { 138 // If using GRPCTrailer(), set the value directly 139 tr := t.(*metadata.MD) 140 *tr = md 141 } else { 142 ctx = context.WithValue(ctx, trailerKey{}, &md) 143 } 144 } 145 return ctx 146 }