Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fortio for openSUSE:Factory checked in at 2022-03-28 17:00:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fortio (Old) and /work/SRC/openSUSE:Factory/.fortio.new.1900 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fortio" Mon Mar 28 17:00:58 2022 rev:5 rq:965309 version:1.24.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fortio/fortio.changes 2022-03-25 21:54:58.318295255 +0100 +++ /work/SRC/openSUSE:Factory/.fortio.new.1900/fortio.changes 2022-03-28 17:01:52.369076287 +0200 @@ -1,0 +2,9 @@ +Mon Mar 28 07:10:20 UTC 2022 - ka...@b1-systems.de + +- Update to version 1.24.0: + * Fix #535: echo debug path normalization needed depending on whether debug path ends with / or not. also fix pprof link which is hardcoded to /debug/pprof/ (#537) + * refactor tlsoptions to common struct and share setup for both http and grpc (#536) + * Create SECURITY.md + * code scanning + +------------------------------------------------------------------- Old: ---- fortio-1.23.0.tar.gz New: ---- fortio-1.24.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fortio.spec ++++++ --- /var/tmp/diff_new_pack.yF6lQx/_old 2022-03-28 17:01:53.065077232 +0200 +++ /var/tmp/diff_new_pack.yF6lQx/_new 2022-03-28 17:01:53.073077243 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: fortio -Version: 1.23.0 +Version: 1.24.0 Release: 0 Summary: Load testing library, command line tool, advanced echo server and web UI License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.yF6lQx/_old 2022-03-28 17:01:53.113077298 +0200 +++ /var/tmp/diff_new_pack.yF6lQx/_new 2022-03-28 17:01:53.117077303 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/fortio/fortio</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v1.23.0</param> + <param name="revision">v1.24.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> @@ -16,7 +16,7 @@ <param name="compression">gz</param> </service> <service name="go_modules" mode="disabled"> - <param name="archive">fortio-1.23.0.tar.gz</param> + <param name="archive">fortio-1.24.0.tar.gz</param> </service> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.yF6lQx/_old 2022-03-28 17:01:53.145077341 +0200 +++ /var/tmp/diff_new_pack.yF6lQx/_new 2022-03-28 17:01:53.149077346 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/fortio/fortio</param> - <param name="changesrevision">8c28aec56c639807472392db3b0ebb3fd5d448ed</param></service></servicedata> + <param name="changesrevision">fb00657cd46406b6660f5fc1fa4894d6c426d295</param></service></servicedata> (No newline at EOF) ++++++ fortio-1.23.0.tar.gz -> fortio-1.24.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/.github/workflows/codeql-analysis.yml new/fortio-1.24.0/.github/workflows/codeql-analysis.yml --- old/fortio-1.23.0/.github/workflows/codeql-analysis.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/fortio-1.24.0/.github/workflows/codeql-analysis.yml 2022-03-28 00:47:13.000000000 +0200 @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '21 5 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go', 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ?????? Command-line programs to run using the OS shell. + # ???? https://git.io/JvXDl + + # ?????? If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/README.md new/fortio-1.24.0/README.md --- old/fortio-1.23.0/README.md 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/README.md 2022-03-28 00:47:13.000000000 +0200 @@ -46,13 +46,13 @@ Or download one of the binary distributions, from the [releases](https://github.com/fortio/fortio/releases) assets page or for instance: ```shell -curl -L https://github.com/fortio/fortio/releases/download/v1.23.0/fortio-linux_x64-1.23.0.tgz \ +curl -L https://github.com/fortio/fortio/releases/download/v1.24.0/fortio-linux_x64-1.24.0.tgz \ | sudo tar -C / -xvzpf - # or the debian package -wget https://github.com/fortio/fortio/releases/download/v1.23.0/fortio_1.23.0_amd64.deb -dpkg -i fortio_1.23.0_amd64.deb +wget https://github.com/fortio/fortio/releases/download/v1.24.0/fortio_1.24.0_amd64.deb +dpkg -i fortio_1.24.0_amd64.deb # or the rpm -rpm -i https://github.com/fortio/fortio/releases/download/v1.23.0/fortio-1.23.0-1.x86_64.rpm +rpm -i https://github.com/fortio/fortio/releases/download/v1.24.0/fortio-1.24.0-1.x86_64.rpm ``` On a MacOS you can also install Fortio using [Homebrew](https://brew.sh/): @@ -61,7 +61,7 @@ brew install fortio ``` -On Windows, download https://github.com/fortio/fortio/releases/download/v1.23.0/fortio_win_1.23.0.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt: +On Windows, download https://github.com/fortio/fortio/releases/download/v1.24.0/fortio_win_1.24.0.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt: ``` fortio.exe server ``` @@ -106,7 +106,7 @@ <details> <!-- use release/updateFlags.sh to update this section --> <pre> -???????????? 1.23.0 usage: +???????????? 1.24.0 usage: where command is one of: load (load testing), server (starts ui, http-echo, redirect, proxies, tcp-echo and grpc ping servers), tcp-echo (only the tcp-echo server), report (report only UI server), redirect (only the redirect server), @@ -204,7 +204,7 @@ -json path Json output to provided file path or '-' for stdout (empty = no json output, unless -a is used) - -k Do not verify certs in https connections + -k Do not verify certs in https/tls/grpc connections -keepalive Keep connection alive (only for fast http 1.1) (default true) -key Path diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/SECURITY.md new/fortio-1.24.0/SECURITY.md --- old/fortio-1.23.0/SECURITY.md 1970-01-01 01:00:00.000000000 +0100 +++ new/fortio-1.24.0/SECURITY.md 2022-03-28 00:47:13.000000000 +0200 @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.23.x | :white_check_mark: | + + +## Reporting a Vulnerability + +Please open in Issue or contact the main author directly at ldemailly at gmail diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/bincommon/commonflags.go new/fortio-1.24.0/bincommon/commonflags.go --- old/fortio-1.23.0/bincommon/commonflags.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/bincommon/commonflags.go 2022-03-28 00:47:13.000000000 +0200 @@ -64,7 +64,7 @@ httpReqTimeoutFlag = flag.Duration("timeout", fhttp.HTTPReqTimeOutDefaultValue, "Connection and read timeout value (for http)") stdClientFlag = flag.Bool("stdclient", false, "Use the slower net/http standard client (slower but supports h2)") http10Flag = flag.Bool("http1.0", false, "Use http1.0 (instead of http 1.1)") - httpsInsecureFlag = flag.Bool("k", false, "Do not verify certs in https connections") + httpsInsecureFlag = flag.Bool("k", false, "Do not verify certs in https/tls/grpc connections") httpsInsecureFlagL = flag.Bool("https-insecure", false, "Long form of the -k flag") resolve = flag.String("resolve", "", "Resolve host name to this `IP`") headersFlags headersFlagList diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fgrpc/grpcrunner.go new/fortio-1.24.0/fgrpc/grpcrunner.go --- old/fortio-1.23.0/fgrpc/grpcrunner.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fgrpc/grpcrunner.go 2022-03-28 00:47:13.000000000 +0200 @@ -16,7 +16,6 @@ import ( "context" - "crypto/tls" "fmt" "net" "os" @@ -25,6 +24,7 @@ "strings" "time" + "fortio.org/fortio/fhttp" "fortio.org/fortio/fnet" "fortio.org/fortio/log" "fortio.org/fortio/periodic" @@ -38,20 +38,14 @@ // it will override the virtual host name of authority in requests. func Dial(o *GRPCRunnerOptions) (conn *grpc.ClientConn, err error) { var opts []grpc.DialOption - switch { - case o.CACert != "": - var creds credentials.TransportCredentials - creds, err = credentials.NewClientTLSFromFile(o.CACert, o.CertOverride) + if o.CACert != "" || strings.HasPrefix(o.Destination, fnet.PrefixHTTPS) { + tlsConfig, err := o.TLSOptions.TLSClientConfig() if err != nil { - log.Errf("Invalid TLS credentials: %v\n", err) return nil, err } - log.Infof("Using CA certificate %v to construct TLS credentials", o.CACert) - opts = append(opts, grpc.WithTransportCredentials(creds)) - case strings.HasPrefix(o.Destination, fnet.PrefixHTTPS): - creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: o.Insecure}) // nolint: gosec // explicit flag - opts = append(opts, grpc.WithTransportCredentials(creds)) - default: + tlsConfig.ServerName = o.CertOverride + opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) + } else { opts = append(opts, grpc.WithInsecure()) } serverAddr := grpcDestination(o.Destination) @@ -114,18 +108,16 @@ // options. type GRPCRunnerOptions struct { periodic.RunnerOptions + fhttp.TLSOptions Destination string Service string // Service to be checked when using grpc health check Profiler string // file to save profiles to. defaults to no profiling Payload string // Payload to be sent for grpc ping service Streams int // number of streams. total go routines and data streams will be streams*numthreads. Delay time.Duration // Delay to be sent when using grpc ping service - CACert string // Path to CA certificate for grpc TLS CertOverride string // Override the cert virtual host of authority for testing - Insecure bool // Allow unknown CA / self signed AllowInitialErrors bool // whether initial errors don't cause an abort UsePing bool // use our own Ping proto for grpc load instead of standard health check one. - UnixDomainSocket string // unix domain socket path to use for physical connection instead of Destination } // RunGRPCTest runs an http test and returns the aggregated stats. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fgrpc/grpcrunner_test.go new/fortio-1.24.0/fgrpc/grpcrunner_test.go --- old/fortio-1.23.0/fgrpc/grpcrunner_test.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fgrpc/grpcrunner_test.go 2022-03-28 00:47:13.000000000 +0200 @@ -20,6 +20,7 @@ "testing" "time" + "fortio.org/fortio/fhttp" "fortio.org/fortio/fnet" "fortio.org/fortio/log" "fortio.org/fortio/periodic" @@ -68,15 +69,15 @@ name: "valid secure runner", runnerOpts: GRPCRunnerOptions{ Destination: sDest, - CACert: caCrt, + TLSOptions: fhttp.TLSOptions{CACert: caCrt}, }, expect: true, }, { name: "valid unix domain socket runner", runnerOpts: GRPCRunnerOptions{ - Destination: uDest, - UnixDomainSocket: uPath.String(), + Destination: uDest, + TLSOptions: fhttp.TLSOptions{UnixDomainSocket: uPath.String()}, }, expect: true, }, @@ -129,7 +130,7 @@ name: "invalid name in secure runner cert", runnerOpts: GRPCRunnerOptions{ Destination: sDest, - CACert: caCrt, + TLSOptions: fhttp.TLSOptions{CACert: caCrt}, CertOverride: "invalidName", }, expect: false, @@ -138,7 +139,7 @@ name: "invalid cert for secure runner", runnerOpts: GRPCRunnerOptions{ Destination: sDest, - CACert: "../missing/cert.crt", + TLSOptions: fhttp.TLSOptions{CACert: "../missing/cert.crt"}, }, expect: false, }, @@ -240,7 +241,7 @@ name: "secure runner", runnerOpts: GRPCRunnerOptions{ Destination: sDest, - CACert: caCrt, + TLSOptions: fhttp.TLSOptions{CACert: caCrt}, }, }, { @@ -253,14 +254,14 @@ name: "invalid secure runner to insecure server", runnerOpts: GRPCRunnerOptions{ Destination: iDest, - CACert: caCrt, + TLSOptions: fhttp.TLSOptions{CACert: caCrt}, }, }, { name: "invalid name in runner cert", runnerOpts: GRPCRunnerOptions{ Destination: sDest, - CACert: caCrt, + TLSOptions: fhttp.TLSOptions{CACert: caCrt}, CertOverride: "invalidName", }, }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fgrpc/pingsrv.go new/fortio-1.24.0/fgrpc/pingsrv.go --- old/fortio-1.23.0/fgrpc/pingsrv.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fgrpc/pingsrv.go 2022-03-28 00:47:13.000000000 +0200 @@ -21,6 +21,7 @@ "os" "time" + "fortio.org/fortio/fhttp" "fortio.org/fortio/fnet" "fortio.org/fortio/log" "fortio.org/fortio/stats" @@ -105,8 +106,8 @@ // PingClientCall calls the ping service (presumably running as PingServer on // the destination). returns the average round trip in seconds. -func PingClientCall(serverAddr, cacert string, n int, payload string, delay time.Duration, insecure bool) (float64, error) { - o := GRPCRunnerOptions{Destination: serverAddr, CACert: cacert, Insecure: insecure} +func PingClientCall(serverAddr string, n int, payload string, delay time.Duration, tlsOpts *fhttp.TLSOptions) (float64, error) { + o := GRPCRunnerOptions{Destination: serverAddr, TLSOptions: *tlsOpts} conn, err := Dial(&o) // somehow this never seem to error out, error comes later if err != nil { return -1, err // error already logged @@ -163,9 +164,9 @@ // GrpcHealthCheck makes a grpc client call to the standard grpc health check // service. -func GrpcHealthCheck(serverAddr, cacert string, svcname string, n int, insecure bool) (*HealthResultMap, error) { +func GrpcHealthCheck(serverAddr, svcname string, n int, tlsOpts *fhttp.TLSOptions) (*HealthResultMap, error) { log.Debugf("GrpcHealthCheck for %s svc '%s', %d iterations", serverAddr, svcname, n) - o := GRPCRunnerOptions{Destination: serverAddr, CACert: cacert, Insecure: insecure} + o := GRPCRunnerOptions{Destination: serverAddr, TLSOptions: *tlsOpts} conn, err := Dial(&o) if err != nil { return nil, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fgrpc/pingsrv_test.go new/fortio-1.24.0/fgrpc/pingsrv_test.go --- old/fortio-1.23.0/fgrpc/pingsrv_test.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fgrpc/pingsrv_test.go 2022-03-28 00:47:13.000000000 +0200 @@ -21,6 +21,7 @@ "testing" "time" + "fortio.org/fortio/fhttp" "fortio.org/fortio/log" "google.golang.org/grpc/credentials" "google.golang.org/grpc/health/grpc_health_v1" @@ -31,7 +32,10 @@ } func TestPingServer(t *testing.T) { - TLSInsecure := false + TLSSecure := &fhttp.TLSOptions{CACert: caCrt, Insecure: false} + TLSSecureMissingCert := &fhttp.TLSOptions{Insecure: false} + TLSSecureBadCert := &fhttp.TLSOptions{CACert: failCrt, Insecure: true} + TLSInsecure := &fhttp.TLSOptions{Insecure: true} iPort := PingServerTCP("0", "", "", "foo", 0) iAddr := fmt.Sprintf("localhost:%d", iPort) t.Logf("insecure grpc ping server running, will connect to %s", iAddr) @@ -39,7 +43,7 @@ sAddr := fmt.Sprintf("localhost:%d", sPort) t.Logf("secure grpc ping server running, will connect to %s", sAddr) delay := 100 * time.Millisecond - latency, err := PingClientCall(iAddr, "", 7, "test payload", delay, TLSInsecure) + latency, err := PingClientCall(iAddr, 7, "test payload", delay, TLSInsecure) if err != nil || latency < delay.Seconds() || latency > 10.*delay.Seconds() { t.Errorf("Unexpected result %f, %v with ping calls and delay of %v", latency, err, delay) } @@ -49,29 +53,29 @@ t.Errorf("Unexpected result %f, %v with ping calls", latency, err) } */ - if latency, err := PingClientCall(sAddr, caCrt, 7, "test payload", 0, TLSInsecure); err != nil || latency <= 0 { + if latency, err := PingClientCall(sAddr, 7, "test payload", 0, TLSSecure); err != nil || latency <= 0 { t.Errorf("Unexpected result %f, %v with ping calls", latency, err) } - if latency, err := PingClientCall(iAddr, caCrt, 1, "", 0, TLSInsecure); err == nil { + if latency, err := PingClientCall(iAddr, 1, "", 0, TLSSecure); err == nil { t.Errorf("Should have had an error instead of result %f for secure ping to insecure port", latency) } - if _, err := PingClientCall("https://"+sAddr, "", 1, "", 0, true); err != nil { + if _, err := PingClientCall("https://"+sAddr, 1, "", 0, TLSInsecure); err != nil { t.Errorf("Should have had no error for secure with bad cert and insecure flag: %v", err) } - if latency, err := PingClientCall("https://"+sAddr, "", 1, "", 0, false); err == nil { + if latency, err := PingClientCall("https://"+sAddr, 1, "", 0, TLSSecureMissingCert); err == nil { t.Errorf("Should have had error for secure with bad cert and no insecure flag: %v", latency) } - if latency, err := PingClientCall(sAddr, "", 1, "", 0, TLSInsecure); err == nil { + if latency, err := PingClientCall(sAddr, 1, "", 0, TLSInsecure); err == nil { t.Errorf("Should have had an error instead of result %f for insecure ping to secure port", latency) } if creds, err := credentials.NewServerTLSFromFile(failCrt, failKey); err == nil { t.Errorf("Should have had an error instead of result %f for ping server", creds) } serving := grpc_health_v1.HealthCheckResponse_SERVING.String() - if r, err := GrpcHealthCheck(iAddr, "", "", 1, TLSInsecure); err != nil || (*r)[serving] != 1 { + if r, err := GrpcHealthCheck(iAddr, "", 1, TLSInsecure); err != nil || (*r)[serving] != 1 { t.Errorf("Unexpected result %+v, %v with empty service health check", r, err) } - if r, err := GrpcHealthCheck(sAddr, caCrt, "", 1, TLSInsecure); err != nil || (*r)[serving] != 1 { + if r, err := GrpcHealthCheck(sAddr, "", 1, TLSSecure); err != nil || (*r)[serving] != 1 { t.Errorf("Unexpected result %+v, %v with empty service health check", r, err) } /* re-enable once we get https://demo.fortio.org/ @@ -79,19 +83,19 @@ t.Errorf("Unexpected result %+v, %v with empty service health check", r, err) } */ - if r, err := GrpcHealthCheck(iAddr, "", "foo", 3, TLSInsecure); err != nil || (*r)[serving] != 3 { + if r, err := GrpcHealthCheck(iAddr, "foo", 3, TLSInsecure); err != nil || (*r)[serving] != 3 { t.Errorf("Unexpected result %+v, %v with health check for same service as started (foo)", r, err) } - if r, err := GrpcHealthCheck(sAddr, caCrt, "foo", 3, TLSInsecure); err != nil || (*r)[serving] != 3 { + if r, err := GrpcHealthCheck(sAddr, "foo", 3, TLSSecure); err != nil || (*r)[serving] != 3 { t.Errorf("Unexpected result %+v, %v with health check for same service as started (foo)", r, err) } - if r, err := GrpcHealthCheck(iAddr, "", "willfail", 1, TLSInsecure); err == nil || r != nil { + if r, err := GrpcHealthCheck(iAddr, "willfail", 1, TLSInsecure); err == nil || r != nil { t.Errorf("Was expecting error when using unknown service, didn't get one, got %+v", r) } - if r, err := GrpcHealthCheck(sAddr, caCrt, "willfail", 1, TLSInsecure); err == nil || r != nil { + if r, err := GrpcHealthCheck(sAddr, "willfail", 1, TLSSecure); err == nil || r != nil { t.Errorf("Was expecting error when using unknown service, didn't get one, got %+v", r) } - if r, err := GrpcHealthCheck(sAddr, failCrt, "willfail", 1, TLSInsecure); err == nil { + if r, err := GrpcHealthCheck(sAddr, "willfail", 1, TLSSecureBadCert); err == nil { t.Errorf("Was expecting dial error when using invalid certificate, didn't get one, got %+v", r) } // 2nd server on same port should fail to bind: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fhttp/http_client.go new/fortio-1.24.0/fhttp/http_client.go --- old/fortio-1.23.0/fhttp/http_client.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fhttp/http_client.go 2022-03-28 00:47:13.000000000 +0200 @@ -19,7 +19,6 @@ "bytes" "context" "crypto/tls" - "crypto/x509" "errors" "fmt" "io" @@ -160,6 +159,7 @@ // HTTPOptions holds the common options of both http clients and the headers. type HTTPOptions struct { + TLSOptions URL string NumConnections int // num connections (for std client) Compression bool // defaults to no compression, only used by std client @@ -167,28 +167,21 @@ HTTP10 bool // defaults to http1.1 DisableKeepAlive bool // so default is keep alive AllowHalfClose bool // if not keepalive, whether to half close after request - Insecure bool // do not verify certs for https FollowRedirects bool // For the Std Client only: follow redirects. initDone bool https bool // whether URLSchemeCheck determined this was an https:// call or not - CACert string // `Path` to a custom CA certificate file to be used - Cert string // `Path` to the certificate file to be used - Key string // `Path` to the key file used Resolve string // resolve Common Name to this ip when use CN as target url // ExtraHeaders to be added to each request (UserAgent and headers set through AddAndValidateExtraHeader()). extraHeaders http.Header // Host is treated specially, remember that virtual header separately. - hostOverride string - HTTPReqTimeOut time.Duration // timeout value for http request - - UserCredentials string // user credentials for authorization - ContentType string // indicates request body type, implies POST instead of GET - Payload []byte // body for http request, implies POST if not empty. - - UnixDomainSocket string // Path of unix domain socket to use instead of host:port from URL - LogErrors bool // whether to log non 2xx code as they occur or not - ID int // id to use for logging (thread id when used as a runner) - SequentialWarmup bool // whether to do http(s) runs warmup sequentially or in parallel (new default is //) + hostOverride string + HTTPReqTimeOut time.Duration // timeout value for http request + UserCredentials string // user credentials for authorization + ContentType string // indicates request body type, implies POST instead of GET + Payload []byte // body for http request, implies POST if not empty. + LogErrors bool // whether to log non 2xx code as they occur or not + ID int // id to use for logging (thread id when used as a runner) + SequentialWarmup bool // whether to do http(s) runs warmup sequentially or in parallel (new default is //) } // ResetHeaders resets all the headers, including the User-Agent: one (and the Host: logical special header). @@ -439,11 +432,12 @@ }, TLSHandshakeTimeout: o.HTTPReqTimeOut, } - tr.TLSClientConfig, err = o.TLSClientConfig() - if err != nil { - return nil, err + if o.https { + tr.TLSClientConfig, err = o.TLSOptions.TLSClientConfig() + if err != nil { + return nil, err + } } - client := Client{ url: o.URL, path: req.URL.Path, @@ -470,43 +464,6 @@ return &client, nil } -// TLSClientConfig creates a tls.Config based on input HTTPOptions. -// ServerName is set later (once host is determined after URL parsing -// and depending on hostOverride). -func (h *HTTPOptions) TLSClientConfig() (*tls.Config, error) { - if !h.https { - return nil, nil - } - var res *tls.Config - - res = &tls.Config{MinVersion: tls.VersionTLS12} - if h.Insecure { - log.LogVf("Using insecure https") - res.InsecureSkipVerify = true - } - if len(h.Cert) > 0 && len(h.Key) > 0 { - cert, err := tls.LoadX509KeyPair(h.Cert, h.Key) - if err != nil { - log.Errf("LoadX509KeyPair error for cert %v / key %v: %v", h.Cert, h.Key, err) - return nil, err - } - res.Certificates = []tls.Certificate{cert} - } - if len(h.CACert) > 0 { - // Load CA cert - caCert, err := ioutil.ReadFile(h.CACert) - if err != nil { - log.Errf("Unable to read CA from %v: %v", h.CACert, err) - return nil, err - } - log.LogVf("Using custom CA from %v", h.CACert) - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - res.RootCAs = caCertPool - } - return res, nil -} - // FetchURL fetches the data at the given url using the standard client and default options. // Returns the http status code (http.StatusOK == 200 for success) and the data. // To be used only for single fetches or when performance doesn't matter as the client is closed at the end. @@ -599,15 +556,17 @@ log.Errf("Bad url '%s' : %v", urlString, err) return nil, err } - tlsConfig, err := o.TLSClientConfig() - if err != nil { - return nil, err - } // note: Host includes the port bc := FastClient{ url: o.URL, host: url.Host, hostname: url.Hostname(), port: url.Port(), http10: o.HTTP10, halfClose: o.AllowHalfClose, logErrors: o.LogErrors, id: o.ID, - https: o.https, tlsConfig: tlsConfig, + https: o.https, + } + if o.https { + bc.tlsConfig, err = o.TLSOptions.TLSClientConfig() + if err != nil { + return nil, err + } } bc.buffer = make([]byte, BufferSizeKb*1024) if bc.port == "" { @@ -640,8 +599,8 @@ if customHostHeader { host = o.hostOverride } - if tlsConfig != nil { - tlsConfig.ServerName = host + if bc.tlsConfig != nil { + bc.tlsConfig.ServerName = host } var buf bytes.Buffer buf.WriteString(method + " " + url.RequestURI() + " HTTP/" + proto + "\r\n") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fhttp/http_server.go new/fortio-1.24.0/fhttp/http_server.go --- old/fortio-1.23.0/fhttp/http_server.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fhttp/http_server.go 2022-03-28 00:47:13.000000000 +0200 @@ -339,6 +339,11 @@ w.Header().Set("Cache-Control", "max-age=365000000, immutable") } +// EchoDebugPath returns the additional echo handler path behind debugPath (ie /debug -> /debug/echo/). +func EchoDebugPath(debugPath string) string { + return strings.TrimSuffix(debugPath, "/") + "/echo/" +} + // Serve starts a debug / echo http server on the given port. // Returns the mux and addr where the listening socket is bound. // The .Port can be retrieved from it when requesting the 0 port as @@ -351,7 +356,7 @@ } if debugPath != "" { mux.HandleFunc(debugPath, DebugHandler) - mux.HandleFunc(strings.TrimSuffix(debugPath, "/")+"/echo/", EchoHandler) // Fix #524 + mux.HandleFunc(EchoDebugPath(debugPath), EchoHandler) // Fix #524 } mux.HandleFunc("/", EchoHandler) return mux, addr diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fhttp/http_test.go new/fortio-1.24.0/fhttp/http_test.go --- old/fortio-1.23.0/fhttp/http_test.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fhttp/http_test.go 2022-03-28 00:47:13.000000000 +0200 @@ -579,7 +579,7 @@ if addr == nil { t.Fatalf("Error for Serve for %s", uds) } - o := HTTPOptions{UnixDomainSocket: uds, URL: "http://foo.bar:123/debug1"} + o := HTTPOptions{TLSOptions: TLSOptions{UnixDomainSocket: uds}, URL: "http://foo.bar:123/debug1"} client, _ := NewClient(&o) code, data, _ := client.Fetch() if code != http.StatusOK { @@ -1415,7 +1415,7 @@ o := HTTPOptions{ DisableFastClient: tst.fastClient, URL: expiredURL, - Insecure: tst.insecure, + TLSOptions: TLSOptions{Insecure: tst.insecure}, } code, _ := Fetch(&o) if code != tst.code { @@ -1446,7 +1446,7 @@ o := HTTPOptions{ DisableFastClient: tst.fastClient, URL: url, - Insecure: tst.insecure, + TLSOptions: TLSOptions{Insecure: tst.insecure}, Resolve: "127.0.0.1", } code, _ := Fetch(&o) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fhttp/http_utils.go new/fortio-1.24.0/fhttp/http_utils.go --- old/fortio-1.23.0/fhttp/http_utils.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fhttp/http_utils.go 2022-03-28 00:47:13.000000000 +0200 @@ -15,10 +15,13 @@ package fhttp // import "fortio.org/fortio/fhttp" import ( + "crypto/tls" + "crypto/x509" "encoding/base64" "flag" "html/template" "io" + "io/ioutil" "math/rand" "net/http" "strconv" @@ -33,6 +36,49 @@ "fortio.org/fortio/stats" ) +// TLSOptions are common TLS related options between https and grpc. +type TLSOptions struct { + Insecure bool // Do not verify certs + CACert string // `Path` to a custom CA certificate file to be used + Cert string // `Path` to the certificate file to be used + Key string // `Path` to the key file used + UnixDomainSocket string // `Path`` of unix domain socket to use instead of host:port +} + +// TLSClientConfig creates a tls.Config based on input TLSOptions. +// For https, ServerName is set later (once host is determined after URL parsing +// and depending on hostOverride). +func (to *TLSOptions) TLSClientConfig() (*tls.Config, error) { + var res *tls.Config + + res = &tls.Config{MinVersion: tls.VersionTLS12} + if to.Insecure { + log.LogVf("Using insecure https") + res.InsecureSkipVerify = true + } + if len(to.Cert) > 0 && len(to.Key) > 0 { + cert, err := tls.LoadX509KeyPair(to.Cert, to.Key) + if err != nil { + log.Errf("LoadX509KeyPair error for cert %v / key %v: %v", to.Cert, to.Key, err) + return nil, err + } + res.Certificates = []tls.Certificate{cert} + } + if len(to.CACert) > 0 { + // Load CA cert + caCert, err := ioutil.ReadFile(to.CACert) + if err != nil { + log.Errf("Unable to read CA from %v: %v", to.CACert, err) + return nil, err + } + log.LogVf("Using custom CA from %v", to.CACert) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + res.RootCAs = caCertPool + } + return res, nil +} + // Used for the fast case insensitive search. const toUpperMask = ^byte('a' - 'A') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/fortio_main.go new/fortio-1.24.0/fortio_main.go --- old/fortio-1.23.0/fortio_main.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/fortio_main.go 2022-03-28 00:47:13.000000000 +0200 @@ -420,16 +420,14 @@ o := fgrpc.GRPCRunnerOptions{ RunnerOptions: ro, Destination: url, - CACert: *bincommon.CACertFlag, - Insecure: bincommon.TLSInsecure(), Service: *healthSvcFlag, Streams: *streamsFlag, AllowInitialErrors: *allowInitialErrorsFlag, Payload: httpOpts.PayloadString(), Delay: *pingDelayFlag, UsePing: *doPingLoadFlag, - UnixDomainSocket: httpOpts.UnixDomainSocket, } + o.TLSOptions = httpOpts.TLSOptions res, err = fgrpc.RunGRPCTest(&o) } else if strings.HasPrefix(url, tcprunner.TCPURLPrefix) { o := tcprunner.RunnerOptions{ @@ -514,13 +512,12 @@ if count <= 0 { count = 1 } - cert := *bincommon.CACertFlag + httpOpts := bincommon.SharedHTTPOptions() var err error if *doHealthFlag { - _, err = fgrpc.GrpcHealthCheck(host, cert, *healthSvcFlag, count, bincommon.TLSInsecure()) + _, err = fgrpc.GrpcHealthCheck(host, *healthSvcFlag, count, &httpOpts.TLSOptions) } else { - httpOpts := bincommon.SharedHTTPOptions() - _, err = fgrpc.PingClientCall(host, cert, count, httpOpts.PayloadString(), *pingDelayFlag, httpOpts.Insecure) + _, err = fgrpc.PingClientCall(host, count, httpOpts.PayloadString(), *pingDelayFlag, &httpOpts.TLSOptions) } if err != nil { // already logged diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/ui/restHandler.go new/fortio-1.24.0/ui/restHandler.go --- old/fortio-1.23.0/ui/restHandler.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/ui/restHandler.go 2022-03-28 00:47:13.000000000 +0200 @@ -247,8 +247,8 @@ Destination: url, UsePing: grpcPing, Delay: grpcPingDelay, - Insecure: httpopts.Insecure, } + o.TLSOptions = httpopts.TLSOptions if grpcSecure { o.Destination = fhttp.AddHTTPS(url) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/ui/templates/main.html new/fortio-1.24.0/ui/templates/main.html --- old/fortio-1.23.0/ui/templates/main.html 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/ui/templates/main.html 2022-03-28 00:47:13.000000000 +0200 @@ -95,9 +95,9 @@ </form> <p><i>Or</i></p> <a href="{{.DebugPath}}">debug</a> and <a href="{{.DebugPath}}?env=dump">debug with env dump</a> -and <a href="{{.DebugPath}}/pprof/">Internal PPROF</a> +and <a href="/debug/pprof/">Internal PPROF</a> and <a href="flags">Command line flags</a> -and <a href="{{.DebugPath}}/echo/">Additional echo handler under {{.DebugPath}}/echo/</a> (supports all the +and <a href="{{.EchoDebugPath}}">Additional echo handler under {{.EchoDebugPath}}</a> (supports all the query arguments mentioned on the <a href="https://github.com/fortio/fortio#server-urls-and-features">Echo url features</a> github doc) <p><i>Or</i></p> <form action="sync"> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.23.0/ui/uihandler.go new/fortio-1.24.0/ui/uihandler.go --- old/fortio-1.23.0/ui/uihandler.go 2022-03-25 02:46:50.000000000 +0100 +++ new/fortio-1.24.0/ui/uihandler.go 2022-03-28 00:47:13.000000000 +0200 @@ -65,7 +65,8 @@ uiPath string // absolute (base) logoPath string // relative chartJSPath string // relative - debugPath string // mostly relative + debugPath string // absolute + echoPath string // absolute fetchPath string // this one is absolute // Used to construct default URL to self. urlHostPort string @@ -239,6 +240,7 @@ Version string LogoPath string DebugPath string + EchoDebugPath string ChartJSPath string StartTime string TargetURL string @@ -250,7 +252,7 @@ DoStop bool DoLoad bool }{ - r, defaultHeaders, version.Short(), logoPath, debugPath, chartJSPath, + r, defaultHeaders, version.Short(), logoPath, debugPath, echoPath, chartJSPath, startTime.Format(time.ANSIC), url, labels, runid, fhttp.RoundDuration(time.Since(startTime)), durSeconds, urlHostPort, mode == stop, mode == run, }) @@ -287,8 +289,8 @@ Destination: url, UsePing: grpcPing, Delay: grpcPingDelay, - Insecure: httpsInsecure, } + o.TLSOptions = httpopts.TLSOptions if grpcSecure { o.Destination = fhttp.AddHTTPS(url) } @@ -895,7 +897,8 @@ log.Warnf("Adding missing trailing / to UI path '%s'", uiPath) uiPath += "/" } - debugPath = ".." + debugpath // TODO: calculate actual path if not same number of directories + debugPath = debugpath + echoPath = fhttp.EchoDebugPath(debugpath) mux.HandleFunc(uiPath, Handler) fetchPath = uiPath + fetchURI // For backward compatibility with http:// only fetcher ++++++ vendor.tar.gz ++++++