@@ -43,6 +43,7 @@ import (
4343 "google.golang.org/grpc"
4444 "google.golang.org/grpc/credentials"
4545 "google.golang.org/grpc/credentials/insecure"
46+ "google.golang.org/grpc/metadata"
4647)
4748
4849const (
@@ -53,16 +54,17 @@ type flags struct {
5354 LogLevel string `kong:"enum='error,warn,info,debug',help='Log level.',default='info'"`
5455
5556 Upload struct {
56- StoreAddress string `kong:"required,help='gRPC address to sends symbols to.'"`
57- BearerToken string `kong:"help='Bearer token to authenticate with store.',env='PARCA_DEBUGINFO_BEARER_TOKEN'"`
58- BearerTokenFile string `kong:"help='File to read bearer token from to authenticate with store.'"`
59- Insecure bool `kong:"help='Send gRPC requests via plaintext instead of TLS.'"`
60- InsecureSkipVerify bool `kong:"help='Skip TLS certificate verification.'"`
61- NoExtract bool `kong:"help='Do not extract debug information from binaries, just upload the binary as is.'"`
62- NoInitiate bool `kong:"help='Do not initiate the upload, just check if it should be initiated.'"`
63- Force bool `kong:"help='Force upload even if the Build ID is already uploaded.'"`
64- Type string `kong:"enum='debuginfo,executable,sources',help='Type of the debug information to upload.',default='debuginfo'"`
65- BuildID string `kong:"help='Build ID of the binary to upload.'"`
57+ StoreAddress string `kong:"required,help='gRPC address to sends symbols to.'"`
58+ BearerToken string `kong:"help='Bearer token to authenticate with store.',env='PARCA_DEBUGINFO_BEARER_TOKEN'"`
59+ BearerTokenFile string `kong:"help='File to read bearer token from to authenticate with store.'"`
60+ Insecure bool `kong:"help='Send gRPC requests via plaintext instead of TLS.'"`
61+ InsecureSkipVerify bool `kong:"help='Skip TLS certificate verification.'"`
62+ GRPCHeaders map [string ]string `kong:"help='Additional gRPC headers to send with each request (key=value pairs).'"`
63+ NoExtract bool `kong:"help='Do not extract debug information from binaries, just upload the binary as is.'"`
64+ NoInitiate bool `kong:"help='Do not initiate the upload, just check if it should be initiated.'"`
65+ Force bool `kong:"help='Force upload even if the Build ID is already uploaded.'"`
66+ Type string `kong:"enum='debuginfo,executable,sources',help='Type of the debug information to upload.',default='debuginfo'"`
67+ BuildID string `kong:"help='Build ID of the binary to upload.'"`
6668
6769 Path string `kong:"required,arg,name='path',help='Paths to upload.',type:'path'"`
6870 } `cmd:"" help:"Upload debug information files."`
@@ -429,10 +431,21 @@ func grpcConn(reg prometheus.Registerer, flags flags) (*grpc.ClientConn, error)
429431 met .EnableClientHandlingTimeHistogram ()
430432 reg .MustRegister (met )
431433
434+ unaryInterceptors := []grpc.UnaryClientInterceptor {
435+ met .UnaryClientInterceptor (),
436+ }
437+ streamInterceptors := []grpc.StreamClientInterceptor {}
438+
439+ if len (flags .Upload .GRPCHeaders ) > 0 {
440+ unaryInterceptors = append ([]grpc.UnaryClientInterceptor {
441+ customHeadersUnaryInterceptor (flags .Upload .GRPCHeaders )}, unaryInterceptors ... )
442+ streamInterceptors = append ([]grpc.StreamClientInterceptor {
443+ customHeadersStreamInterceptor (flags .Upload .GRPCHeaders )}, streamInterceptors ... )
444+ }
445+
432446 opts := []grpc.DialOption {
433- grpc .WithUnaryInterceptor (
434- met .UnaryClientInterceptor (),
435- ),
447+ grpc .WithChainUnaryInterceptor (unaryInterceptors ... ),
448+ grpc .WithChainStreamInterceptor (streamInterceptors ... ),
436449 }
437450 if flags .Upload .Insecure {
438451 opts = append (opts , grpc .WithTransportCredentials (insecure .NewCredentials ()))
@@ -480,6 +493,24 @@ func (t *perRequestBearerToken) RequireTransportSecurity() bool {
480493 return ! t .insecure
481494}
482495
496+ func customHeadersUnaryInterceptor (headers map [string ]string ) grpc.UnaryClientInterceptor {
497+ return func (ctx context.Context , method string , req , reply interface {}, cc * grpc.ClientConn , invoker grpc.UnaryInvoker , opts ... grpc.CallOption ) error {
498+ for key , value := range headers {
499+ ctx = metadata .AppendToOutgoingContext (ctx , key , value )
500+ }
501+ return invoker (ctx , method , req , reply , cc , opts ... )
502+ }
503+ }
504+
505+ func customHeadersStreamInterceptor (headers map [string ]string ) grpc.StreamClientInterceptor {
506+ return func (ctx context.Context , desc * grpc.StreamDesc , cc * grpc.ClientConn , method string , streamer grpc.Streamer , opts ... grpc.CallOption ) (grpc.ClientStream , error ) {
507+ for key , value := range headers {
508+ ctx = metadata .AppendToOutgoingContext (ctx , key , value )
509+ }
510+ return streamer (ctx , desc , cc , method , opts ... )
511+ }
512+ }
513+
483514func uploadViaSignedURL (ctx context.Context , url string , r io.Reader ) error {
484515 req , err := http .NewRequestWithContext (ctx , http .MethodPut , url , r )
485516 if err != nil {
0 commit comments