Skip to content

fix: export ConfigureTLS helper for wrapped transports#73

Draft
MattDevy wants to merge 2 commits intomainfrom
flex/configure-tls-helper
Draft

fix: export ConfigureTLS helper for wrapped transports#73
MattDevy wants to merge 2 commits intomainfrom
flex/configure-tls-helper

Conversation

@MattDevy
Copy link
Copy Markdown
Contributor

@MattDevy MattDevy commented Feb 24, 2026

Summary

  • Extracts TLS configuration logic from New() into an exported ConfigureTLS helper (tls.go) so that wrapped transports (e.g. custom http.RoundTripper middleware) can reuse it directly.
  • Hardens the function against invalid input (nil transport, malformed fingerprint hex) and resource leaks (closes TLS connections on fingerprint mismatch).
  • Replaces the legacy tls.Dial with a context-aware tls.Dialer for fingerprint verification.
  • Skips CA cert pool setup when a fingerprint is set, since the custom DialTLSContext bypasses standard CA verification.
  • Returns a clear error when TLS options are provided with a non-*http.Transport transport.
  • Adds comprehensive unit tests for both ConfigureTLS and the updated New() integration paths.

Test plan

  • TestConfigureTLS covers nil transport, invalid CA cert, valid CA cert, invalid fingerprint hex, valid fingerprint, and fingerprint-takes-precedence-over-CACert scenarios.
  • TestTransportConfig covers CACert on default transport and TLS options on non-http.Transport error path.
  • Verify existing tests still pass: go test ./...

Export ConfigureTLS as a public helper so wrapped transports can reuse
the TLS configuration logic. Harden the function against invalid input
and resource leaks, skip dead root CAs when a fingerprint is set, and
use a context-aware TLS dialer.
@prodsecmachine
Copy link
Copy Markdown

prodsecmachine commented Feb 24, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Results

ubuntu-latest

