| 860 | } |
| 861 | |
| 862 | func (cs *clientStream) Header() (metadata.MD, error) { |
| 863 | var m metadata.MD |
| 864 | err := cs.withRetry(func(a *csAttempt) error { |
| 865 | var err error |
| 866 | m, err = a.transportStream.Header() |
| 867 | return toRPCErr(err) |
| 868 | }, cs.commitAttemptLocked) |
| 869 | |
| 870 | if m == nil && err == nil { |
| 871 | // The stream ended with success. Finish the clientStream. |
| 872 | err = io.EOF |
| 873 | } |
| 874 | |
| 875 | if err != nil { |
| 876 | cs.finish(err) |
| 877 | // Do not return the error. The user should get it by calling Recv(). |
| 878 | return nil, nil |
| 879 | } |
| 880 | |
| 881 | if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged && m != nil { |
| 882 | // Only log if binary log is on and header has not been logged, and |
| 883 | // there is actually headers to log. |
| 884 | logEntry := &binarylog.ServerHeader{ |
| 885 | OnClientSide: true, |
| 886 | Header: m, |
| 887 | PeerAddr: nil, |
| 888 | } |
| 889 | if peer, ok := peer.FromContext(cs.Context()); ok { |
| 890 | logEntry.PeerAddr = peer.Addr |
| 891 | } |
| 892 | cs.serverHeaderBinlogged = true |
| 893 | for _, binlog := range cs.binlogs { |
| 894 | binlog.Log(cs.ctx, logEntry) |
| 895 | } |
| 896 | } |
| 897 | |
| 898 | return m, nil |
| 899 | } |
| 900 | |
| 901 | func (cs *clientStream) Trailer() metadata.MD { |
| 902 | // On RPC failure, we never need to retry, because usage requires that |