@@ -27,6 +27,7 @@ import (
27
27
"cdr.dev/slog"
28
28
29
29
"github.com/charmbracelet/lipgloss"
30
+ "github.com/gobwas/httphead"
30
31
"github.com/mattn/go-isatty"
31
32
32
33
"github.com/coder/coder/buildinfo"
@@ -428,9 +429,9 @@ type RootCmd struct {
428
429
noFeatureWarning bool
429
430
}
430
431
431
- func telemetryInvocation ( i * clibase.Invocation ) telemetry. CLIInvocation {
432
+ func addTelemetryHeader ( client * codersdk. Client , inv * clibase.Invocation ) {
432
433
var topts []telemetry.CLIOption
433
- for _ , opt := range i .Command .FullOptions () {
434
+ for _ , opt := range inv .Command .FullOptions () {
434
435
if opt .ValueSource == clibase .ValueSourceNone || opt .ValueSource == clibase .ValueSourceDefault {
435
436
continue
436
437
}
@@ -439,11 +440,29 @@ func telemetryInvocation(i *clibase.Invocation) telemetry.CLIInvocation {
439
440
ValueSource : string (opt .ValueSource ),
440
441
})
441
442
}
442
- return telemetry.CLIInvocation {
443
- Command : i .Command .FullName (),
443
+ ti := telemetry.CLIInvocation {
444
+ Command : inv .Command .FullName (),
444
445
Options : topts ,
445
446
InvokedAt : time .Now (),
446
447
}
448
+
449
+ byt , err := json .Marshal (ti )
450
+ if err != nil {
451
+ // Should be impossible
452
+ panic (err )
453
+ }
454
+
455
+ // Per https://stackoverflow.com/questions/686217/maximum-on-http-header-values,
456
+ // we don't want to send headers that are too long.
457
+ s := base64 .StdEncoding .EncodeToString (byt )
458
+ if len (s ) > 4096 {
459
+ return
460
+ }
461
+
462
+ client .ExtraHeaders .Set (
463
+ codersdk .CLITelemetryHeader ,
464
+ s ,
465
+ )
447
466
}
448
467
449
468
// InitClient sets client to a new client.
@@ -456,7 +475,7 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc {
456
475
panic ("root is nil" )
457
476
}
458
477
return func (next clibase.HandlerFunc ) clibase.HandlerFunc {
459
- return func (i * clibase.Invocation ) error {
478
+ return func (inv * clibase.Invocation ) error {
460
479
conf := r .createConfig ()
461
480
var err error
462
481
if r .clientURL == nil || r .clientURL .String () == "" {
@@ -485,23 +504,15 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc {
485
504
return err
486
505
}
487
506
}
488
-
489
- telemInv := telemetryInvocation (i )
490
- byt , err := json .Marshal (telemInv )
491
- if err != nil {
492
- // Should be impossible
493
- panic (err )
494
- }
495
507
err = r .setClient (
496
508
client , r .clientURL ,
497
- append (r .header , codersdk .CLITelemetryHeader + "=" +
498
- base64 .StdEncoding .EncodeToString (byt ),
499
- ),
500
509
)
501
510
if err != nil {
502
511
return err
503
512
}
504
513
514
+ addTelemetryHeader (client , inv )
515
+
505
516
client .SetSessionToken (r .token )
506
517
507
518
if r .debugHTTP {
@@ -515,57 +526,58 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc {
515
526
warningErr = make (chan error )
516
527
)
517
528
go func () {
518
- versionErr <- r .checkVersions (i , client )
529
+ versionErr <- r .checkVersions (inv , client )
519
530
close (versionErr )
520
531
}()
521
532
522
533
go func () {
523
- warningErr <- r .checkWarnings (i , client )
534
+ warningErr <- r .checkWarnings (inv , client )
524
535
close (warningErr )
525
536
}()
526
537
527
538
if err = <- versionErr ; err != nil {
528
539
// Just log the error here. We never want to fail a command
529
540
// due to a pre-run.
530
- _ , _ = fmt .Fprintf (i .Stderr ,
541
+ _ , _ = fmt .Fprintf (inv .Stderr ,
531
542
cliui .Styles .Warn .Render ("check versions error: %s" ), err )
532
- _ , _ = fmt .Fprintln (i .Stderr )
543
+ _ , _ = fmt .Fprintln (inv .Stderr )
533
544
}
534
545
535
546
if err = <- warningErr ; err != nil {
536
547
// Same as above
537
- _ , _ = fmt .Fprintf (i .Stderr ,
548
+ _ , _ = fmt .Fprintf (inv .Stderr ,
538
549
cliui .Styles .Warn .Render ("check entitlement warnings error: %s" ), err )
539
- _ , _ = fmt .Fprintln (i .Stderr )
550
+ _ , _ = fmt .Fprintln (inv .Stderr )
540
551
}
541
552
542
- return next (i )
553
+ return next (inv )
543
554
}
544
555
}
545
556
}
546
557
547
- func (* RootCmd ) setClient (client * codersdk.Client , serverURL * url.URL , headers [] string ) error {
558
+ func (r * RootCmd ) setClient (client * codersdk.Client , serverURL * url.URL ) error {
548
559
transport := & headerTransport {
549
560
transport : http .DefaultTransport ,
550
561
header : http.Header {},
551
562
}
552
- for _ , header := range headers {
553
- parts := strings .SplitN (header , "=" , 2 )
554
- if len (parts ) < 2 {
555
- return xerrors .Errorf ("split header %q had less than two parts" , header )
556
- }
557
- transport .header .Add (parts [0 ], parts [1 ])
558
- }
559
563
client .URL = serverURL
560
564
client .HTTPClient = & http.Client {
561
565
Transport : transport ,
562
566
}
567
+ client .ExtraHeaders = make (http.Header )
568
+ for _ , hd := range r .header {
569
+ k , v , ok := httphead .ParseHeaderLine ([]byte (hd ))
570
+ if ! ok {
571
+ return xerrors .Errorf ("invalid header: %s" , hd )
572
+ }
573
+ client .ExtraHeaders .Add (string (k ), string (v ))
574
+ }
563
575
return nil
564
576
}
565
577
566
578
func (r * RootCmd ) createUnauthenticatedClient (serverURL * url.URL ) (* codersdk.Client , error ) {
567
579
var client codersdk.Client
568
- err := r .setClient (& client , serverURL , r . header )
580
+ err := r .setClient (& client , serverURL )
569
581
return & client , err
570
582
}
571
583
0 commit comments