goos: linux
goarch: amd64
pkg: github.com/elastic/elastic-transport-go/v8/elastictransport
cpu: AMD EPYC 7763 64-Core Processor                
                                                                           │ /home/runner/work/_temp/base.txt │   /home/runner/work/_temp/head.txt   │
                                                                           │              sec/op              │    sec/op      vs base               │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                                    446.0n ±  2%    440.9n ± 16%        ~ (p=0.383 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                                   503.1n ± 16%    495.1n ±  1%   -1.59% (p=0.017 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                                  698.0n ±  3%    686.1n ±  1%   -1.70% (p=0.001 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                                 751.7n ± 10%    790.0n ±  9%        ~ (p=1.000 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                                    600.2n ±  3%    649.3n ±  1%   +8.18% (p=0.001 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                                   586.0n ±  1%    650.0n ±  1%  +10.92% (p=0.001 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                                  647.0n ±  2%    698.5n ±  1%   +7.96% (p=0.001 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                                 825.6n ±  5%    821.4n ± 12%        ~ (p=0.456 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4                          627.3n ±  2%    618.3n ±  2%   -1.43% (p=0.004 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4                         611.5n ±  3%    604.4n ±  1%   -1.16% (p=0.026 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4                        666.2n ±  2%    657.0n ±  1%   -1.38% (p=0.024 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4                       832.9n ± 11%    873.8n ± 13%        ~ (p=0.620 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4                          539.0n ±  2%    545.8n ±  2%        ~ (p=0.165 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4                         561.2n ±  2%    566.6n ±  1%        ~ (p=0.165 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4                        631.2n ±  2%    625.7n ±  1%        ~ (p=0.383 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4                       809.5n ±  5%    774.8n ± 11%        ~ (p=0.456 n=7)
SingleConnectionPool/Next()/Single__________-4                                                  0.3158n ±  0%   0.3154n ±  1%        ~ (p=0.436 n=7)
SingleConnectionPool/Next()/Parallel_(1000)-4                                                   0.3295n ±  0%   0.3298n ±  5%        ~ (p=0.085 n=7)
SingleConnectionPool/OnFailure()/Single_____-4                                                  0.3115n ±  0%   0.3115n ±  0%        ~ (p=0.272 n=7)
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                              0.2592n ±  0%   0.2591n ±  1%        ~ (p=0.963 n=7)
StatusConnectionPool/Next()/Single_____-4                                                        10.75n ±  0%    10.72n ±  0%   -0.28% (p=0.034 n=7)
StatusConnectionPool/Next()/Parallel_(100)-4                                                     84.66n ±  1%    83.50n ±  1%   -1.37% (p=0.007 n=7)
StatusConnectionPool/OnFailure()/Single_____-4                                                   10.21n ±  0%    10.37n ±  1%   +1.57% (p=0.001 n=7)
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                                 83.19n ±  1%    84.41n ±  2%        ~ (p=0.053 n=7)
StatusConnectionPool/OnSuccess()/Single_____-4                                                   5.610n ±  4%    4.991n ±  0%  -11.03% (p=0.001 n=7)
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                                 2.092n ± 10%    2.418n ±  4%  +15.58% (p=0.001 n=7)
StatusConnectionPool/resurrect()/Single-4                                                        73.80n ± 45%    78.35n ± 43%        ~ (p=0.620 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-4                                                 75.29n ±  7%    76.10n ±  5%        ~ (p=0.620 n=7)
Transport/Defaults-4                                                                             915.7n ± 16%    863.1n ± 11%   -5.74% (p=0.016 n=7)
Transport/Headers-4                                                                              1.112µ ±  1%    1.051µ ±  1%   -5.49% (p=0.001 n=7)
Transport/Compress_body_(pool:_false)-4                                                          221.8µ ± 18%    195.7µ ± 10%  -11.75% (p=0.038 n=7)
Transport/Compress_body_(pool:_true)-4                                                           15.38µ ±  8%    16.45µ ±  4%        ~ (p=0.097 n=7)
TransportLogger/Text-4                                                                           1.704µ ±  3%    1.626µ ±  2%   -4.58% (p=0.001 n=7)
TransportLogger/Text-Body-4                                                                      4.352µ ±  2%    5.094µ ± 17%        ~ (p=0.209 n=7)
TransportLogger/JSON-4                                                                           1.546µ ±  1%    1.492µ ±  1%   -3.49% (p=0.001 n=7)
TransportLogger/JSON-Body-4                                                                      3.018µ ±  1%    2.882µ ±  2%   -4.51% (p=0.001 n=7)
geomean                                                                                          196.6n          197.7n         +0.56%

                                                                           │ /home/runner/work/_temp/base.txt │   /home/runner/work/_temp/head.txt    │
                                                                           │               B/op               │     B/op       vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                                 1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                                1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                               1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                              1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                                 1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                                1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                               1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                              1.095Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4                       1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4                      1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4                     1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4                    1.095Ki ±  0%     1.095Ki ±  0%       ~ (p=1.000 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4                       1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4                      1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4                     1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4                    1.094Ki ±  0%     1.094Ki ±  0%       ~ (p=1.000 n=7)
SingleConnectionPool/Next()/Single__________-4                                                  0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-4                                                   0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-4                                                  0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                              0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-4                                                       0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-4                                                    0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-4                                                  0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                                0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-4                                                  0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                                0.000 ±  0%       0.000 ±  0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-4                                                       43.00 ± 12%       46.00 ± 13%       ~ (p=0.719 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-4                                                45.00 ± 11%       46.00 ±  9%       ~ (p=0.590 n=7)
Transport/Defaults-4                                                                          1.453Ki ±  0%     1.453Ki ±  0%       ~ (p=1.000 n=7) ¹
Transport/Headers-4                                                                           1.469Ki ±  0%     1.469Ki ±  0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-4                                                       796.6Ki ±  0%     796.6Ki ±  0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_true)-4                                                        1.690Ki ±  1%     1.693Ki ±  1%       ~ (p=0.096 n=7)
TransportLogger/Text-4                                                                        1.689Ki ±  0%     1.689Ki ±  0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-4                                                                   9.562Ki ±  0%     9.562Ki ±  0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-4                                                                        1.797Ki ±  0%     1.797Ki ±  0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-4                                                                   5.422Ki ±  0%     5.422Ki ±  0%       ~ (p=1.000 n=7) ¹
geomean                                                                                                     ²                  +0.25%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                                           │ /home/runner/work/_temp/base.txt │  /home/runner/work/_temp/head.txt  │
                                                                           │            allocs/op             │ allocs/op   vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                                   9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                                  9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                                 9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                                   9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                                  9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                                 9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4                          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4                         9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4                        9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4                       9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4                          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4                         9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4                        9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4                       9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Single__________-4                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-4                                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-4                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-4                                                        0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-4                                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-4                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-4                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-4                                                        0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Parallel_(10)-4                                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Defaults-4                                                                             11.00 ± 0%     11.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Headers-4                                                                              12.00 ± 0%     12.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-4                                                          38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_true)-4                                                           19.00 ± 0%     19.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-4                                                                           18.00 ± 0%     18.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-4                                                                      36.00 ± 0%     36.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-4                                                                           13.00 ± 0%     13.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-4                                                                      24.00 ± 0%     24.00 ± 0%       ~ (p=1.000 n=7) ¹
geomean                                                                                                     ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

windows-latest

goos: windows
goarch: amd64
pkg: github.com/elastic/elastic-transport-go/v8/elastictransport
cpu: AMD EPYC 7763 64-Core Processor                
                                                                           │ D:\a\_temp/base.txt │          D:\a\_temp/head.txt          │
                                                                           │       sec/op        │     sec/op      vs base               │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                      718.9n ±   1%    739.4n ±   3%   +2.85% (p=0.026 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                     758.2n ±   2%    767.2n ±   2%   +1.19% (p=0.001 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                    960.0n ±  20%    948.6n ±  25%        ~ (p=0.902 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                   660.6n ±   6%    673.5n ±   3%        ~ (p=0.456 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                      642.9n ±   4%    679.4n ±   4%   +5.68% (p=0.004 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                     698.3n ±   1%    715.5n ±   1%   +2.46% (p=0.001 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                    835.6n ±   4%    836.8n ±   8%        ~ (p=0.259 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                   703.3n ±  48%    786.7n ±  11%        ~ (p=0.097 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4            694.0n ±   2%    707.1n ±   3%   +1.89% (p=0.019 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4           727.4n ±  69%    747.5n ±   1%   +2.76% (p=0.026 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4          878.2n ±   9%    832.2n ±   3%        ~ (p=0.209 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4         939.1n ±   9%    915.8n ±   9%        ~ (p=0.165 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4            737.3n ±  17%    627.4n ±   8%  -14.91% (p=0.001 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4           719.0n ±  44%    693.7n ±   2%   -3.52% (p=0.001 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4          812.2n ±   4%    832.9n ±   2%        ~ (p=0.097 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4         829.1n ±  18%    753.6n ±  26%        ~ (p=0.259 n=7)
SingleConnectionPool/Next()/Single__________-4                                    0.3235n ±   4%   0.3220n ±   1%   -0.46% (p=0.008 n=7)
SingleConnectionPool/Next()/Parallel_(1000)-4                                     0.3307n ±   3%   0.3300n ±   1%        ~ (p=0.125 n=7)
SingleConnectionPool/OnFailure()/Single_____-4                                    0.3166n ±   2%   0.3179n ±   1%        ~ (p=0.735 n=7)
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                0.2607n ±   1%   0.2601n ±   1%        ~ (p=0.645 n=7)
StatusConnectionPool/Next()/Single_____-4                                          10.89n ±  16%    10.91n ±   0%        ~ (p=0.247 n=7)
StatusConnectionPool/Next()/Parallel_(100)-4                                       68.29n ±   0%    69.31n ±   4%   +1.49% (p=0.001 n=7)
StatusConnectionPool/OnFailure()/Single_____-4                                     10.45n ±   1%    10.26n ±   0%   -1.82% (p=0.001 n=7)
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                   70.71n ±   2%    68.42n ±   2%   -3.24% (p=0.001 n=7)
StatusConnectionPool/OnSuccess()/Single_____-4                                     5.067n ±   3%    5.630n ±   0%  +11.11% (p=0.001 n=7)
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                   2.474n ±   7%    2.162n ±  31%  -12.61% (p=0.038 n=7)
StatusConnectionPool/resurrect()/Single-4                                          52.60n ±  25%    59.35n ±  44%        ~ (p=0.710 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-4                                   53.42n ±   4%    53.51n ±   3%        ~ (p=0.456 n=7)
Transport/Defaults-4                                                               849.0n ±  25%    787.4n ±  34%        ~ (p=0.620 n=7)
Transport/Headers-4                                                               1036.0n ±   8%    969.4n ±   7%   -6.43% (p=0.017 n=7)
Transport/Compress_body_(pool:_false)-4                                           107.39µ ± 264%    91.54µ ± 222%        ~ (p=0.456 n=7)
Transport/Compress_body_(pool:_true)-4                                             15.58µ ±   3%    15.71µ ±   4%        ~ (p=0.535 n=7)
TransportLogger/Text-4                                                             1.471µ ±  21%    1.480µ ±   2%        ~ (p=0.777 n=7)
TransportLogger/Text-Body-4                                                        3.647µ ±  39%    3.594µ ±  44%        ~ (p=0.456 n=7)
TransportLogger/JSON-4                                                             1.287µ ±  27%    1.286µ ±   2%        ~ (p=0.383 n=7)
TransportLogger/JSON-Body-4                                                        2.546µ ±   5%    2.703µ ±  19%   +6.17% (p=0.011 n=7)
geomean                                                                            199.2n           197.9n          -0.69%

                                                                           │ D:\a\_temp/base.txt │         D:\a\_temp/head.txt          │
                                                                           │        B/op         │     B/op      vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                    1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                   1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                  1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                 1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                    1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                   1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                  1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                 1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=0.559 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4          1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4         1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4        1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4       1.095Ki ±  0%     1.095Ki ± 0%       ~ (p=1.000 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4          1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4         1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4        1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4       1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7)
SingleConnectionPool/Next()/Single__________-4                                     0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-4                                      0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-4                                     0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                 0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-4                                          0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-4                                       0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-4                                     0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-4                                     0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-4                                          42.00 ± 10%       43.00 ± 7%       ~ (p=0.516 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-4                                   46.00 ±  7%       46.00 ± 2%       ~ (p=0.710 n=7)
Transport/Defaults-4                                                             1.453Ki ±  0%     1.453Ki ± 0%       ~ (p=1.000 n=7) ¹
Transport/Headers-4                                                              1.469Ki ±  0%     1.469Ki ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-4                                          796.6Ki ±  0%     796.6Ki ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_true)-4                                           1.716Ki ±  1%     1.717Ki ± 1%       ~ (p=0.311 n=7)
TransportLogger/Text-4                                                           1.689Ki ±  0%     1.689Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-4                                                      9.562Ki ±  0%     9.562Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-4                                                           1.797Ki ±  0%     1.797Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-4                                                      5.422Ki ±  0%     5.422Ki ± 0%       ~ (p=1.000 n=7) ¹
geomean                                                                                        ²                 +0.07%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                                           │ D:\a\_temp/base.txt │        D:\a\_temp/head.txt         │
                                                                           │      allocs/op      │ allocs/op   vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-4                       9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-4                      9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-4                     9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-4                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-4                       9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-4                      9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-4                     9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-4                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-4             9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-4            9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-4           9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-4          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-4             9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-4            9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-4           9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-4          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Single__________-4                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-4                                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-4                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-4                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-4                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-4                                        0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-4                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-4                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-4                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-4                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-4                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Parallel_(10)-4                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Defaults-4                                                                11.00 ± 0%     11.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Headers-4                                                                 12.00 ± 0%     12.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-4                                             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_true)-4                                              19.00 ± 0%     19.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-4                                                              18.00 ± 0%     18.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-4                                                         36.00 ± 0%     36.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-4                                                              13.00 ± 0%     13.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-4                                                         24.00 ± 0%     24.00 ± 0%       ~ (p=1.000 n=7) ¹
geomean                                                                                        ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

macos-latest

goos: darwin
goarch: arm64
pkg: github.com/elastic/elastic-transport-go/v8/elastictransport
cpu: Apple M1 (Virtual)
                                                                           │ /Users/runner/work/_temp/base.txt │  /Users/runner/work/_temp/head.txt   │
                                                                           │              sec/op               │    sec/op      vs base               │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-3                                    465.4n ±  41%    405.3n ± 29%        ~ (p=0.259 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-3                                   684.4n ±  13%    524.1n ± 32%  -23.42% (p=0.007 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-3                                  590.0n ±  84%    437.2n ±  6%  -25.90% (p=0.001 n=7)
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-3                                 636.8n ±  16%    714.0n ± 29%        ~ (p=0.318 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-3                                    788.2n ±  76%    691.5n ± 13%        ~ (p=0.209 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-3                                   722.9n ±  20%    513.3n ± 38%  -28.99% (p=0.004 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-3                                  626.8n ±  17%    544.6n ± 25%        ~ (p=0.318 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-3                                 605.2n ±  53%    855.5n ±  7%  +41.36% (p=0.026 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-3                          669.4n ±  30%    519.9n ± 10%  -22.33% (p=0.001 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-3                         840.6n ±  37%    656.1n ± 24%        ~ (p=0.053 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-3                        665.4n ±  80%    706.7n ± 28%        ~ (p=0.902 n=7)
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-3                      1314.0n ±  23%    623.1n ± 48%  -52.58% (p=0.001 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-3                         1079.0n ±  53%    568.7n ± 25%  -47.29% (p=0.011 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-3                         545.6n ±  16%    613.2n ± 20%        ~ (p=0.902 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-3                        963.6n ±  32%    476.7n ±  9%  -50.53% (p=0.001 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-3                      1100.0n ±  19%    783.7n ± 16%  -28.75% (p=0.001 n=7)
SingleConnectionPool/Next()/Single__________-3                                                  0.3468n ±   7%   0.3318n ± 16%   -4.33% (p=0.026 n=7)
SingleConnectionPool/Next()/Parallel_(1000)-3                                                   0.4271n ±   7%   0.3339n ±  7%  -21.82% (p=0.001 n=7)
SingleConnectionPool/OnFailure()/Single_____-3                                                  0.3427n ±   3%   0.3297n ±  1%   -3.79% (p=0.001 n=7)
SingleConnectionPool/OnFailure()/Parallel_(1000)-3                                              0.6844n ±  60%   0.5189n ± 17%        ~ (p=0.053 n=7)
StatusConnectionPool/Next()/Single_____-3                                                        17.14n ±  15%    14.40n ±  3%  -15.99% (p=0.002 n=7)
StatusConnectionPool/Next()/Parallel_(100)-3                                                     49.84n ±  53%    61.25n ±  6%        ~ (p=0.073 n=7)
StatusConnectionPool/OnFailure()/Single_____-3                                                   22.39n ±  16%    21.18n ±  3%   -5.40% (p=0.001 n=7)
StatusConnectionPool/OnFailure()/Parallel_(10)-3                                                 94.66n ±  11%    77.99n ± 32%        ~ (p=0.318 n=7)
StatusConnectionPool/OnSuccess()/Single_____-3                                                   14.90n ±   4%    14.31n ±  5%   -3.96% (p=0.001 n=7)
StatusConnectionPool/OnSuccess()/Parallel_(10)-3                                                 5.998n ±  11%    5.209n ± 54%        ~ (p=0.165 n=7)
StatusConnectionPool/resurrect()/Single-3                                                        48.98n ±  58%    34.50n ± 58%        ~ (p=0.318 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-3                                                 77.48n ±  33%   118.30n ± 30%  +52.68% (p=0.011 n=7)
Transport/Defaults-3                                                                            1531.0n ±  44%    969.7n ± 24%  -36.66% (p=0.001 n=7)
Transport/Headers-3                                                                              1.495µ ±  28%    1.126µ ± 14%  -24.68% (p=0.038 n=7)
Transport/Compress_body_(pool:_false)-3                                                          418.6µ ±  29%    382.2µ ± 39%        ~ (p=0.383 n=7)
Transport/Compress_body_(pool:_true)-3                                                           17.67µ ±   6%    17.05µ ±  3%        ~ (p=0.128 n=7)
TransportLogger/Text-3                                                                           1.254µ ±  61%    1.273µ ± 52%        ~ (p=0.805 n=7)
TransportLogger/Text-Body-3                                                                      4.484µ ± 105%    6.101µ ± 42%        ~ (p=1.000 n=7)
TransportLogger/JSON-3                                                                           1.330µ ±  68%    1.233µ ± 29%        ~ (p=0.259 n=7)
TransportLogger/JSON-Body-3                                                                      3.959µ ±  59%    2.713µ ± 21%        ~ (p=0.128 n=7)
geomean                                                                                          243.7n           209.0n        -14.26%

                                                                           │ /Users/runner/work/_temp/base.txt │  /Users/runner/work/_temp/head.txt   │
                                                                           │               B/op                │     B/op      vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-3                                  1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-3                                 1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-3                                1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-3                               1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7)
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-3                                  1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-3                                 1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-3                                1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-3                               1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-3                        1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-3                       1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-3                      1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-3                     1.095Ki ±  0%     1.094Ki ± 0%  -0.09% (p=0.001 n=7)
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-3                        1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-3                       1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-3                      1.094Ki ±  0%     1.094Ki ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-3                     1.095Ki ±  0%     1.094Ki ± 0%  -0.09% (p=0.021 n=7)
SingleConnectionPool/Next()/Single__________-3                                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-3                                                    0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-3                                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-3                                               0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-3                                                        0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-3                                                     0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-3                                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-3                                                 0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-3                                                   0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-3                                                 0.000 ±  0%       0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-3                                                        44.00 ± 11%       43.00 ± 7%       ~ (p=0.270 n=7)
StatusConnectionPool/resurrect()/Parallel_(10)-3                                                 46.00 ± 11%       43.00 ± 7%       ~ (p=0.114 n=7)
Transport/Defaults-3                                                                           1.453Ki ±  0%     1.453Ki ± 0%       ~ (p=1.000 n=7) ¹
Transport/Headers-3                                                                            1.469Ki ±  0%     1.469Ki ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-3                                                        796.6Ki ±  0%     796.6Ki ± 0%       ~ (p=1.000 n=7)
Transport/Compress_body_(pool:_true)-3                                                         1.694Ki ±  0%     1.694Ki ± 0%       ~ (p=0.639 n=7)
TransportLogger/Text-3                                                                         1.689Ki ±  0%     1.689Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-3                                                                    9.562Ki ±  0%     9.562Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-3                                                                         1.797Ki ±  0%     1.797Ki ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-3                                                                    5.422Ki ±  0%     5.422Ki ± 0%       ~ (p=1.000 n=7) ¹
geomean                                                                                                      ²                 -0.26%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                                           │ /Users/runner/work/_temp/base.txt │ /Users/runner/work/_temp/head.txt  │
                                                                           │             allocs/op             │ allocs/op   vs base                │
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1-3                                     9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-10-3                                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-100-3                                   9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/SingleConnectionPool/Perform/parallelism-1000-3                                  9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1-3                                     9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-10-3                                    9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-100-3                                   9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/StatusConnectionPool/Perform/parallelism-1000-3                                  9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1-3                           9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-10-3                          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-100-3                         9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/SynchronizedWrapper/Perform/parallelism-1000-3                        9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1-3                           9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-10-3                          9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-100-3                         9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
ClientPoolAccess/CustomPool/ConcurrentSafeOptIn/Perform/parallelism-1000-3                        9.000 ± 0%     9.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Single__________-3                                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/Next()/Parallel_(1000)-3                                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Single_____-3                                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
SingleConnectionPool/OnFailure()/Parallel_(1000)-3                                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Single_____-3                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/Next()/Parallel_(100)-3                                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Single_____-3                                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnFailure()/Parallel_(10)-3                                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Single_____-3                                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/OnSuccess()/Parallel_(10)-3                                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Single-3                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
StatusConnectionPool/resurrect()/Parallel_(10)-3                                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Defaults-3                                                                              11.00 ± 0%     11.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Headers-3                                                                               12.00 ± 0%     12.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_false)-3                                                           38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=7) ¹
Transport/Compress_body_(pool:_true)-3                                                            19.00 ± 0%     19.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-3                                                                            18.00 ± 0%     18.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/Text-Body-3                                                                       36.00 ± 0%     36.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-3                                                                            13.00 ± 0%     13.00 ± 0%       ~ (p=1.000 n=7) ¹
TransportLogger/JSON-Body-3                                                                       24.00 ± 0%     24.00 ± 0%       ~ (p=1.000 n=7) ¹
geomean                                                                                                      ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

Compared using benchstat. Benchmarks were run with -benchtime=500ms -count=7 on the same runner for a fair comparison.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors TLS setup in elastictransport by extracting the TLS configuration logic from New() into a new exported helper, ConfigureTLS, intended for reuse when *http.Transport is wrapped by custom http.RoundTripper middleware.

Changes:

  • Adds ConfigureTLS(*http.Transport, caCert, certificateFingerprint) in a new tls.go.
  • Updates New() to clone/configure *http.Transport via ConfigureTLS, and error when TLS options are used with a non-*http.Transport.
  • Adds unit tests covering the new helper and the updated New() TLS integration paths.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
elastictransport/tls.go Introduces exported ConfigureTLS helper and fingerprint/CA configuration logic.
elastictransport/elastictransport.go Replaces inline TLS configuration in New() with a call to ConfigureTLS and adds a non-*http.Transport error path.
elastictransport/elastictransport_internal_test.go Adds tests for ConfigureTLS and TLS configuration behavior in New().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread elastictransport/tls.go
fingerprint, err := hex.DecodeString(certificateFingerprint)
if err != nil {
return fmt.Errorf("invalid certificate fingerprint %q: %w", certificateFingerprint, err)
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

certificateFingerprint is decoded from hex but the decoded length is never validated. Since the comparison is bytes.Equal(sha256Sum[:], fingerprint), any decoded length other than 32 bytes will never match and will cause all TLS dials to fail later with a mismatch error. Consider validating len(fingerprint)==sha256.Size (and optionally rejecting odd lengths / whitespace) and returning a clear error early.

Suggested change
}
}
if len(fingerprint) != sha256.Size {
return fmt.Errorf("invalid certificate fingerprint %q: expected %d-byte SHA-256 digest, got %d bytes", certificateFingerprint, sha256.Size, len(fingerprint))
}

Copilot uses AI. Check for mistakes.
Comment thread elastictransport/tls.go
Comment on lines +54 to +69
transport.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
d := tls.Dialer{Config: &tls.Config{InsecureSkipVerify: true}}
conn, err := d.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}

tlsConn := conn.(*tls.Conn)
for _, cert := range tlsConn.ConnectionState().PeerCertificates {
digest := sha256.Sum256(cert.Raw)
if bytes.Equal(digest[:], fingerprint) {
return tlsConn, nil
}
}
_ = tlsConn.Close()
return nil, fmt.Errorf("fingerprint mismatch, provided: %s", certificateFingerprint)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Transport.DialTLSContext for fingerprint pinning means the fingerprint verification only runs for non-proxied HTTPS connections, and it also bypasses transport.TLSClientConfig settings (e.g., ALPN NextProtos for HTTP/2, min TLS version, cipher suites). To ensure fingerprint pinning is consistently enforced (including proxied HTTPS) and to preserve TLS settings, consider implementing pinning via transport.TLSClientConfig (e.g., InsecureSkipVerify=true plus VerifyPeerCertificate/VerifyConnection) instead of a custom dialer.

Suggested change
transport.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
d := tls.Dialer{Config: &tls.Config{InsecureSkipVerify: true}}
conn, err := d.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsConn := conn.(*tls.Conn)
for _, cert := range tlsConn.ConnectionState().PeerCertificates {
digest := sha256.Sum256(cert.Raw)
if bytes.Equal(digest[:], fingerprint) {
return tlsConn, nil
}
}
_ = tlsConn.Close()
return nil, fmt.Errorf("fingerprint mismatch, provided: %s", certificateFingerprint)
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
// In fingerprint mode, we bypass standard CA verification and rely solely on
// the fingerprint check. We therefore set InsecureSkipVerify and implement
// verification via VerifyPeerCertificate so that it applies consistently,
// including for proxied HTTPS connections.
cfg := transport.TLSClientConfig
cfg.InsecureSkipVerify = true
prevVerify := cfg.VerifyPeerCertificate
cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
for _, raw := range rawCerts {
cert, err := x509.ParseCertificate(raw)
if err != nil {
return err
}
digest := sha256.Sum256(cert.Raw)
if bytes.Equal(digest[:], fingerprint) {
if prevVerify != nil {
return prevVerify(rawCerts, verifiedChains)
}
return nil
}
}
return fmt.Errorf("fingerprint mismatch, provided: %s", certificateFingerprint)

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +108
t.Run("Sets DialTLSContext when fingerprint is configured", func(t *testing.T) {
transport := &http.Transport{}
if err := ConfigureTLS(transport, nil, "A98116BE"); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These subtests pass a very short fingerprint ("A98116BE"), which decodes to 4 bytes and can never match a SHA-256 certificate digest (32 bytes). This currently allows ConfigureTLS to succeed but guarantees runtime fingerprint mismatch errors. The test should use a full 32-byte (64 hex chars) fingerprint, and ideally exercise a real TLS handshake to verify that the correct fingerprint succeeds and a wrong one fails.

Copilot uses AI. Check for mistakes.
Comment on lines 181 to 185
if transport, ok := cfg.Transport.(*http.Transport); ok {
if cfg.CertificateFingerprint != "" {
transport.DialTLSContext = func(_ context.Context, network, addr string) (net.Conn, error) {
fingerprint, _ := hex.DecodeString(cfg.CertificateFingerprint)

c, err := tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: true})
if err != nil {
return nil, err
}

// Retrieve the connection state from the remote server.
cState := c.ConnectionState()
for _, cert := range cState.PeerCertificates {
// Compute digest for each certificate.
digest := sha256.Sum256(cert.Raw)

// Provided fingerprint should match at least one certificate from remote before we continue.
if bytes.Equal(digest[0:], fingerprint) {
return c, nil
}
}
return nil, fmt.Errorf("fingerprint mismatch, provided: %s", cfg.CertificateFingerprint)
}
if cfg.CACert != nil || cfg.CertificateFingerprint != "" {
transport = transport.Clone()
cfg.Transport = transport
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When cfg.Transport is nil, the default transport is already cloned above. This block clones the transport again whenever TLS options are set, which creates an extra unused clone in the common case. Consider only cloning here when the transport came from the user (or track a boolean) to avoid the redundant clone.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +113
func TestConfigureTLS(t *testing.T) {
t.Run("Returns error when transport is nil", func(t *testing.T) {
if err := ConfigureTLS(nil, nil, ""); err == nil {
t.Fatal("Expected error, got nil")
}
})

t.Run("Returns error on invalid CA cert", func(t *testing.T) {
transport := &http.Transport{}
if err := ConfigureTLS(transport, []byte("invalid"), ""); err == nil {
t.Fatal("Expected error, got nil")
}
})

t.Run("Initializes TLS config and RootCAs from PEM", func(t *testing.T) {
caCert, err := os.ReadFile("testdata/cert.pem")
if err != nil {
t.Fatalf("Unexpected error reading cert: %s", err)
}

transport := &http.Transport{}
if err := ConfigureTLS(transport, caCert, ""); err != nil {
t.Fatalf("Unexpected error: %s", err)
}

if transport.TLSClientConfig == nil {
t.Fatal("Expected TLSClientConfig to be initialized")
}
if transport.TLSClientConfig.RootCAs == nil {
t.Fatal("Expected RootCAs to be initialized")
}
})

t.Run("Returns error on invalid fingerprint hex", func(t *testing.T) {
transport := &http.Transport{}
err := ConfigureTLS(transport, nil, "not-valid-hex")
if err == nil {
t.Fatal("Expected error, got nil")
}
if !strings.Contains(err.Error(), "invalid certificate fingerprint") {
t.Fatalf("Unexpected error message: %s", err)
}
})

t.Run("Sets DialTLSContext when fingerprint is configured", func(t *testing.T) {
transport := &http.Transport{}
if err := ConfigureTLS(transport, nil, "A98116BE"); err != nil {
t.Fatalf("Unexpected error: %s", err)
}

if transport.DialTLSContext == nil {
t.Fatal("Expected DialTLSContext to be configured")
}
})
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description states TestConfigureTLS covers valid fingerprint / mismatch (including closing connections). In this test file, fingerprint scenarios only assert that DialTLSContext is set and that invalid hex errors; they don't validate successful/failed verification behavior. Either update the tests to cover the described behaviors (e.g., using a local TLS server with testdata/cert.pem) or adjust the PR description/test plan to match what's actually covered.

Copilot uses AI. Check for mistakes.
@MattDevy MattDevy marked this pull request as draft February 24, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants